Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: OpenGIS Simple Features Reference Implementation
4 : * Purpose: Implementation of OGRGeoJSONReader class (OGR GeoJSON Driver).
5 : * Author: Mateusz Loskot, mateusz@loskot.net
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2007, Mateusz Loskot
9 : * Copyright (c) 2008-2017, Even Rouault <even dot rouault at spatialys dot com>
10 : *
11 : * SPDX-License-Identifier: MIT
12 : ****************************************************************************/
13 :
14 : #include "ogrgeojsonreader.h"
15 : #include "ogrgeojsonutils.h"
16 : #include "ogrgeojsongeometry.h"
17 : #include "ogr_geojson.h"
18 : #include "ogrlibjsonutils.h"
19 : #include "ogrjsoncollectionstreamingparser.h"
20 : #include "ogr_api.h"
21 :
22 : #include <cmath>
23 : #include <limits>
24 : #include <set>
25 : #include <functional>
26 :
27 : /************************************************************************/
28 : /* OGRGeoJSONReaderStreamingParser */
29 : /************************************************************************/
30 :
31 : class OGRGeoJSONReaderStreamingParser final
32 : : public OGRJSONCollectionStreamingParser
33 : {
34 : OGRGeoJSONReader &m_oReader;
35 : OGRGeoJSONLayer *m_poLayer = nullptr;
36 :
37 : std::vector<OGRFeature *> m_apoFeatures{};
38 : size_t m_nCurFeatureIdx = 0;
39 : bool m_bOriginalIdModifiedEmitted = false;
40 : std::set<GIntBig> m_oSetUsedFIDs{};
41 :
42 : std::map<std::string, int> m_oMapFieldNameToIdx{};
43 : std::vector<std::unique_ptr<OGRFieldDefn>> m_apoFieldDefn{};
44 : gdal::DirectedAcyclicGraph<int, std::string> m_dag{};
45 :
46 : void AnalyzeFeature();
47 :
48 : CPL_DISALLOW_COPY_ASSIGN(OGRGeoJSONReaderStreamingParser)
49 :
50 : protected:
51 : void GotFeature(json_object *poObj, bool bFirstPass,
52 : const std::string &osJson) override;
53 : void TooComplex() override;
54 :
55 : public:
56 : OGRGeoJSONReaderStreamingParser(OGRGeoJSONReader &oReader,
57 : OGRGeoJSONLayer *poLayer, bool bFirstPass,
58 : bool bStoreNativeData);
59 : ~OGRGeoJSONReaderStreamingParser();
60 :
61 : void FinalizeLayerDefn();
62 :
63 : OGRFeature *GetNextFeature();
64 :
65 123 : inline bool GetOriginalIdModifiedEmitted() const
66 : {
67 123 : return m_bOriginalIdModifiedEmitted;
68 : }
69 :
70 290 : inline void SetOriginalIdModifiedEmitted(bool b)
71 : {
72 290 : m_bOriginalIdModifiedEmitted = b;
73 290 : }
74 : };
75 :
76 : /************************************************************************/
77 : /* OGRGeoJSONBaseReader() */
78 : /************************************************************************/
79 :
80 : OGRGeoJSONBaseReader::OGRGeoJSONBaseReader() = default;
81 :
82 : /************************************************************************/
83 : /* SetPreserveGeometryType */
84 : /************************************************************************/
85 :
86 0 : void OGRGeoJSONBaseReader::SetPreserveGeometryType(bool bPreserve)
87 : {
88 0 : bGeometryPreserve_ = bPreserve;
89 0 : }
90 :
91 : /************************************************************************/
92 : /* SetSkipAttributes */
93 : /************************************************************************/
94 :
95 0 : void OGRGeoJSONBaseReader::SetSkipAttributes(bool bSkip)
96 : {
97 0 : bAttributesSkip_ = bSkip;
98 0 : }
99 :
100 : /************************************************************************/
101 : /* SetFlattenNestedAttributes */
102 : /************************************************************************/
103 :
104 434 : void OGRGeoJSONBaseReader::SetFlattenNestedAttributes(bool bFlatten,
105 : char chSeparator)
106 : {
107 434 : bFlattenNestedAttributes_ = bFlatten;
108 434 : chNestedAttributeSeparator_ = chSeparator;
109 434 : }
110 :
111 : /************************************************************************/
112 : /* SetStoreNativeData */
113 : /************************************************************************/
114 :
115 434 : void OGRGeoJSONBaseReader::SetStoreNativeData(bool bStoreNativeData)
116 : {
117 434 : bStoreNativeData_ = bStoreNativeData;
118 434 : }
119 :
120 : /************************************************************************/
121 : /* SetArrayAsString */
122 : /************************************************************************/
123 :
124 434 : void OGRGeoJSONBaseReader::SetArrayAsString(bool bArrayAsString)
125 : {
126 434 : bArrayAsString_ = bArrayAsString;
127 434 : }
128 :
129 : /************************************************************************/
130 : /* SetDateAsString */
131 : /************************************************************************/
132 :
133 434 : void OGRGeoJSONBaseReader::SetDateAsString(bool bDateAsString)
134 : {
135 434 : bDateAsString_ = bDateAsString;
136 434 : }
137 :
138 : /************************************************************************/
139 : /* OGRGeoJSONReader */
140 : /************************************************************************/
141 :
142 434 : OGRGeoJSONReader::OGRGeoJSONReader()
143 : : poGJObject_(nullptr), poStreamingParser_(nullptr), bFirstSeg_(false),
144 : bJSonPLikeWrapper_(false), fp_(nullptr), bCanEasilyAppend_(false),
145 : bFCHasBBOX_(false), nBufferSize_(0), pabyBuffer_(nullptr),
146 434 : nTotalFeatureCount_(0), nTotalOGRFeatureMemEstimate_(0)
147 : {
148 434 : }
149 :
150 : /************************************************************************/
151 : /* ~OGRGeoJSONReader */
152 : /************************************************************************/
153 :
154 434 : OGRGeoJSONReader::~OGRGeoJSONReader()
155 : {
156 434 : if (nullptr != poGJObject_)
157 : {
158 431 : json_object_put(poGJObject_);
159 : }
160 434 : if (fp_ != nullptr)
161 : {
162 265 : VSIFCloseL(fp_);
163 : }
164 434 : delete poStreamingParser_;
165 434 : CPLFree(pabyBuffer_);
166 :
167 434 : poGJObject_ = nullptr;
168 434 : }
169 :
170 : /************************************************************************/
171 : /* Parse */
172 : /************************************************************************/
173 :
174 166 : OGRErr OGRGeoJSONReader::Parse(const char *pszText)
175 : {
176 166 : if (nullptr != pszText)
177 : {
178 : // Skip UTF-8 BOM (#5630).
179 166 : const GByte *pabyData = (const GByte *)pszText;
180 166 : if (pabyData[0] == 0xEF && pabyData[1] == 0xBB && pabyData[2] == 0xBF)
181 : {
182 1 : CPLDebug("GeoJSON", "Skip UTF-8 BOM");
183 1 : pszText += 3;
184 : }
185 :
186 166 : if (poGJObject_ != nullptr)
187 : {
188 0 : json_object_put(poGJObject_);
189 0 : poGJObject_ = nullptr;
190 : }
191 :
192 : // JSON tree is shared for while lifetime of the reader object
193 : // and will be released in the destructor.
194 166 : if (!OGRJSonParse(pszText, &poGJObject_))
195 0 : return OGRERR_CORRUPT_DATA;
196 : }
197 :
198 166 : return OGRERR_NONE;
199 : }
200 :
201 : /************************************************************************/
202 : /* ReadLayers */
203 : /************************************************************************/
204 :
205 166 : void OGRGeoJSONReader::ReadLayers(OGRGeoJSONDataSource *poDS)
206 : {
207 166 : if (nullptr == poGJObject_)
208 : {
209 0 : CPLDebug("GeoJSON",
210 : "Missing parsed GeoJSON data. Forgot to call Parse()?");
211 0 : return;
212 : }
213 :
214 166 : ReadLayer(poDS, nullptr, poGJObject_);
215 : }
216 :
217 : /************************************************************************/
218 : /* OGRGeoJSONReaderStreamingParserGetMaxObjectSize() */
219 : /************************************************************************/
220 :
221 558 : static size_t OGRGeoJSONReaderStreamingParserGetMaxObjectSize()
222 : {
223 : const double dfTmp =
224 558 : CPLAtof(CPLGetConfigOption("OGR_GEOJSON_MAX_OBJ_SIZE", "200"));
225 558 : return dfTmp > 0 ? static_cast<size_t>(dfTmp * 1024 * 1024) : 0;
226 : }
227 :
228 : /************************************************************************/
229 : /* OGRGeoJSONReaderStreamingParser() */
230 : /************************************************************************/
231 :
232 558 : OGRGeoJSONReaderStreamingParser::OGRGeoJSONReaderStreamingParser(
233 : OGRGeoJSONReader &oReader, OGRGeoJSONLayer *poLayer, bool bFirstPass,
234 558 : bool bStoreNativeData)
235 : : OGRJSONCollectionStreamingParser(
236 : bFirstPass, bStoreNativeData,
237 : OGRGeoJSONReaderStreamingParserGetMaxObjectSize()),
238 558 : m_oReader(oReader), m_poLayer(poLayer)
239 : {
240 558 : }
241 :
242 : /************************************************************************/
243 : /* ~OGRGeoJSONReaderStreamingParser() */
244 : /************************************************************************/
245 :
246 843 : OGRGeoJSONReaderStreamingParser::~OGRGeoJSONReaderStreamingParser()
247 : {
248 911 : for (size_t i = 0; i < m_apoFeatures.size(); i++)
249 353 : delete m_apoFeatures[i];
250 843 : }
251 :
252 : /************************************************************************/
253 : /* GetNextFeature() */
254 : /************************************************************************/
255 :
256 1821 : OGRFeature *OGRGeoJSONReaderStreamingParser::GetNextFeature()
257 : {
258 1821 : if (m_nCurFeatureIdx < m_apoFeatures.size())
259 : {
260 1092 : OGRFeature *poFeat = m_apoFeatures[m_nCurFeatureIdx];
261 1092 : m_apoFeatures[m_nCurFeatureIdx] = nullptr;
262 1092 : m_nCurFeatureIdx++;
263 1092 : return poFeat;
264 : }
265 729 : m_nCurFeatureIdx = 0;
266 729 : m_apoFeatures.clear();
267 729 : return nullptr;
268 : }
269 :
270 : /************************************************************************/
271 : /* GotFeature() */
272 : /************************************************************************/
273 :
274 5687 : void OGRGeoJSONReaderStreamingParser::GotFeature(json_object *poObj,
275 : bool bFirstPass,
276 : const std::string &osJson)
277 : {
278 5687 : if (bFirstPass)
279 : {
280 4412 : if (!m_oReader.GenerateFeatureDefn(m_oMapFieldNameToIdx, m_apoFieldDefn,
281 4412 : m_dag, m_poLayer, poObj))
282 : {
283 : }
284 4412 : m_poLayer->IncFeatureCount();
285 : }
286 : else
287 : {
288 : OGRFeature *poFeat =
289 1275 : m_oReader.ReadFeature(m_poLayer, poObj, osJson.c_str());
290 1275 : if (poFeat)
291 : {
292 1275 : GIntBig nFID = poFeat->GetFID();
293 1275 : if (nFID == OGRNullFID)
294 : {
295 1101 : nFID = static_cast<GIntBig>(m_oSetUsedFIDs.size());
296 1101 : while (cpl::contains(m_oSetUsedFIDs, nFID))
297 : {
298 0 : ++nFID;
299 : }
300 : }
301 174 : else if (cpl::contains(m_oSetUsedFIDs, nFID))
302 : {
303 33 : if (!m_bOriginalIdModifiedEmitted)
304 : {
305 2 : CPLError(CE_Warning, CPLE_AppDefined,
306 : "Several features with id = " CPL_FRMT_GIB " have "
307 : "been found. Altering it to be unique. "
308 : "This warning will not be emitted anymore for "
309 : "this layer",
310 : nFID);
311 2 : m_bOriginalIdModifiedEmitted = true;
312 : }
313 33 : nFID = static_cast<GIntBig>(m_oSetUsedFIDs.size());
314 33 : while (cpl::contains(m_oSetUsedFIDs, nFID))
315 : {
316 0 : ++nFID;
317 : }
318 : }
319 1275 : m_oSetUsedFIDs.insert(nFID);
320 1275 : poFeat->SetFID(nFID);
321 :
322 1275 : m_apoFeatures.push_back(poFeat);
323 : }
324 : }
325 5687 : }
326 :
327 : /************************************************************************/
328 : /* FinalizeLayerDefn() */
329 : /************************************************************************/
330 :
331 265 : void OGRGeoJSONReaderStreamingParser::FinalizeLayerDefn()
332 : {
333 265 : OGRFeatureDefn *poDefn = m_poLayer->GetLayerDefn();
334 530 : auto oTemporaryUnsealer(poDefn->GetTemporaryUnsealer());
335 530 : const auto sortedFields = m_dag.getTopologicalOrdering();
336 265 : CPLAssert(sortedFields.size() == m_apoFieldDefn.size());
337 961 : for (int idx : sortedFields)
338 : {
339 696 : poDefn->AddFieldDefn(m_apoFieldDefn[idx].get());
340 : }
341 265 : m_dag = gdal::DirectedAcyclicGraph<int, std::string>();
342 265 : m_oMapFieldNameToIdx.clear();
343 265 : m_apoFieldDefn.clear();
344 265 : }
345 :
346 : /************************************************************************/
347 : /* TooComplex() */
348 : /************************************************************************/
349 :
350 1 : void OGRGeoJSONReaderStreamingParser::TooComplex()
351 : {
352 1 : if (!ExceptionOccurred())
353 1 : EmitException("GeoJSON object too complex/large. You may define the "
354 : "OGR_GEOJSON_MAX_OBJ_SIZE configuration option to "
355 : "a value in megabytes to allow "
356 : "for larger features, or 0 to remove any size limit.");
357 1 : }
358 :
359 : /************************************************************************/
360 : /* SetCoordinatePrecision() */
361 : /************************************************************************/
362 :
363 357 : static void SetCoordinatePrecision(json_object *poRootObj,
364 : OGRGeoJSONLayer *poLayer)
365 : {
366 357 : if (poLayer->GetLayerDefn()->GetGeomType() != wkbNone)
367 : {
368 714 : OGRGeoJSONWriteOptions options;
369 :
370 : json_object *poXYRes =
371 357 : CPL_json_object_object_get(poRootObj, "xy_coordinate_resolution");
372 357 : if (poXYRes && (json_object_get_type(poXYRes) == json_type_double ||
373 0 : json_object_get_type(poXYRes) == json_type_int))
374 : {
375 8 : auto poGeomFieldDefn = poLayer->GetLayerDefn()->GetGeomFieldDefn(0);
376 : OGRGeomCoordinatePrecision oCoordPrec(
377 8 : poGeomFieldDefn->GetCoordinatePrecision());
378 8 : oCoordPrec.dfXYResolution = json_object_get_double(poXYRes);
379 8 : whileUnsealing(poGeomFieldDefn)->SetCoordinatePrecision(oCoordPrec);
380 :
381 8 : options.nXYCoordPrecision =
382 8 : OGRGeomCoordinatePrecision::ResolutionToPrecision(
383 : oCoordPrec.dfXYResolution);
384 : }
385 :
386 : json_object *poZRes =
387 357 : CPL_json_object_object_get(poRootObj, "z_coordinate_resolution");
388 357 : if (poZRes && (json_object_get_type(poZRes) == json_type_double ||
389 0 : json_object_get_type(poZRes) == json_type_int))
390 : {
391 6 : auto poGeomFieldDefn = poLayer->GetLayerDefn()->GetGeomFieldDefn(0);
392 : OGRGeomCoordinatePrecision oCoordPrec(
393 6 : poGeomFieldDefn->GetCoordinatePrecision());
394 6 : oCoordPrec.dfZResolution = json_object_get_double(poZRes);
395 6 : whileUnsealing(poGeomFieldDefn)->SetCoordinatePrecision(oCoordPrec);
396 :
397 6 : options.nZCoordPrecision =
398 6 : OGRGeomCoordinatePrecision::ResolutionToPrecision(
399 : oCoordPrec.dfZResolution);
400 : }
401 :
402 357 : poLayer->SetWriteOptions(options);
403 : }
404 357 : }
405 :
406 : /************************************************************************/
407 : /* FirstPassReadLayer() */
408 : /************************************************************************/
409 :
410 268 : bool OGRGeoJSONReader::FirstPassReadLayer(OGRGeoJSONDataSource *poDS,
411 : VSILFILE *fp,
412 : bool &bTryStandardReading)
413 : {
414 268 : bTryStandardReading = false;
415 268 : VSIFSeekL(fp, 0, SEEK_SET);
416 268 : bFirstSeg_ = true;
417 :
418 268 : const char *pszName = poDS->GetDescription();
419 268 : if (STARTS_WITH_CI(pszName, "GeoJSON:"))
420 0 : pszName += strlen("GeoJSON:");
421 268 : pszName = CPLGetBasename(pszName);
422 :
423 : OGRGeoJSONLayer *poLayer = new OGRGeoJSONLayer(
424 268 : pszName, nullptr, OGRGeoJSONLayer::DefaultGeometryType, poDS, this);
425 : OGRGeoJSONReaderStreamingParser oParser(*this, poLayer, true,
426 536 : bStoreNativeData_);
427 :
428 268 : vsi_l_offset nFileSize = 0;
429 343 : if (STARTS_WITH(poDS->GetDescription(), "/vsimem/") ||
430 75 : !STARTS_WITH(poDS->GetDescription(), "/vsi"))
431 : {
432 : VSIStatBufL sStatBuf;
433 262 : if (VSIStatL(poDS->GetDescription(), &sStatBuf) == 0)
434 : {
435 262 : nFileSize = sStatBuf.st_size;
436 : }
437 : }
438 :
439 268 : nBufferSize_ = 4096 * 10;
440 268 : pabyBuffer_ = static_cast<GByte *>(CPLMalloc(nBufferSize_));
441 268 : int nIter = 0;
442 268 : bool bThresholdReached = false;
443 268 : const GIntBig nMaxBytesFirstPass = CPLAtoGIntBig(
444 : CPLGetConfigOption("OGR_GEOJSON_MAX_BYTES_FIRST_PASS", "0"));
445 268 : const GIntBig nLimitFeaturesFirstPass = CPLAtoGIntBig(
446 : CPLGetConfigOption("OGR_GEOJSON_MAX_FEATURES_FIRST_PASS", "0"));
447 : while (true)
448 : {
449 413 : nIter++;
450 :
451 413 : if (nMaxBytesFirstPass > 0 &&
452 0 : static_cast<GIntBig>(nIter) * static_cast<GIntBig>(nBufferSize_) >=
453 : nMaxBytesFirstPass)
454 : {
455 0 : CPLDebug("GeoJSON", "First pass: early exit since above "
456 : "OGR_GEOJSON_MAX_BYTES_FIRST_PASS");
457 0 : bThresholdReached = true;
458 0 : break;
459 : }
460 :
461 413 : size_t nRead = VSIFReadL(pabyBuffer_, 1, nBufferSize_, fp);
462 413 : const bool bFinished = nRead < nBufferSize_;
463 413 : size_t nSkip = 0;
464 413 : if (bFirstSeg_)
465 : {
466 268 : bFirstSeg_ = false;
467 268 : nSkip = SkipPrologEpilogAndUpdateJSonPLikeWrapper(nRead);
468 : }
469 413 : if (bFinished && bJSonPLikeWrapper_ && nRead > nSkip)
470 1 : nRead--;
471 413 : if (!oParser.Parse(reinterpret_cast<const char *>(pabyBuffer_ + nSkip),
472 824 : nRead - nSkip, bFinished) ||
473 411 : oParser.ExceptionOccurred())
474 : {
475 : // to avoid killing ourselves during layer deletion
476 2 : poLayer->UnsetReader();
477 2 : delete poLayer;
478 2 : return false;
479 : }
480 411 : if (bFinished || (nIter % 100) == 0)
481 : {
482 266 : if (nFileSize == 0)
483 : {
484 6 : if (bFinished)
485 : {
486 6 : CPLDebug("GeoJSON", "First pass: 100.00 %%");
487 : }
488 : else
489 : {
490 0 : CPLDebug("GeoJSON",
491 : "First pass: " CPL_FRMT_GUIB " bytes read",
492 0 : static_cast<GUIntBig>(nIter) *
493 0 : static_cast<GUIntBig>(nBufferSize_) +
494 : nRead);
495 : }
496 : }
497 : else
498 : {
499 260 : CPLDebug("GeoJSON", "First pass: %.2f %%",
500 260 : 100.0 * VSIFTellL(fp) / nFileSize);
501 : }
502 : }
503 411 : if (nLimitFeaturesFirstPass > 0 &&
504 0 : poLayer->GetFeatureCount(FALSE) >= nLimitFeaturesFirstPass)
505 : {
506 0 : CPLDebug("GeoJSON", "First pass: early exit since above "
507 : "OGR_GEOJSON_MAX_FEATURES_FIRST_PASS");
508 0 : bThresholdReached = true;
509 0 : break;
510 : }
511 411 : if (oParser.IsTypeKnown() && !oParser.IsFeatureCollection())
512 0 : break;
513 411 : if (bFinished)
514 266 : break;
515 145 : }
516 :
517 266 : if (bThresholdReached)
518 : {
519 0 : poLayer->InvalidateFeatureCount();
520 : }
521 266 : else if (!oParser.IsTypeKnown() || !oParser.IsFeatureCollection())
522 : {
523 : // to avoid killing ourselves during layer deletion
524 1 : poLayer->UnsetReader();
525 1 : delete poLayer;
526 : const vsi_l_offset nRAM =
527 1 : static_cast<vsi_l_offset>(CPLGetUsablePhysicalRAM());
528 1 : if (nFileSize == 0 || nRAM == 0 || nRAM > nFileSize * 20)
529 : {
530 : // Only try full ingestion if we have 20x more RAM than the file
531 : // size
532 1 : bTryStandardReading = true;
533 : }
534 1 : return false;
535 : }
536 :
537 265 : oParser.FinalizeLayerDefn();
538 :
539 265 : CPLString osFIDColumn;
540 265 : FinalizeLayerDefn(poLayer, osFIDColumn);
541 265 : if (!osFIDColumn.empty())
542 26 : poLayer->SetFIDColumn(osFIDColumn);
543 :
544 265 : bCanEasilyAppend_ = oParser.CanEasilyAppend();
545 265 : nTotalFeatureCount_ = poLayer->GetFeatureCount(FALSE);
546 265 : nTotalOGRFeatureMemEstimate_ = oParser.GetTotalOGRFeatureMemEstimate();
547 :
548 265 : json_object *poRootObj = oParser.StealRootObject();
549 265 : if (poRootObj)
550 : {
551 265 : bFCHasBBOX_ = CPL_json_object_object_get(poRootObj, "bbox") != nullptr;
552 :
553 : // CPLDebug("GeoJSON", "%s", json_object_get_string(poRootObj));
554 :
555 265 : json_object *poName = CPL_json_object_object_get(poRootObj, "name");
556 265 : if (poName && json_object_get_type(poName) == json_type_string)
557 : {
558 116 : const char *pszValue = json_object_get_string(poName);
559 116 : whileUnsealing(poLayer->GetLayerDefn())->SetName(pszValue);
560 116 : poLayer->SetDescription(pszValue);
561 : }
562 :
563 : json_object *poDescription =
564 265 : CPL_json_object_object_get(poRootObj, "description");
565 266 : if (poDescription &&
566 1 : json_object_get_type(poDescription) == json_type_string)
567 : {
568 1 : const char *pszValue = json_object_get_string(poDescription);
569 1 : poLayer->SetMetadataItem("DESCRIPTION", pszValue);
570 : }
571 :
572 265 : OGRSpatialReference *poSRS = OGRGeoJSONReadSpatialReference(poRootObj);
573 265 : const auto eGeomType = poLayer->GetLayerDefn()->GetGeomType();
574 265 : if (eGeomType != wkbNone && poSRS == nullptr)
575 : {
576 : // If there is none defined, we use 4326 / 4979.
577 230 : poSRS = new OGRSpatialReference();
578 230 : if (OGR_GT_HasZ(eGeomType))
579 17 : poSRS->importFromEPSG(4979);
580 : else
581 213 : poSRS->SetFromUserInput(SRS_WKT_WGS84_LAT_LONG);
582 230 : poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
583 : }
584 265 : CPLErrorReset();
585 :
586 265 : if (eGeomType != wkbNone && poSRS != nullptr)
587 : {
588 265 : auto poGeomFieldDefn = poLayer->GetLayerDefn()->GetGeomFieldDefn(0);
589 265 : whileUnsealing(poGeomFieldDefn)->SetSpatialRef(poSRS);
590 : }
591 265 : if (poSRS)
592 265 : poSRS->Release();
593 :
594 265 : SetCoordinatePrecision(poRootObj, poLayer);
595 :
596 265 : if (bStoreNativeData_)
597 : {
598 58 : CPLString osNativeData("NATIVE_DATA=");
599 29 : osNativeData += json_object_get_string(poRootObj);
600 :
601 29 : char *apszMetadata[3] = {
602 29 : const_cast<char *>(osNativeData.c_str()),
603 : const_cast<char *>(
604 : "NATIVE_MEDIA_TYPE=application/vnd.geo+json"),
605 29 : nullptr};
606 :
607 29 : poLayer->SetMetadata(apszMetadata, "NATIVE_DATA");
608 : }
609 :
610 265 : poGJObject_ = poRootObj;
611 : }
612 :
613 265 : fp_ = fp;
614 265 : poDS->AddLayer(poLayer);
615 265 : return true;
616 : }
617 :
618 : /************************************************************************/
619 : /* SkipPrologEpilogAndUpdateJSonPLikeWrapper() */
620 : /************************************************************************/
621 :
622 558 : size_t OGRGeoJSONReader::SkipPrologEpilogAndUpdateJSonPLikeWrapper(size_t nRead)
623 : {
624 558 : size_t nSkip = 0;
625 558 : if (nRead >= 3 && pabyBuffer_[0] == 0xEF && pabyBuffer_[1] == 0xBB &&
626 0 : pabyBuffer_[2] == 0xBF)
627 : {
628 0 : CPLDebug("GeoJSON", "Skip UTF-8 BOM");
629 0 : nSkip += 3;
630 : }
631 :
632 558 : const char *const apszPrefix[] = {"loadGeoJSON(", "jsonp("};
633 1672 : for (size_t i = 0; i < CPL_ARRAYSIZE(apszPrefix); i++)
634 : {
635 1115 : if (nRead >= nSkip + strlen(apszPrefix[i]) &&
636 1115 : memcmp(pabyBuffer_ + nSkip, apszPrefix[i], strlen(apszPrefix[i])) ==
637 : 0)
638 : {
639 1 : nSkip += strlen(apszPrefix[i]);
640 1 : bJSonPLikeWrapper_ = true;
641 1 : break;
642 : }
643 : }
644 :
645 558 : return nSkip;
646 : }
647 :
648 : /************************************************************************/
649 : /* ResetReading() */
650 : /************************************************************************/
651 :
652 538 : void OGRGeoJSONReader::ResetReading()
653 : {
654 538 : CPLAssert(fp_);
655 538 : if (poStreamingParser_)
656 114 : bOriginalIdModifiedEmitted_ =
657 114 : poStreamingParser_->GetOriginalIdModifiedEmitted();
658 538 : delete poStreamingParser_;
659 538 : poStreamingParser_ = nullptr;
660 538 : }
661 :
662 : /************************************************************************/
663 : /* GetNextFeature() */
664 : /************************************************************************/
665 :
666 1261 : OGRFeature *OGRGeoJSONReader::GetNextFeature(OGRGeoJSONLayer *poLayer)
667 : {
668 1261 : CPLAssert(fp_);
669 1261 : if (poStreamingParser_ == nullptr)
670 : {
671 285 : poStreamingParser_ = new OGRGeoJSONReaderStreamingParser(
672 285 : *this, poLayer, false, bStoreNativeData_);
673 285 : poStreamingParser_->SetOriginalIdModifiedEmitted(
674 285 : bOriginalIdModifiedEmitted_);
675 285 : VSIFSeekL(fp_, 0, SEEK_SET);
676 285 : bFirstSeg_ = true;
677 285 : bJSonPLikeWrapper_ = false;
678 : }
679 :
680 1261 : OGRFeature *poFeat = poStreamingParser_->GetNextFeature();
681 1261 : if (poFeat)
682 719 : return poFeat;
683 :
684 : while (true)
685 : {
686 542 : size_t nRead = VSIFReadL(pabyBuffer_, 1, nBufferSize_, fp_);
687 542 : const bool bFinished = nRead < nBufferSize_;
688 542 : size_t nSkip = 0;
689 542 : if (bFirstSeg_)
690 : {
691 285 : bFirstSeg_ = false;
692 285 : nSkip = SkipPrologEpilogAndUpdateJSonPLikeWrapper(nRead);
693 : }
694 542 : if (bFinished && bJSonPLikeWrapper_ && nRead > nSkip)
695 0 : nRead--;
696 1626 : if (!poStreamingParser_->Parse(
697 542 : reinterpret_cast<const char *>(pabyBuffer_ + nSkip),
698 1084 : nRead - nSkip, bFinished) ||
699 542 : poStreamingParser_->ExceptionOccurred())
700 : {
701 0 : break;
702 : }
703 :
704 542 : poFeat = poStreamingParser_->GetNextFeature();
705 542 : if (poFeat)
706 355 : return poFeat;
707 :
708 187 : if (bFinished)
709 187 : break;
710 0 : }
711 :
712 187 : return nullptr;
713 : }
714 :
715 : /************************************************************************/
716 : /* GetFeature() */
717 : /************************************************************************/
718 :
719 22 : OGRFeature *OGRGeoJSONReader::GetFeature(OGRGeoJSONLayer *poLayer, GIntBig nFID)
720 : {
721 22 : CPLAssert(fp_);
722 :
723 22 : if (oMapFIDToOffsetSize_.empty())
724 : {
725 5 : CPLDebug("GeoJSON",
726 : "Establishing index to features for first GetFeature() call");
727 :
728 5 : if (poStreamingParser_)
729 4 : bOriginalIdModifiedEmitted_ =
730 4 : poStreamingParser_->GetOriginalIdModifiedEmitted();
731 5 : delete poStreamingParser_;
732 5 : poStreamingParser_ = nullptr;
733 :
734 : OGRGeoJSONReaderStreamingParser oParser(*this, poLayer, false,
735 5 : bStoreNativeData_);
736 5 : oParser.SetOriginalIdModifiedEmitted(bOriginalIdModifiedEmitted_);
737 5 : VSIFSeekL(fp_, 0, SEEK_SET);
738 5 : bFirstSeg_ = true;
739 5 : bJSonPLikeWrapper_ = false;
740 5 : vsi_l_offset nCurOffset = 0;
741 5 : vsi_l_offset nFeatureOffset = 0;
742 : while (true)
743 : {
744 5 : size_t nRead = VSIFReadL(pabyBuffer_, 1, nBufferSize_, fp_);
745 5 : const bool bFinished = nRead < nBufferSize_;
746 5 : size_t nSkip = 0;
747 5 : if (bFirstSeg_)
748 : {
749 5 : bFirstSeg_ = false;
750 5 : nSkip = SkipPrologEpilogAndUpdateJSonPLikeWrapper(nRead);
751 : }
752 5 : if (bFinished && bJSonPLikeWrapper_ && nRead > nSkip)
753 0 : nRead--;
754 5 : auto pszPtr = reinterpret_cast<const char *>(pabyBuffer_ + nSkip);
755 1673 : for (size_t i = 0; i < nRead - nSkip; i++)
756 : {
757 1668 : oParser.ResetFeatureDetectionState();
758 1668 : if (!oParser.Parse(pszPtr + i, 1,
759 5004 : bFinished && (i + 1 == nRead - nSkip)) ||
760 1668 : oParser.ExceptionOccurred())
761 : {
762 0 : return nullptr;
763 : }
764 1668 : if (oParser.IsStartFeature())
765 : {
766 18 : nFeatureOffset = nCurOffset + i;
767 : }
768 1650 : else if (oParser.IsEndFeature())
769 : {
770 18 : vsi_l_offset nFeatureSize =
771 18 : (nCurOffset + i) - nFeatureOffset + 1;
772 18 : auto poFeat = oParser.GetNextFeature();
773 18 : if (poFeat)
774 : {
775 18 : const GIntBig nThisFID = poFeat->GetFID();
776 18 : if (!cpl::contains(oMapFIDToOffsetSize_, nThisFID))
777 : {
778 18 : oMapFIDToOffsetSize_[nThisFID] =
779 36 : std::pair<vsi_l_offset, vsi_l_offset>(
780 18 : nFeatureOffset, nFeatureSize);
781 : }
782 18 : delete poFeat;
783 : }
784 : }
785 : }
786 :
787 5 : if (bFinished)
788 5 : break;
789 0 : nCurOffset += nRead;
790 0 : }
791 :
792 5 : bOriginalIdModifiedEmitted_ = oParser.GetOriginalIdModifiedEmitted();
793 : }
794 :
795 22 : const auto oIter = oMapFIDToOffsetSize_.find(nFID);
796 22 : if (oIter == oMapFIDToOffsetSize_.end())
797 : {
798 5 : return nullptr;
799 : }
800 :
801 17 : VSIFSeekL(fp_, oIter->second.first, SEEK_SET);
802 17 : if (oIter->second.second > 1000 * 1000 * 1000)
803 : {
804 0 : return nullptr;
805 : }
806 17 : size_t nSize = static_cast<size_t>(oIter->second.second);
807 17 : char *pszBuffer = static_cast<char *>(VSIMalloc(nSize + 1));
808 17 : if (!pszBuffer)
809 : {
810 0 : return nullptr;
811 : }
812 17 : if (VSIFReadL(pszBuffer, 1, nSize, fp_) != nSize)
813 : {
814 0 : VSIFree(pszBuffer);
815 0 : return nullptr;
816 : }
817 17 : pszBuffer[nSize] = 0;
818 17 : json_object *poObj = nullptr;
819 17 : if (!OGRJSonParse(pszBuffer, &poObj))
820 : {
821 0 : VSIFree(pszBuffer);
822 0 : return nullptr;
823 : }
824 :
825 17 : OGRFeature *poFeat = ReadFeature(poLayer, poObj, pszBuffer);
826 17 : json_object_put(poObj);
827 17 : VSIFree(pszBuffer);
828 17 : if (!poFeat)
829 : {
830 0 : return nullptr;
831 : }
832 17 : poFeat->SetFID(nFID);
833 17 : return poFeat;
834 : }
835 :
836 : /************************************************************************/
837 : /* IngestAll() */
838 : /************************************************************************/
839 :
840 14 : bool OGRGeoJSONReader::IngestAll(OGRGeoJSONLayer *poLayer)
841 : {
842 : const vsi_l_offset nRAM =
843 14 : static_cast<vsi_l_offset>(CPLGetUsablePhysicalRAM()) / 3 * 4;
844 14 : if (nRAM && nTotalOGRFeatureMemEstimate_ > nRAM)
845 : {
846 0 : CPLError(CE_Failure, CPLE_OutOfMemory,
847 : "Not enough memory to ingest all the layer: " CPL_FRMT_GUIB
848 : " available, " CPL_FRMT_GUIB " needed",
849 : nRAM, nTotalOGRFeatureMemEstimate_);
850 0 : return false;
851 : }
852 :
853 14 : CPLDebug("GeoJSON",
854 : "Total memory estimated for ingestion: " CPL_FRMT_GUIB " bytes",
855 : nTotalOGRFeatureMemEstimate_);
856 :
857 14 : ResetReading();
858 14 : GIntBig nCounter = 0;
859 : while (true)
860 : {
861 42 : OGRFeature *poFeature = GetNextFeature(poLayer);
862 42 : if (poFeature == nullptr)
863 14 : break;
864 28 : poLayer->AddFeature(poFeature);
865 28 : delete poFeature;
866 28 : nCounter++;
867 28 : if (((nCounter % 10000) == 0 || nCounter == nTotalFeatureCount_) &&
868 12 : nTotalFeatureCount_ > 0)
869 : {
870 12 : CPLDebug("GeoJSON", "Ingestion at %.02f %%",
871 12 : 100.0 * nCounter / nTotalFeatureCount_);
872 : }
873 28 : }
874 14 : return true;
875 : }
876 :
877 : /************************************************************************/
878 : /* ReadLayer */
879 : /************************************************************************/
880 :
881 170 : void OGRGeoJSONReader::ReadLayer(OGRGeoJSONDataSource *poDS,
882 : const char *pszName, json_object *poObj)
883 : {
884 170 : GeoJSONObject::Type objType = OGRGeoJSONGetType(poObj);
885 170 : if (objType == GeoJSONObject::eUnknown)
886 : {
887 : // Check if the object contains key:value pairs where value
888 : // is a standard GeoJSON object. In which case, use key as the layer
889 : // name.
890 2 : if (json_type_object == json_object_get_type(poObj))
891 : {
892 : json_object_iter it;
893 2 : it.key = nullptr;
894 2 : it.val = nullptr;
895 2 : it.entry = nullptr;
896 6 : json_object_object_foreachC(poObj, it)
897 : {
898 4 : objType = OGRGeoJSONGetType(it.val);
899 4 : if (objType != GeoJSONObject::eUnknown)
900 4 : ReadLayer(poDS, it.key, it.val);
901 : }
902 : }
903 :
904 : // CPLError(CE_Failure, CPLE_AppDefined,
905 : // "Unrecognized GeoJSON structure.");
906 :
907 2 : return;
908 : }
909 :
910 168 : CPLErrorReset();
911 :
912 : // Figure out layer name
913 168 : if (pszName == nullptr)
914 : {
915 164 : if (GeoJSONObject::eFeatureCollection == objType)
916 : {
917 91 : json_object *poName = CPL_json_object_object_get(poObj, "name");
918 94 : if (poName != nullptr &&
919 3 : json_object_get_type(poName) == json_type_string)
920 : {
921 3 : pszName = json_object_get_string(poName);
922 : }
923 : }
924 164 : if (pszName == nullptr)
925 : {
926 161 : const char *pszDesc = poDS->GetDescription();
927 161 : if (strchr(pszDesc, '?') == nullptr &&
928 161 : strchr(pszDesc, '{') == nullptr)
929 : {
930 30 : pszName = CPLGetBasename(pszDesc);
931 : }
932 : }
933 164 : if (pszName == nullptr)
934 131 : pszName = OGRGeoJSONLayer::DefaultName;
935 : }
936 :
937 : OGRGeoJSONLayer *poLayer = new OGRGeoJSONLayer(
938 168 : pszName, nullptr, OGRGeoJSONLayer::DefaultGeometryType, poDS, nullptr);
939 :
940 168 : OGRSpatialReference *poSRS = OGRGeoJSONReadSpatialReference(poObj);
941 168 : bool bDefaultSRS = false;
942 168 : if (poSRS == nullptr)
943 : {
944 : // If there is none defined, we use 4326 / 4979.
945 161 : poSRS = new OGRSpatialReference();
946 161 : bDefaultSRS = true;
947 : }
948 : {
949 168 : auto poGeomFieldDefn = poLayer->GetLayerDefn()->GetGeomFieldDefn(0);
950 168 : whileUnsealing(poGeomFieldDefn)->SetSpatialRef(poSRS);
951 : }
952 :
953 168 : if (!GenerateLayerDefn(poLayer, poObj))
954 : {
955 1 : CPLError(CE_Failure, CPLE_AppDefined,
956 : "Layer schema generation failed.");
957 :
958 1 : delete poLayer;
959 1 : poSRS->Release();
960 1 : return;
961 : }
962 :
963 167 : if (GeoJSONObject::eFeatureCollection == objType)
964 : {
965 : json_object *poDescription =
966 92 : CPL_json_object_object_get(poObj, "description");
967 93 : if (poDescription != nullptr &&
968 1 : json_object_get_type(poDescription) == json_type_string)
969 : {
970 1 : poLayer->SetMetadataItem("DESCRIPTION",
971 1 : json_object_get_string(poDescription));
972 : }
973 :
974 92 : SetCoordinatePrecision(poObj, poLayer);
975 : }
976 :
977 : /* -------------------------------------------------------------------- */
978 : /* Translate single geometry-only Feature object. */
979 : /* -------------------------------------------------------------------- */
980 :
981 167 : if (GeoJSONObject::ePoint == objType ||
982 121 : GeoJSONObject::eMultiPoint == objType ||
983 119 : GeoJSONObject::eLineString == objType ||
984 118 : GeoJSONObject::eMultiLineString == objType ||
985 116 : GeoJSONObject::ePolygon == objType ||
986 111 : GeoJSONObject::eMultiPolygon == objType ||
987 : GeoJSONObject::eGeometryCollection == objType)
988 : {
989 58 : OGRGeometry *poGeometry = ReadGeometry(poObj, poLayer->GetSpatialRef());
990 58 : if (!AddFeature(poLayer, poGeometry))
991 : {
992 1 : CPLDebug("GeoJSON", "Translation of single geometry failed.");
993 1 : delete poLayer;
994 1 : poSRS->Release();
995 1 : return;
996 57 : }
997 : }
998 : /* -------------------------------------------------------------------- */
999 : /* Translate single but complete Feature object. */
1000 : /* -------------------------------------------------------------------- */
1001 109 : else if (GeoJSONObject::eFeature == objType)
1002 : {
1003 17 : OGRFeature *poFeature = ReadFeature(poLayer, poObj, nullptr);
1004 17 : AddFeature(poLayer, poFeature);
1005 : }
1006 : /* -------------------------------------------------------------------- */
1007 : /* Translate multi-feature FeatureCollection object. */
1008 : /* -------------------------------------------------------------------- */
1009 92 : else if (GeoJSONObject::eFeatureCollection == objType)
1010 : {
1011 92 : ReadFeatureCollection(poLayer, poObj);
1012 : }
1013 :
1014 166 : if (CPLGetLastErrorType() != CE_Warning)
1015 163 : CPLErrorReset();
1016 :
1017 166 : poLayer->DetectGeometryType();
1018 :
1019 166 : if (bDefaultSRS && poLayer->GetGeomType() != wkbNone)
1020 : {
1021 159 : if (OGR_GT_HasZ(poLayer->GetGeomType()))
1022 46 : poSRS->importFromEPSG(4979);
1023 : else
1024 113 : poSRS->SetFromUserInput(SRS_WKT_WGS84_LAT_LONG);
1025 159 : poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
1026 : }
1027 166 : poSRS->Release();
1028 :
1029 166 : poDS->AddLayer(poLayer);
1030 : }
1031 :
1032 : /************************************************************************/
1033 : /* GenerateLayerDefn() */
1034 : /************************************************************************/
1035 :
1036 168 : bool OGRGeoJSONReader::GenerateLayerDefn(OGRGeoJSONLayer *poLayer,
1037 : json_object *poGJObject)
1038 : {
1039 168 : CPLAssert(nullptr != poGJObject);
1040 168 : CPLAssert(nullptr != poLayer->GetLayerDefn());
1041 168 : CPLAssert(0 == poLayer->GetLayerDefn()->GetFieldCount());
1042 :
1043 168 : if (bAttributesSkip_)
1044 0 : return true;
1045 :
1046 : /* -------------------------------------------------------------------- */
1047 : /* Scan all features and generate layer definition. */
1048 : /* -------------------------------------------------------------------- */
1049 168 : bool bSuccess = true;
1050 :
1051 336 : std::map<std::string, int> oMapFieldNameToIdx;
1052 336 : std::vector<std::unique_ptr<OGRFieldDefn>> apoFieldDefn;
1053 336 : gdal::DirectedAcyclicGraph<int, std::string> dag;
1054 :
1055 168 : GeoJSONObject::Type objType = OGRGeoJSONGetType(poGJObject);
1056 168 : if (GeoJSONObject::eFeature == objType)
1057 : {
1058 17 : bSuccess = GenerateFeatureDefn(oMapFieldNameToIdx, apoFieldDefn, dag,
1059 : poLayer, poGJObject);
1060 : }
1061 151 : else if (GeoJSONObject::eFeatureCollection == objType)
1062 : {
1063 : json_object *poObjFeatures =
1064 93 : OGRGeoJSONFindMemberByName(poGJObject, "features");
1065 186 : if (nullptr != poObjFeatures &&
1066 93 : json_type_array == json_object_get_type(poObjFeatures))
1067 : {
1068 93 : const auto nFeatures = json_object_array_length(poObjFeatures);
1069 208 : for (auto i = decltype(nFeatures){0}; i < nFeatures; ++i)
1070 : {
1071 : json_object *poObjFeature =
1072 115 : json_object_array_get_idx(poObjFeatures, i);
1073 115 : if (!GenerateFeatureDefn(oMapFieldNameToIdx, apoFieldDefn, dag,
1074 : poLayer, poObjFeature))
1075 : {
1076 1 : CPLDebug("GeoJSON", "Create feature schema failure.");
1077 1 : bSuccess = false;
1078 : }
1079 : }
1080 : }
1081 : else
1082 : {
1083 0 : CPLError(CE_Failure, CPLE_AppDefined,
1084 : "Invalid FeatureCollection object. "
1085 : "Missing \'features\' member.");
1086 0 : bSuccess = false;
1087 : }
1088 : }
1089 :
1090 : // Note: the current strategy will not produce stable output, depending
1091 : // on the order of features, if there are conflicting order / cycles.
1092 : // See https://github.com/OSGeo/gdal/pull/4552 for a number of potential
1093 : // resolutions if that has to be solved in the future.
1094 168 : OGRFeatureDefn *poDefn = poLayer->GetLayerDefn();
1095 336 : const auto sortedFields = dag.getTopologicalOrdering();
1096 168 : CPLAssert(sortedFields.size() == apoFieldDefn.size());
1097 : {
1098 336 : auto oTemporaryUnsealer(poDefn->GetTemporaryUnsealer());
1099 287 : for (int idx : sortedFields)
1100 : {
1101 119 : poDefn->AddFieldDefn(apoFieldDefn[idx].get());
1102 : }
1103 : }
1104 :
1105 168 : CPLString osFIDColumn;
1106 168 : FinalizeLayerDefn(poLayer, osFIDColumn);
1107 168 : if (!osFIDColumn.empty())
1108 8 : poLayer->SetFIDColumn(osFIDColumn);
1109 :
1110 168 : return bSuccess;
1111 : }
1112 :
1113 : /************************************************************************/
1114 : /* FinalizeLayerDefn() */
1115 : /************************************************************************/
1116 :
1117 476 : void OGRGeoJSONBaseReader::FinalizeLayerDefn(OGRLayer *poLayer,
1118 : CPLString &osFIDColumn)
1119 : {
1120 : /* -------------------------------------------------------------------- */
1121 : /* Validate and add FID column if necessary. */
1122 : /* -------------------------------------------------------------------- */
1123 476 : osFIDColumn.clear();
1124 476 : OGRFeatureDefn *poLayerDefn = poLayer->GetLayerDefn();
1125 476 : CPLAssert(nullptr != poLayerDefn);
1126 :
1127 476 : whileUnsealing(poLayerDefn)->SetGeomType(m_eLayerGeomType);
1128 :
1129 476 : if (m_bNeedFID64)
1130 : {
1131 4 : poLayer->SetMetadataItem(OLMD_FID64, "YES");
1132 : }
1133 :
1134 476 : if (!bFeatureLevelIdAsFID_)
1135 : {
1136 453 : const int idx = poLayerDefn->GetFieldIndexCaseSensitive("id");
1137 453 : if (idx >= 0)
1138 : {
1139 67 : OGRFieldDefn *poFDefn = poLayerDefn->GetFieldDefn(idx);
1140 102 : if (poFDefn->GetType() == OFTInteger ||
1141 35 : poFDefn->GetType() == OFTInteger64)
1142 : {
1143 34 : osFIDColumn = poLayerDefn->GetFieldDefn(idx)->GetNameRef();
1144 : }
1145 : }
1146 : }
1147 476 : }
1148 :
1149 : /************************************************************************/
1150 : /* OGRGeoJSONReaderAddOrUpdateField() */
1151 : /************************************************************************/
1152 :
1153 20073 : void OGRGeoJSONReaderAddOrUpdateField(
1154 : std::vector<int> &retIndices,
1155 : std::map<std::string, int> &oMapFieldNameToIdx,
1156 : std::vector<std::unique_ptr<OGRFieldDefn>> &apoFieldDefn,
1157 : const char *pszKey, json_object *poVal, bool bFlattenNestedAttributes,
1158 : char chNestedAttributeSeparator, bool bArrayAsString, bool bDateAsString,
1159 : std::set<int> &aoSetUndeterminedTypeFields)
1160 : {
1161 20073 : const auto jType = json_object_get_type(poVal);
1162 20073 : if (bFlattenNestedAttributes && poVal != nullptr &&
1163 : jType == json_type_object)
1164 : {
1165 : json_object_iter it;
1166 2 : it.key = nullptr;
1167 2 : it.val = nullptr;
1168 2 : it.entry = nullptr;
1169 6 : json_object_object_foreachC(poVal, it)
1170 : {
1171 4 : char szSeparator[2] = {chNestedAttributeSeparator, '\0'};
1172 :
1173 : CPLString osAttrName(
1174 8 : CPLSPrintf("%s%s%s", pszKey, szSeparator, it.key));
1175 8 : if (it.val != nullptr &&
1176 4 : json_object_get_type(it.val) == json_type_object)
1177 : {
1178 0 : OGRGeoJSONReaderAddOrUpdateField(
1179 : retIndices, oMapFieldNameToIdx, apoFieldDefn, osAttrName,
1180 : it.val, true, chNestedAttributeSeparator, bArrayAsString,
1181 : bDateAsString, aoSetUndeterminedTypeFields);
1182 : }
1183 : else
1184 : {
1185 4 : OGRGeoJSONReaderAddOrUpdateField(
1186 : retIndices, oMapFieldNameToIdx, apoFieldDefn, osAttrName,
1187 : it.val, false, 0, bArrayAsString, bDateAsString,
1188 : aoSetUndeterminedTypeFields);
1189 : }
1190 : }
1191 2 : return;
1192 : }
1193 :
1194 20071 : const auto oMapFieldNameToIdxIter = oMapFieldNameToIdx.find(pszKey);
1195 20071 : if (oMapFieldNameToIdxIter == oMapFieldNameToIdx.end())
1196 : {
1197 : OGRFieldSubType eSubType;
1198 : const OGRFieldType eType =
1199 1021 : GeoJSONPropertyToFieldType(poVal, eSubType, bArrayAsString);
1200 2042 : auto poFieldDefn = std::make_unique<OGRFieldDefn>(pszKey, eType);
1201 1021 : poFieldDefn->SetSubType(eSubType);
1202 1021 : if (eSubType == OFSTBoolean)
1203 34 : poFieldDefn->SetWidth(1);
1204 1021 : if (poFieldDefn->GetType() == OFTString && !bDateAsString)
1205 : {
1206 500 : int nTZFlag = 0;
1207 500 : poFieldDefn->SetType(
1208 : GeoJSONStringPropertyToFieldType(poVal, nTZFlag));
1209 500 : poFieldDefn->SetTZFlag(nTZFlag);
1210 : }
1211 1021 : apoFieldDefn.emplace_back(std::move(poFieldDefn));
1212 1021 : const int nIndex = static_cast<int>(apoFieldDefn.size()) - 1;
1213 1021 : retIndices.emplace_back(nIndex);
1214 1021 : oMapFieldNameToIdx[pszKey] = nIndex;
1215 1021 : if (poVal == nullptr)
1216 8 : aoSetUndeterminedTypeFields.insert(nIndex);
1217 : }
1218 19050 : else if (poVal)
1219 : {
1220 19035 : const int nIndex = oMapFieldNameToIdxIter->second;
1221 19035 : retIndices.emplace_back(nIndex);
1222 : // If there is a null value: do not update field definition.
1223 19035 : OGRFieldDefn *poFDefn = apoFieldDefn[nIndex].get();
1224 19035 : const OGRFieldType eType = poFDefn->GetType();
1225 19035 : const OGRFieldSubType eSubType = poFDefn->GetSubType();
1226 : OGRFieldSubType eNewSubType;
1227 : OGRFieldType eNewType =
1228 19035 : GeoJSONPropertyToFieldType(poVal, eNewSubType, bArrayAsString);
1229 : const bool bNewIsEmptyArray =
1230 19035 : (jType == json_type_array && json_object_array_length(poVal) == 0);
1231 19035 : if (cpl::contains(aoSetUndeterminedTypeFields, nIndex))
1232 : {
1233 7 : poFDefn->SetSubType(OFSTNone);
1234 7 : poFDefn->SetType(eNewType);
1235 7 : if (poFDefn->GetType() == OFTString && !bDateAsString)
1236 : {
1237 2 : int nTZFlag = 0;
1238 2 : poFDefn->SetType(
1239 : GeoJSONStringPropertyToFieldType(poVal, nTZFlag));
1240 2 : poFDefn->SetTZFlag(nTZFlag);
1241 : }
1242 7 : poFDefn->SetSubType(eNewSubType);
1243 7 : aoSetUndeterminedTypeFields.erase(nIndex);
1244 : }
1245 19028 : else if (eType == OFTInteger)
1246 : {
1247 12971 : if (eNewType == OFTInteger && eSubType == OFSTBoolean &&
1248 5 : eNewSubType != OFSTBoolean)
1249 : {
1250 2 : poFDefn->SetSubType(OFSTNone);
1251 : }
1252 12969 : else if (eNewType == OFTInteger64 || eNewType == OFTReal ||
1253 12955 : eNewType == OFTInteger64List || eNewType == OFTRealList ||
1254 : eNewType == OFTStringList)
1255 : {
1256 18 : poFDefn->SetSubType(OFSTNone);
1257 18 : poFDefn->SetType(eNewType);
1258 : }
1259 12951 : else if (eNewType == OFTIntegerList)
1260 : {
1261 4 : if (eSubType == OFSTBoolean && eNewSubType != OFSTBoolean)
1262 : {
1263 1 : poFDefn->SetSubType(OFSTNone);
1264 : }
1265 4 : poFDefn->SetType(eNewType);
1266 : }
1267 12947 : else if (eNewType != OFTInteger)
1268 : {
1269 15 : poFDefn->SetSubType(OFSTNone);
1270 15 : poFDefn->SetType(OFTString);
1271 15 : poFDefn->SetSubType(OFSTJSON);
1272 : }
1273 : }
1274 6057 : else if (eType == OFTInteger64)
1275 : {
1276 15 : if (eNewType == OFTReal)
1277 : {
1278 2 : poFDefn->SetSubType(OFSTNone);
1279 2 : poFDefn->SetType(eNewType);
1280 : }
1281 13 : else if (eNewType == OFTIntegerList || eNewType == OFTInteger64List)
1282 : {
1283 3 : poFDefn->SetSubType(OFSTNone);
1284 3 : poFDefn->SetType(OFTInteger64List);
1285 : }
1286 10 : else if (eNewType == OFTRealList || eNewType == OFTStringList)
1287 : {
1288 2 : poFDefn->SetSubType(OFSTNone);
1289 2 : poFDefn->SetType(eNewType);
1290 : }
1291 8 : else if (eNewType != OFTInteger && eNewType != OFTInteger64)
1292 : {
1293 2 : poFDefn->SetSubType(OFSTNone);
1294 2 : poFDefn->SetType(OFTString);
1295 2 : poFDefn->SetSubType(OFSTJSON);
1296 : }
1297 : }
1298 6042 : else if (eType == OFTReal)
1299 : {
1300 413 : if (eNewType == OFTIntegerList || eNewType == OFTInteger64List ||
1301 : eNewType == OFTRealList)
1302 : {
1303 4 : poFDefn->SetSubType(OFSTNone);
1304 4 : poFDefn->SetType(OFTRealList);
1305 : }
1306 409 : else if (eNewType == OFTStringList)
1307 : {
1308 1 : poFDefn->SetSubType(OFSTNone);
1309 1 : poFDefn->SetType(OFTStringList);
1310 : }
1311 408 : else if (eNewType != OFTInteger && eNewType != OFTInteger64 &&
1312 : eNewType != OFTReal)
1313 : {
1314 2 : poFDefn->SetSubType(OFSTNone);
1315 2 : poFDefn->SetType(OFTString);
1316 2 : poFDefn->SetSubType(OFSTJSON);
1317 : }
1318 : }
1319 5629 : else if (eType == OFTString)
1320 : {
1321 5353 : if (eSubType == OFSTNone)
1322 : {
1323 5317 : if (eNewType == OFTStringList)
1324 : {
1325 1 : poFDefn->SetType(OFTStringList);
1326 : }
1327 5316 : else if (eNewType != OFTString)
1328 : {
1329 15 : poFDefn->SetSubType(OFSTJSON);
1330 : }
1331 : }
1332 : }
1333 276 : else if (eType == OFTIntegerList)
1334 : {
1335 50 : if (eNewType == OFTString)
1336 : {
1337 6 : if (!bNewIsEmptyArray)
1338 : {
1339 6 : poFDefn->SetSubType(OFSTNone);
1340 6 : poFDefn->SetType(eNewType);
1341 6 : poFDefn->SetSubType(OFSTJSON);
1342 : }
1343 : }
1344 44 : else if (eNewType == OFTInteger64List || eNewType == OFTRealList ||
1345 : eNewType == OFTStringList)
1346 : {
1347 19 : poFDefn->SetSubType(OFSTNone);
1348 19 : poFDefn->SetType(eNewType);
1349 : }
1350 25 : else if (eNewType == OFTInteger64)
1351 : {
1352 2 : poFDefn->SetSubType(OFSTNone);
1353 2 : poFDefn->SetType(OFTInteger64List);
1354 : }
1355 23 : else if (eNewType == OFTReal)
1356 : {
1357 2 : poFDefn->SetSubType(OFSTNone);
1358 2 : poFDefn->SetType(OFTRealList);
1359 : }
1360 21 : else if (eNewType == OFTInteger || eNewType == OFTIntegerList)
1361 : {
1362 21 : if (eSubType == OFSTBoolean && eNewSubType != OFSTBoolean)
1363 : {
1364 2 : poFDefn->SetSubType(OFSTNone);
1365 : }
1366 : }
1367 : else
1368 : {
1369 0 : poFDefn->SetSubType(OFSTNone);
1370 0 : poFDefn->SetType(OFTString);
1371 0 : poFDefn->SetSubType(OFSTJSON);
1372 : }
1373 : }
1374 226 : else if (eType == OFTInteger64List)
1375 : {
1376 24 : if (eNewType == OFTString)
1377 : {
1378 3 : if (!bNewIsEmptyArray)
1379 : {
1380 3 : poFDefn->SetSubType(OFSTNone);
1381 3 : poFDefn->SetType(eNewType);
1382 3 : poFDefn->SetSubType(OFSTJSON);
1383 : }
1384 : }
1385 21 : else if (eNewType == OFTInteger64List || eNewType == OFTRealList ||
1386 : eNewType == OFTStringList)
1387 : {
1388 9 : poFDefn->SetSubType(OFSTNone);
1389 9 : poFDefn->SetType(eNewType);
1390 : }
1391 12 : else if (eNewType == OFTReal)
1392 : {
1393 1 : poFDefn->SetSubType(OFSTNone);
1394 1 : poFDefn->SetType(OFTRealList);
1395 : }
1396 11 : else if (eNewType != OFTInteger && eNewType != OFTInteger64 &&
1397 : eNewType != OFTIntegerList)
1398 : {
1399 0 : poFDefn->SetSubType(OFSTNone);
1400 0 : poFDefn->SetType(OFTString);
1401 0 : poFDefn->SetSubType(OFSTJSON);
1402 : }
1403 : }
1404 202 : else if (eType == OFTRealList)
1405 : {
1406 24 : if (eNewType == OFTString)
1407 : {
1408 3 : if (!bNewIsEmptyArray)
1409 : {
1410 3 : poFDefn->SetSubType(OFSTNone);
1411 3 : poFDefn->SetType(eNewType);
1412 3 : poFDefn->SetSubType(OFSTJSON);
1413 : }
1414 : }
1415 21 : else if (eNewType == OFTStringList)
1416 : {
1417 1 : poFDefn->SetSubType(OFSTNone);
1418 1 : poFDefn->SetType(eNewType);
1419 : }
1420 20 : else if (eNewType != OFTInteger && eNewType != OFTInteger64 &&
1421 16 : eNewType != OFTReal && eNewType != OFTIntegerList &&
1422 4 : eNewType != OFTInteger64List && eNewType != OFTRealList)
1423 : {
1424 0 : poFDefn->SetSubType(OFSTNone);
1425 0 : poFDefn->SetType(OFTString);
1426 0 : poFDefn->SetSubType(OFSTJSON);
1427 : }
1428 : }
1429 178 : else if (eType == OFTStringList)
1430 : {
1431 30 : if (eNewType == OFTString && eNewSubType == OFSTJSON)
1432 : {
1433 1 : if (!bNewIsEmptyArray)
1434 : {
1435 1 : poFDefn->SetSubType(OFSTNone);
1436 1 : poFDefn->SetType(eNewType);
1437 1 : poFDefn->SetSubType(OFSTJSON);
1438 : }
1439 : }
1440 : }
1441 148 : else if (eType == OFTDate || eType == OFTTime || eType == OFTDateTime)
1442 : {
1443 148 : if (eNewType == OFTString && !bDateAsString &&
1444 147 : eNewSubType == OFSTNone)
1445 : {
1446 146 : int nTZFlag = 0;
1447 146 : eNewType = GeoJSONStringPropertyToFieldType(poVal, nTZFlag);
1448 156 : if (poFDefn->GetTZFlag() > OGR_TZFLAG_UNKNOWN &&
1449 10 : nTZFlag != poFDefn->GetTZFlag())
1450 : {
1451 6 : if (nTZFlag == OGR_TZFLAG_UNKNOWN)
1452 4 : poFDefn->SetTZFlag(OGR_TZFLAG_UNKNOWN);
1453 : else
1454 2 : poFDefn->SetTZFlag(OGR_TZFLAG_MIXED_TZ);
1455 : }
1456 : }
1457 148 : if (eType != eNewType)
1458 : {
1459 8 : poFDefn->SetSubType(OFSTNone);
1460 8 : if (eNewType == OFTString)
1461 : {
1462 5 : poFDefn->SetType(eNewType);
1463 5 : poFDefn->SetSubType(eNewSubType);
1464 : }
1465 3 : else if (eType == OFTDate && eNewType == OFTDateTime)
1466 : {
1467 1 : poFDefn->SetType(OFTDateTime);
1468 : }
1469 2 : else if (!(eType == OFTDateTime && eNewType == OFTDate))
1470 : {
1471 1 : poFDefn->SetType(OFTString);
1472 1 : poFDefn->SetSubType(OFSTJSON);
1473 : }
1474 : }
1475 : }
1476 :
1477 19035 : poFDefn->SetWidth(poFDefn->GetSubType() == OFSTBoolean ? 1 : 0);
1478 : }
1479 : else
1480 : {
1481 15 : const int nIndex = oMapFieldNameToIdxIter->second;
1482 15 : retIndices.emplace_back(nIndex);
1483 : }
1484 : }
1485 :
1486 : /************************************************************************/
1487 : /* OGRGeoJSONGenerateFeatureDefnDealWithID() */
1488 : /************************************************************************/
1489 :
1490 4916 : void OGRGeoJSONGenerateFeatureDefnDealWithID(
1491 : json_object *poObj, json_object *poObjProps, int &nPrevFieldIdx,
1492 : std::map<std::string, int> &oMapFieldNameToIdx,
1493 : std::vector<std::unique_ptr<OGRFieldDefn>> &apoFieldDefn,
1494 : gdal::DirectedAcyclicGraph<int, std::string> &dag,
1495 : bool &bFeatureLevelIdAsFID, bool &bFeatureLevelIdAsAttribute,
1496 : bool &bNeedFID64)
1497 : {
1498 4916 : json_object *poObjId = OGRGeoJSONFindMemberByName(poObj, "id");
1499 4916 : if (poObjId)
1500 : {
1501 1697 : const auto iterIdxId = oMapFieldNameToIdx.find("id");
1502 1697 : if (iterIdxId == oMapFieldNameToIdx.end())
1503 : {
1504 107 : if (json_object_get_type(poObjId) == json_type_int)
1505 : {
1506 : // If the value is negative, we cannot use it as the FID
1507 : // as OGRMemLayer doesn't support negative FID. And we would
1508 : // have an ambiguity with -1 that can mean OGRNullFID
1509 : // so in that case create a regular attribute and let OGR
1510 : // attribute sequential OGR FIDs.
1511 71 : if (json_object_get_int64(poObjId) < 0)
1512 : {
1513 5 : bFeatureLevelIdAsFID = false;
1514 : }
1515 : else
1516 : {
1517 66 : bFeatureLevelIdAsFID = true;
1518 : }
1519 : }
1520 107 : if (!bFeatureLevelIdAsFID)
1521 : {
1522 : // If there's a top-level id of type string or negative int,
1523 : // and no properties.id, then declare a id field.
1524 41 : bool bHasRegularIdProp = false;
1525 80 : if (nullptr != poObjProps &&
1526 39 : json_object_get_type(poObjProps) == json_type_object)
1527 : {
1528 39 : bHasRegularIdProp =
1529 39 : CPL_json_object_object_get(poObjProps, "id") != nullptr;
1530 : }
1531 41 : if (!bHasRegularIdProp)
1532 : {
1533 38 : OGRFieldType eType = OFTString;
1534 38 : if (json_object_get_type(poObjId) == json_type_int)
1535 : {
1536 5 : if (CPL_INT64_FITS_ON_INT32(
1537 : json_object_get_int64(poObjId)))
1538 4 : eType = OFTInteger;
1539 : else
1540 1 : eType = OFTInteger64;
1541 : }
1542 : apoFieldDefn.emplace_back(
1543 38 : std::make_unique<OGRFieldDefn>("id", eType));
1544 38 : const int nIdx = static_cast<int>(apoFieldDefn.size()) - 1;
1545 38 : oMapFieldNameToIdx["id"] = nIdx;
1546 38 : nPrevFieldIdx = nIdx;
1547 38 : dag.addNode(nIdx, "id");
1548 38 : bFeatureLevelIdAsAttribute = true;
1549 : }
1550 : }
1551 : }
1552 : else
1553 : {
1554 1590 : const int nIdx = iterIdxId->second;
1555 1590 : nPrevFieldIdx = nIdx;
1556 1607 : if (bFeatureLevelIdAsAttribute &&
1557 17 : json_object_get_type(poObjId) == json_type_int)
1558 : {
1559 3 : if (apoFieldDefn[nIdx]->GetType() == OFTInteger)
1560 : {
1561 1 : if (!CPL_INT64_FITS_ON_INT32(
1562 : json_object_get_int64(poObjId)))
1563 1 : apoFieldDefn[nIdx]->SetType(OFTInteger64);
1564 : }
1565 : }
1566 1587 : else if (bFeatureLevelIdAsAttribute)
1567 : {
1568 14 : apoFieldDefn[nIdx]->SetType(OFTString);
1569 : }
1570 : }
1571 : }
1572 :
1573 4916 : if (!bNeedFID64)
1574 : {
1575 4915 : json_object *poId = CPL_json_object_object_get(poObj, "id");
1576 4915 : if (poId == nullptr)
1577 : {
1578 6392 : if (poObjProps &&
1579 3173 : json_object_get_type(poObjProps) == json_type_object)
1580 : {
1581 3172 : poId = CPL_json_object_object_get(poObjProps, "id");
1582 : }
1583 : }
1584 4915 : if (poId != nullptr && json_object_get_type(poId) == json_type_int)
1585 : {
1586 1689 : GIntBig nFID = json_object_get_int64(poId);
1587 1689 : if (!CPL_INT64_FITS_ON_INT32(nFID))
1588 : {
1589 4 : bNeedFID64 = true;
1590 : }
1591 : }
1592 : }
1593 4916 : }
1594 :
1595 : /************************************************************************/
1596 : /* GenerateFeatureDefn() */
1597 : /************************************************************************/
1598 4697 : bool OGRGeoJSONBaseReader::GenerateFeatureDefn(
1599 : std::map<std::string, int> &oMapFieldNameToIdx,
1600 : std::vector<std::unique_ptr<OGRFieldDefn>> &apoFieldDefn,
1601 : gdal::DirectedAcyclicGraph<int, std::string> &dag, OGRLayer *poLayer,
1602 : json_object *poObj)
1603 : {
1604 : /* -------------------------------------------------------------------- */
1605 : /* Read collection of properties. */
1606 : /* -------------------------------------------------------------------- */
1607 : lh_entry *poObjPropsEntry =
1608 4697 : OGRGeoJSONFindMemberEntryByName(poObj, "properties");
1609 4697 : json_object *poObjProps =
1610 4697 : const_cast<json_object *>(static_cast<const json_object *>(
1611 : poObjPropsEntry ? poObjPropsEntry->v : nullptr));
1612 :
1613 9394 : std::vector<int> anCurFieldIndices;
1614 4697 : int nPrevFieldIdx = -1;
1615 :
1616 4697 : OGRGeoJSONGenerateFeatureDefnDealWithID(
1617 : poObj, poObjProps, nPrevFieldIdx, oMapFieldNameToIdx, apoFieldDefn, dag,
1618 4697 : bFeatureLevelIdAsFID_, bFeatureLevelIdAsAttribute_, m_bNeedFID64);
1619 :
1620 4697 : json_object *poGeomObj = CPL_json_object_object_get(poObj, "geometry");
1621 4697 : if (poGeomObj && json_object_get_type(poGeomObj) == json_type_object)
1622 : {
1623 4451 : const auto eType = OGRGeoJSONGetOGRGeometryType(poGeomObj);
1624 :
1625 4451 : OGRGeoJSONUpdateLayerGeomType(m_bFirstGeometry, eType,
1626 4451 : m_eLayerGeomType);
1627 :
1628 4451 : if (eType != wkbNone && eType != wkbUnknown)
1629 : {
1630 : // This is maybe too optimistic: it assumes that the geometry
1631 : // coordinates array is in the correct format
1632 4451 : m_bExtentRead |= OGRGeoJSONGetExtent3D(poGeomObj, &m_oEnvelope3D);
1633 : }
1634 : }
1635 :
1636 4697 : bool bSuccess = false;
1637 :
1638 9349 : if (nullptr != poObjProps &&
1639 4652 : json_object_get_type(poObjProps) == json_type_object)
1640 : {
1641 4651 : if (bIsGeocouchSpatiallistFormat)
1642 : {
1643 3 : poObjProps = CPL_json_object_object_get(poObjProps, "properties");
1644 6 : if (nullptr == poObjProps ||
1645 3 : json_object_get_type(poObjProps) != json_type_object)
1646 : {
1647 2 : return true;
1648 : }
1649 : }
1650 :
1651 : json_object_iter it;
1652 4651 : it.key = nullptr;
1653 4651 : it.val = nullptr;
1654 4651 : it.entry = nullptr;
1655 24367 : json_object_object_foreachC(poObjProps, it)
1656 : {
1657 39427 : if (!bIsGeocouchSpatiallistFormat &&
1658 19709 : !cpl::contains(oMapFieldNameToIdx, it.key))
1659 : {
1660 : // Detect the special kind of GeoJSON output by a spatiallist of
1661 : // GeoCouch such as:
1662 : // http://gd.iriscouch.com/cphosm/_design/geo/_rewrite/data?bbox=12.53%2C55.73%2C12.54%2C55.73
1663 886 : if (strcmp(it.key, "_id") == 0)
1664 : {
1665 2 : bFoundGeocouchId = true;
1666 : }
1667 884 : else if (bFoundGeocouchId && strcmp(it.key, "_rev") == 0)
1668 : {
1669 2 : bFoundRev = true;
1670 : }
1671 4 : else if (bFoundRev && strcmp(it.key, "type") == 0 &&
1672 2 : it.val != nullptr &&
1673 888 : json_object_get_type(it.val) == json_type_string &&
1674 2 : strcmp(json_object_get_string(it.val), "Feature") == 0)
1675 : {
1676 2 : bFoundTypeFeature = true;
1677 : }
1678 1762 : else if (bFoundTypeFeature &&
1679 2 : strcmp(it.key, "properties") == 0 &&
1680 884 : it.val != nullptr &&
1681 2 : json_object_get_type(it.val) == json_type_object)
1682 : {
1683 2 : if (bFlattenGeocouchSpatiallistFormat < 0)
1684 2 : bFlattenGeocouchSpatiallistFormat =
1685 2 : CPLTestBool(CPLGetConfigOption(
1686 : "GEOJSON_FLATTEN_GEOCOUCH", "TRUE"));
1687 2 : if (bFlattenGeocouchSpatiallistFormat)
1688 : {
1689 2 : const auto typeIter = oMapFieldNameToIdx.find("type");
1690 2 : if (typeIter != oMapFieldNameToIdx.end())
1691 : {
1692 2 : const int nIdx = typeIter->second;
1693 2 : apoFieldDefn.erase(apoFieldDefn.begin() + nIdx);
1694 2 : oMapFieldNameToIdx.erase(typeIter);
1695 2 : dag.removeNode(nIdx);
1696 : }
1697 :
1698 2 : bIsGeocouchSpatiallistFormat = true;
1699 2 : return GenerateFeatureDefn(oMapFieldNameToIdx,
1700 : apoFieldDefn, dag, poLayer,
1701 2 : poObj);
1702 : }
1703 : }
1704 : }
1705 :
1706 19716 : anCurFieldIndices.clear();
1707 19716 : OGRGeoJSONReaderAddOrUpdateField(
1708 19716 : anCurFieldIndices, oMapFieldNameToIdx, apoFieldDefn, it.key,
1709 19716 : it.val, bFlattenNestedAttributes_, chNestedAttributeSeparator_,
1710 19716 : bArrayAsString_, bDateAsString_, aoSetUndeterminedTypeFields_);
1711 39434 : for (int idx : anCurFieldIndices)
1712 : {
1713 19718 : dag.addNode(idx, apoFieldDefn[idx]->GetNameRef());
1714 19718 : if (nPrevFieldIdx != -1)
1715 : {
1716 17392 : dag.addEdge(nPrevFieldIdx, idx);
1717 : }
1718 19718 : nPrevFieldIdx = idx;
1719 : }
1720 : }
1721 :
1722 4649 : bSuccess = true; // SUCCESS
1723 : }
1724 47 : else if (nullptr != poObjPropsEntry &&
1725 1 : (poObjProps == nullptr ||
1726 1 : (json_object_get_type(poObjProps) == json_type_array &&
1727 1 : json_object_array_length(poObjProps) == 0)))
1728 : {
1729 : // Ignore "properties": null and "properties": []
1730 13 : bSuccess = true;
1731 : }
1732 65 : else if (poObj != nullptr &&
1733 32 : json_object_get_type(poObj) == json_type_object)
1734 : {
1735 : json_object_iter it;
1736 32 : it.key = nullptr;
1737 32 : it.val = nullptr;
1738 32 : it.entry = nullptr;
1739 100 : json_object_object_foreachC(poObj, it)
1740 : {
1741 68 : if (strcmp(it.key, "type") != 0 &&
1742 36 : strcmp(it.key, "geometry") != 0 &&
1743 4 : strcmp(it.key, "centroid") != 0 &&
1744 4 : strcmp(it.key, "bbox") != 0 && strcmp(it.key, "center") != 0)
1745 : {
1746 4 : if (!cpl::contains(oMapFieldNameToIdx, it.key))
1747 : {
1748 4 : anCurFieldIndices.clear();
1749 4 : OGRGeoJSONReaderAddOrUpdateField(
1750 : anCurFieldIndices, oMapFieldNameToIdx, apoFieldDefn,
1751 4 : it.key, it.val, bFlattenNestedAttributes_,
1752 4 : chNestedAttributeSeparator_, bArrayAsString_,
1753 4 : bDateAsString_, aoSetUndeterminedTypeFields_);
1754 8 : for (int idx : anCurFieldIndices)
1755 : {
1756 4 : dag.addNode(idx, apoFieldDefn[idx]->GetNameRef());
1757 4 : if (nPrevFieldIdx != -1)
1758 : {
1759 0 : dag.addEdge(nPrevFieldIdx, idx);
1760 : }
1761 4 : nPrevFieldIdx = idx;
1762 : }
1763 : }
1764 : }
1765 : }
1766 :
1767 32 : bSuccess = true; // SUCCESS
1768 : // CPLError(CE_Failure, CPLE_AppDefined,
1769 : // "Invalid Feature object. "
1770 : // "Missing \'properties\' member." );
1771 : }
1772 :
1773 4695 : return bSuccess;
1774 : }
1775 :
1776 : /************************************************************************/
1777 : /* OGRGeoJSONUpdateLayerGeomType() */
1778 : /************************************************************************/
1779 :
1780 4666 : bool OGRGeoJSONUpdateLayerGeomType(bool &bFirstGeom,
1781 : OGRwkbGeometryType eGeomType,
1782 : OGRwkbGeometryType &eLayerGeomType)
1783 : {
1784 4666 : if (bFirstGeom)
1785 : {
1786 415 : eLayerGeomType = eGeomType;
1787 415 : bFirstGeom = false;
1788 : }
1789 4262 : else if (OGR_GT_HasZ(eGeomType) && !OGR_GT_HasZ(eLayerGeomType) &&
1790 11 : wkbFlatten(eGeomType) == wkbFlatten(eLayerGeomType))
1791 : {
1792 2 : eLayerGeomType = eGeomType;
1793 : }
1794 4252 : else if (!OGR_GT_HasZ(eGeomType) && OGR_GT_HasZ(eLayerGeomType) &&
1795 3 : wkbFlatten(eGeomType) == wkbFlatten(eLayerGeomType))
1796 : {
1797 : // ok
1798 : }
1799 4247 : else if (eGeomType != eLayerGeomType && eLayerGeomType != wkbUnknown)
1800 : {
1801 45 : CPLDebug("GeoJSON", "Detected layer of mixed-geometry type features.");
1802 45 : eLayerGeomType = wkbUnknown;
1803 45 : return false;
1804 : }
1805 4621 : return true;
1806 : }
1807 :
1808 : /************************************************************************/
1809 : /* AddFeature */
1810 : /************************************************************************/
1811 :
1812 58 : bool OGRGeoJSONReader::AddFeature(OGRGeoJSONLayer *poLayer,
1813 : OGRGeometry *poGeometry)
1814 : {
1815 58 : bool bAdded = false;
1816 :
1817 : // TODO: Should we check if geometry is of type of wkbGeometryCollection?
1818 :
1819 58 : if (nullptr != poGeometry)
1820 : {
1821 57 : OGRFeature *poFeature = new OGRFeature(poLayer->GetLayerDefn());
1822 57 : poFeature->SetGeometryDirectly(poGeometry);
1823 :
1824 57 : bAdded = AddFeature(poLayer, poFeature);
1825 : }
1826 :
1827 58 : return bAdded;
1828 : }
1829 :
1830 : /************************************************************************/
1831 : /* AddFeature */
1832 : /************************************************************************/
1833 :
1834 188 : bool OGRGeoJSONReader::AddFeature(OGRGeoJSONLayer *poLayer,
1835 : OGRFeature *poFeature)
1836 : {
1837 188 : if (poFeature == nullptr)
1838 0 : return false;
1839 :
1840 188 : poLayer->AddFeature(poFeature);
1841 188 : delete poFeature;
1842 :
1843 188 : return true;
1844 : }
1845 :
1846 : /************************************************************************/
1847 : /* ReadGeometry */
1848 : /************************************************************************/
1849 :
1850 1250 : OGRGeometry *OGRGeoJSONBaseReader::ReadGeometry(json_object *poObj,
1851 : OGRSpatialReference *poLayerSRS)
1852 : {
1853 1250 : OGRGeometry *poGeometry = OGRGeoJSONReadGeometry(poObj, poLayerSRS);
1854 :
1855 : /* -------------------------------------------------------------------- */
1856 : /* Wrap geometry with GeometryCollection as a common denominator. */
1857 : /* Sometimes a GeoJSON text may consist of objects of different */
1858 : /* geometry types. Users may request wrapping all geometries with */
1859 : /* OGRGeometryCollection type by using option */
1860 : /* GEOMETRY_AS_COLLECTION=NO|YES (NO is default). */
1861 : /* -------------------------------------------------------------------- */
1862 1250 : if (nullptr != poGeometry)
1863 : {
1864 1235 : if (!bGeometryPreserve_ &&
1865 0 : wkbGeometryCollection != poGeometry->getGeometryType())
1866 : {
1867 0 : OGRGeometryCollection *poMetaGeometry = new OGRGeometryCollection();
1868 0 : poMetaGeometry->addGeometryDirectly(poGeometry);
1869 0 : return poMetaGeometry;
1870 : }
1871 : }
1872 :
1873 1250 : return poGeometry;
1874 : }
1875 :
1876 : /************************************************************************/
1877 : /* OGRGeoJSONReaderSetFieldNestedAttribute() */
1878 : /************************************************************************/
1879 :
1880 2 : static void OGRGeoJSONReaderSetFieldNestedAttribute(OGRLayer *poLayer,
1881 : OGRFeature *poFeature,
1882 : const char *pszAttrPrefix,
1883 : char chSeparator,
1884 : json_object *poVal)
1885 : {
1886 : json_object_iter it;
1887 2 : it.key = nullptr;
1888 2 : it.val = nullptr;
1889 2 : it.entry = nullptr;
1890 6 : json_object_object_foreachC(poVal, it)
1891 : {
1892 4 : const char szSeparator[2] = {chSeparator, '\0'};
1893 : const CPLString osAttrName(
1894 8 : CPLSPrintf("%s%s%s", pszAttrPrefix, szSeparator, it.key));
1895 8 : if (it.val != nullptr &&
1896 4 : json_object_get_type(it.val) == json_type_object)
1897 : {
1898 0 : OGRGeoJSONReaderSetFieldNestedAttribute(
1899 : poLayer, poFeature, osAttrName, chSeparator, it.val);
1900 : }
1901 : else
1902 : {
1903 : const int nField =
1904 4 : poFeature->GetDefnRef()->GetFieldIndexCaseSensitive(osAttrName);
1905 4 : OGRGeoJSONReaderSetField(poLayer, poFeature, nField, osAttrName,
1906 : it.val, false, 0);
1907 : }
1908 : }
1909 2 : }
1910 :
1911 : /************************************************************************/
1912 : /* OGRGeoJSONReaderSetField() */
1913 : /************************************************************************/
1914 :
1915 5987 : void OGRGeoJSONReaderSetField(OGRLayer *poLayer, OGRFeature *poFeature,
1916 : int nField, const char *pszAttrPrefix,
1917 : json_object *poVal, bool bFlattenNestedAttributes,
1918 : char chNestedAttributeSeparator)
1919 : {
1920 5991 : if (bFlattenNestedAttributes && poVal != nullptr &&
1921 4 : json_object_get_type(poVal) == json_type_object)
1922 : {
1923 2 : OGRGeoJSONReaderSetFieldNestedAttribute(
1924 : poLayer, poFeature, pszAttrPrefix, chNestedAttributeSeparator,
1925 : poVal);
1926 2 : return;
1927 : }
1928 5985 : if (nField < 0)
1929 0 : return;
1930 :
1931 5985 : OGRFieldDefn *poFieldDefn = poFeature->GetFieldDefnRef(nField);
1932 5985 : CPLAssert(nullptr != poFieldDefn);
1933 5985 : OGRFieldType eType = poFieldDefn->GetType();
1934 :
1935 5985 : if (poVal == nullptr)
1936 : {
1937 86 : poFeature->SetFieldNull(nField);
1938 : }
1939 5899 : else if (OFTInteger == eType)
1940 : {
1941 1701 : poFeature->SetField(nField, json_object_get_int(poVal));
1942 :
1943 : // Check if FID available and set correct value.
1944 1701 : if (EQUAL(poFieldDefn->GetNameRef(), poLayer->GetFIDColumn()))
1945 145 : poFeature->SetFID(json_object_get_int(poVal));
1946 : }
1947 4198 : else if (OFTInteger64 == eType)
1948 : {
1949 26 : poFeature->SetField(nField, (GIntBig)json_object_get_int64(poVal));
1950 :
1951 : // Check if FID available and set correct value.
1952 26 : if (EQUAL(poFieldDefn->GetNameRef(), poLayer->GetFIDColumn()))
1953 0 : poFeature->SetFID(
1954 0 : static_cast<GIntBig>(json_object_get_int64(poVal)));
1955 : }
1956 4172 : else if (OFTReal == eType)
1957 : {
1958 1521 : poFeature->SetField(nField, json_object_get_double(poVal));
1959 : }
1960 2651 : else if (OFTIntegerList == eType)
1961 : {
1962 59 : const enum json_type eJSonType(json_object_get_type(poVal));
1963 59 : if (eJSonType == json_type_array)
1964 : {
1965 51 : const auto nLength = json_object_array_length(poVal);
1966 51 : int *panVal = static_cast<int *>(CPLMalloc(sizeof(int) * nLength));
1967 108 : for (auto i = decltype(nLength){0}; i < nLength; i++)
1968 : {
1969 57 : json_object *poRow = json_object_array_get_idx(poVal, i);
1970 57 : panVal[i] = json_object_get_int(poRow);
1971 : }
1972 51 : poFeature->SetField(nField, static_cast<int>(nLength), panVal);
1973 51 : CPLFree(panVal);
1974 : }
1975 8 : else if (eJSonType == json_type_boolean || eJSonType == json_type_int)
1976 : {
1977 8 : poFeature->SetField(nField, json_object_get_int(poVal));
1978 : }
1979 : }
1980 2592 : else if (OFTInteger64List == eType)
1981 : {
1982 77 : const enum json_type eJSonType(json_object_get_type(poVal));
1983 77 : if (eJSonType == json_type_array)
1984 : {
1985 67 : const auto nLength = json_object_array_length(poVal);
1986 : GIntBig *panVal =
1987 67 : static_cast<GIntBig *>(CPLMalloc(sizeof(GIntBig) * nLength));
1988 149 : for (auto i = decltype(nLength){0}; i < nLength; i++)
1989 : {
1990 82 : json_object *poRow = json_object_array_get_idx(poVal, i);
1991 82 : panVal[i] = static_cast<GIntBig>(json_object_get_int64(poRow));
1992 : }
1993 67 : poFeature->SetField(nField, static_cast<int>(nLength), panVal);
1994 67 : CPLFree(panVal);
1995 : }
1996 10 : else if (eJSonType == json_type_boolean || eJSonType == json_type_int)
1997 : {
1998 10 : poFeature->SetField(
1999 10 : nField, static_cast<GIntBig>(json_object_get_int64(poVal)));
2000 : }
2001 : }
2002 2515 : else if (OFTRealList == eType)
2003 : {
2004 96 : const enum json_type eJSonType(json_object_get_type(poVal));
2005 96 : if (eJSonType == json_type_array)
2006 : {
2007 82 : const auto nLength = json_object_array_length(poVal);
2008 : double *padfVal =
2009 82 : static_cast<double *>(CPLMalloc(sizeof(double) * nLength));
2010 179 : for (auto i = decltype(nLength){0}; i < nLength; i++)
2011 : {
2012 97 : json_object *poRow = json_object_array_get_idx(poVal, i);
2013 97 : padfVal[i] = json_object_get_double(poRow);
2014 : }
2015 82 : poFeature->SetField(nField, static_cast<int>(nLength), padfVal);
2016 82 : CPLFree(padfVal);
2017 : }
2018 14 : else if (eJSonType == json_type_boolean || eJSonType == json_type_int ||
2019 : eJSonType == json_type_double)
2020 : {
2021 14 : poFeature->SetField(nField, json_object_get_double(poVal));
2022 : }
2023 : }
2024 2419 : else if (OFTStringList == eType)
2025 : {
2026 80 : const enum json_type eJSonType(json_object_get_type(poVal));
2027 80 : if (eJSonType == json_type_array)
2028 : {
2029 70 : auto nLength = json_object_array_length(poVal);
2030 : char **papszVal =
2031 70 : (char **)CPLMalloc(sizeof(char *) * (nLength + 1));
2032 70 : decltype(nLength) i = 0; // Used after for.
2033 143 : for (; i < nLength; i++)
2034 : {
2035 73 : json_object *poRow = json_object_array_get_idx(poVal, i);
2036 73 : const char *pszVal = json_object_get_string(poRow);
2037 73 : if (pszVal == nullptr)
2038 0 : break;
2039 73 : papszVal[i] = CPLStrdup(pszVal);
2040 : }
2041 70 : papszVal[i] = nullptr;
2042 70 : poFeature->SetField(nField, papszVal);
2043 70 : CSLDestroy(papszVal);
2044 : }
2045 : else
2046 : {
2047 10 : poFeature->SetField(nField, json_object_get_string(poVal));
2048 : }
2049 : }
2050 : else
2051 : {
2052 2339 : poFeature->SetField(nField, json_object_get_string(poVal));
2053 : }
2054 : }
2055 :
2056 : /************************************************************************/
2057 : /* ReadFeature() */
2058 : /************************************************************************/
2059 :
2060 1558 : OGRFeature *OGRGeoJSONBaseReader::ReadFeature(OGRLayer *poLayer,
2061 : json_object *poObj,
2062 : const char *pszSerializedObj)
2063 : {
2064 1558 : CPLAssert(nullptr != poObj);
2065 :
2066 1558 : OGRFeatureDefn *poFDefn = poLayer->GetLayerDefn();
2067 1558 : OGRFeature *poFeature = new OGRFeature(poFDefn);
2068 :
2069 1558 : if (bStoreNativeData_)
2070 : {
2071 430 : poFeature->SetNativeData(pszSerializedObj
2072 : ? pszSerializedObj
2073 10 : : json_object_to_json_string(poObj));
2074 420 : poFeature->SetNativeMediaType("application/vnd.geo+json");
2075 : }
2076 :
2077 : /* -------------------------------------------------------------------- */
2078 : /* Translate GeoJSON "properties" object to feature attributes. */
2079 : /* -------------------------------------------------------------------- */
2080 1558 : CPLAssert(nullptr != poFeature);
2081 :
2082 1558 : json_object *poObjProps = OGRGeoJSONFindMemberByName(poObj, "properties");
2083 3075 : if (!bAttributesSkip_ && nullptr != poObjProps &&
2084 1517 : json_object_get_type(poObjProps) == json_type_object)
2085 : {
2086 1516 : if (bIsGeocouchSpatiallistFormat)
2087 : {
2088 3 : json_object *poId = CPL_json_object_object_get(poObjProps, "_id");
2089 6 : if (poId != nullptr &&
2090 3 : json_object_get_type(poId) == json_type_string)
2091 3 : poFeature->SetField("_id", json_object_get_string(poId));
2092 :
2093 3 : json_object *poRev = CPL_json_object_object_get(poObjProps, "_rev");
2094 6 : if (poRev != nullptr &&
2095 3 : json_object_get_type(poRev) == json_type_string)
2096 : {
2097 3 : poFeature->SetField("_rev", json_object_get_string(poRev));
2098 : }
2099 :
2100 3 : poObjProps = CPL_json_object_object_get(poObjProps, "properties");
2101 6 : if (nullptr == poObjProps ||
2102 3 : json_object_get_type(poObjProps) != json_type_object)
2103 : {
2104 0 : return poFeature;
2105 : }
2106 : }
2107 :
2108 : json_object_iter it;
2109 1516 : it.key = nullptr;
2110 1516 : it.val = nullptr;
2111 1516 : it.entry = nullptr;
2112 5985 : json_object_object_foreachC(poObjProps, it)
2113 : {
2114 4469 : const int nField = poFDefn->GetFieldIndexCaseSensitive(it.key);
2115 4471 : if (nField < 0 &&
2116 2 : !(bFlattenNestedAttributes_ && it.val != nullptr &&
2117 2 : json_object_get_type(it.val) == json_type_object))
2118 : {
2119 0 : CPLDebug("GeoJSON", "Cannot find field %s", it.key);
2120 : }
2121 : else
2122 : {
2123 4469 : OGRGeoJSONReaderSetField(poLayer, poFeature, nField, it.key,
2124 4469 : it.val, bFlattenNestedAttributes_,
2125 4469 : chNestedAttributeSeparator_);
2126 : }
2127 : }
2128 : }
2129 :
2130 1558 : if (!bAttributesSkip_ && nullptr == poObjProps)
2131 : {
2132 : json_object_iter it;
2133 41 : it.key = nullptr;
2134 41 : it.val = nullptr;
2135 41 : it.entry = nullptr;
2136 137 : json_object_object_foreachC(poObj, it)
2137 : {
2138 96 : const int nFldIndex = poFDefn->GetFieldIndexCaseSensitive(it.key);
2139 96 : if (nFldIndex >= 0)
2140 : {
2141 4 : if (it.val)
2142 4 : poFeature->SetField(nFldIndex,
2143 : json_object_get_string(it.val));
2144 : else
2145 0 : poFeature->SetFieldNull(nFldIndex);
2146 : }
2147 : }
2148 : }
2149 :
2150 : /* -------------------------------------------------------------------- */
2151 : /* Try to use feature-level ID if available */
2152 : /* and of integral type. Otherwise, leave unset (-1) then index */
2153 : /* in features sequence will be used as FID. */
2154 : /* -------------------------------------------------------------------- */
2155 1558 : json_object *poObjId = OGRGeoJSONFindMemberByName(poObj, "id");
2156 1558 : if (nullptr != poObjId && bFeatureLevelIdAsFID_)
2157 : {
2158 57 : poFeature->SetFID(static_cast<GIntBig>(json_object_get_int64(poObjId)));
2159 : }
2160 :
2161 : /* -------------------------------------------------------------------- */
2162 : /* Handle the case where the special id is in a regular field. */
2163 : /* -------------------------------------------------------------------- */
2164 1501 : else if (nullptr != poObjId)
2165 : {
2166 45 : const int nIdx = poFDefn->GetFieldIndexCaseSensitive("id");
2167 45 : if (nIdx >= 0 && !poFeature->IsFieldSet(nIdx))
2168 : {
2169 41 : poFeature->SetField(nIdx, json_object_get_string(poObjId));
2170 : }
2171 : }
2172 :
2173 : /* -------------------------------------------------------------------- */
2174 : /* Translate geometry sub-object of GeoJSON Feature. */
2175 : /* -------------------------------------------------------------------- */
2176 1558 : json_object *poObjGeom = nullptr;
2177 1558 : json_object *poTmp = poObj;
2178 : json_object_iter it;
2179 1558 : it.key = nullptr;
2180 1558 : it.val = nullptr;
2181 1558 : it.entry = nullptr;
2182 5956 : json_object_object_foreachC(poTmp, it)
2183 : {
2184 4741 : if (EQUAL(it.key, "geometry"))
2185 : {
2186 1531 : if (it.val != nullptr)
2187 1188 : poObjGeom = it.val;
2188 : // Done. They had 'geometry':null.
2189 : else
2190 343 : return poFeature;
2191 : }
2192 : }
2193 :
2194 1215 : if (nullptr != poObjGeom)
2195 : {
2196 : // NOTE: If geometry can not be parsed or read correctly
2197 : // then NULL geometry is assigned to a feature and
2198 : // geometry type for layer is classified as wkbUnknown.
2199 : OGRGeometry *poGeometry =
2200 1188 : ReadGeometry(poObjGeom, poLayer->GetSpatialRef());
2201 1188 : if (nullptr != poGeometry)
2202 : {
2203 1174 : poFeature->SetGeometryDirectly(poGeometry);
2204 : }
2205 : }
2206 : else
2207 : {
2208 : static bool bWarned = false;
2209 27 : if (!bWarned)
2210 : {
2211 1 : bWarned = true;
2212 1 : CPLDebug(
2213 : "GeoJSON",
2214 : "Non conformant Feature object. Missing \'geometry\' member.");
2215 : }
2216 : }
2217 :
2218 1215 : return poFeature;
2219 : }
2220 :
2221 : /************************************************************************/
2222 : /* Extent getters */
2223 : /************************************************************************/
2224 :
2225 30 : bool OGRGeoJSONBaseReader::ExtentRead() const
2226 : {
2227 30 : return m_bExtentRead;
2228 : }
2229 :
2230 24 : OGREnvelope3D OGRGeoJSONBaseReader::GetExtent3D() const
2231 : {
2232 24 : return m_oEnvelope3D;
2233 : }
2234 :
2235 : /************************************************************************/
2236 : /* ReadFeatureCollection() */
2237 : /************************************************************************/
2238 :
2239 92 : void OGRGeoJSONReader::ReadFeatureCollection(OGRGeoJSONLayer *poLayer,
2240 : json_object *poObj)
2241 : {
2242 92 : json_object *poObjFeatures = OGRGeoJSONFindMemberByName(poObj, "features");
2243 92 : if (nullptr == poObjFeatures)
2244 : {
2245 0 : CPLError(CE_Failure, CPLE_AppDefined,
2246 : "Invalid FeatureCollection object. "
2247 : "Missing \'features\' member.");
2248 0 : return;
2249 : }
2250 :
2251 92 : if (json_type_array == json_object_get_type(poObjFeatures))
2252 : {
2253 92 : const auto nFeatures = json_object_array_length(poObjFeatures);
2254 206 : for (auto i = decltype(nFeatures){0}; i < nFeatures; ++i)
2255 : {
2256 : json_object *poObjFeature =
2257 114 : json_object_array_get_idx(poObjFeatures, i);
2258 114 : OGRFeature *poFeature = ReadFeature(poLayer, poObjFeature, nullptr);
2259 114 : AddFeature(poLayer, poFeature);
2260 : }
2261 : }
2262 :
2263 : // Collect top objects except 'type' and the 'features' array.
2264 92 : if (bStoreNativeData_)
2265 : {
2266 : json_object_iter it;
2267 5 : it.key = nullptr;
2268 5 : it.val = nullptr;
2269 5 : it.entry = nullptr;
2270 10 : CPLString osNativeData;
2271 25 : json_object_object_foreachC(poObj, it)
2272 : {
2273 20 : if (strcmp(it.key, "type") == 0 || strcmp(it.key, "features") == 0)
2274 : {
2275 10 : continue;
2276 : }
2277 10 : if (osNativeData.empty())
2278 3 : osNativeData = "{ ";
2279 : else
2280 7 : osNativeData += ", ";
2281 10 : json_object *poKey = json_object_new_string(it.key);
2282 10 : osNativeData += json_object_to_json_string(poKey);
2283 10 : json_object_put(poKey);
2284 10 : osNativeData += ": ";
2285 10 : osNativeData += json_object_to_json_string(it.val);
2286 : }
2287 5 : if (osNativeData.empty())
2288 : {
2289 2 : osNativeData = "{ ";
2290 : }
2291 5 : osNativeData += " }";
2292 :
2293 5 : osNativeData = "NATIVE_DATA=" + osNativeData;
2294 :
2295 5 : char *apszMetadata[3] = {
2296 5 : const_cast<char *>(osNativeData.c_str()),
2297 : const_cast<char *>("NATIVE_MEDIA_TYPE=application/vnd.geo+json"),
2298 5 : nullptr};
2299 :
2300 5 : poLayer->SetMetadata(apszMetadata, "NATIVE_DATA");
2301 : }
2302 : }
2303 :
2304 : /************************************************************************/
2305 : /* OGRGeoJSONGetExtent3D() */
2306 : /************************************************************************/
2307 :
2308 4451 : bool OGRGeoJSONGetExtent3D(json_object *poObj, OGREnvelope3D *poEnvelope)
2309 : {
2310 4451 : if (!poEnvelope || !poObj)
2311 : {
2312 0 : return false;
2313 : }
2314 :
2315 : // poObjCoords can be an array of arrays, this lambda function will
2316 : // recursively parse the array
2317 8902 : std::function<bool(json_object *, OGREnvelope3D *)> fParseCoords;
2318 194494 : fParseCoords = [&fParseCoords](json_object *poObjCoordsIn,
2319 190039 : OGREnvelope3D *poEnvelopeIn) -> bool
2320 : {
2321 194494 : if (json_type_array == json_object_get_type(poObjCoordsIn))
2322 : {
2323 194494 : const auto nItems = json_object_array_length(poObjCoordsIn);
2324 :
2325 194494 : double dXVal = std::numeric_limits<double>::quiet_NaN();
2326 194494 : double dYVal = std::numeric_limits<double>::quiet_NaN();
2327 194494 : double dZVal = std::numeric_limits<double>::quiet_NaN();
2328 :
2329 756072 : for (auto i = decltype(nItems){0}; i < nItems; ++i)
2330 : {
2331 :
2332 : // Get the i element
2333 : json_object *poObjCoordsElement =
2334 561595 : json_object_array_get_idx(poObjCoordsIn, i);
2335 :
2336 561595 : const json_type eType{json_object_get_type(poObjCoordsElement)};
2337 :
2338 : // if it is an array, recurse
2339 561595 : if (json_type_array == eType)
2340 : {
2341 190039 : if (!fParseCoords(poObjCoordsElement, poEnvelopeIn))
2342 : {
2343 1 : return false;
2344 : }
2345 : }
2346 371556 : else if (json_type_double == eType || json_type_int == eType)
2347 : {
2348 371540 : switch (i)
2349 : {
2350 185650 : case 0:
2351 : {
2352 185650 : dXVal = json_object_get_double(poObjCoordsElement);
2353 185650 : break;
2354 : }
2355 185649 : case 1:
2356 : {
2357 185649 : dYVal = json_object_get_double(poObjCoordsElement);
2358 185649 : break;
2359 : }
2360 241 : case 2:
2361 : {
2362 241 : dZVal = json_object_get_double(poObjCoordsElement);
2363 241 : break;
2364 : }
2365 0 : default:
2366 0 : return false;
2367 : }
2368 : }
2369 : else
2370 : {
2371 16 : return false;
2372 : }
2373 : }
2374 :
2375 194477 : if (!std::isnan(dXVal) && !std::isnan(dYVal))
2376 : {
2377 185648 : if (std::isnan(dZVal))
2378 : {
2379 : static_cast<OGREnvelope *>(poEnvelopeIn)
2380 185407 : ->Merge(dXVal, dYVal);
2381 : }
2382 : else
2383 : {
2384 241 : poEnvelopeIn->Merge(dXVal, dYVal, dZVal);
2385 : }
2386 : }
2387 :
2388 194477 : return true;
2389 : }
2390 : else
2391 : {
2392 0 : return false;
2393 : }
2394 4451 : };
2395 :
2396 : // This function looks for "coordinates" and for "geometries" to handle
2397 : // geometry collections. It will recurse on itself to handle nested geometry.
2398 8902 : std::function<bool(json_object *, OGREnvelope3D *)> fParseGeometry;
2399 4473 : fParseGeometry = [&fParseGeometry,
2400 : &fParseCoords](json_object *poObjIn,
2401 4477 : OGREnvelope3D *poEnvelopeIn) -> bool
2402 : {
2403 : // Get the "coordinates" array from the JSON object
2404 : json_object *poObjCoords =
2405 4473 : OGRGeoJSONFindMemberByName(poObjIn, "coordinates");
2406 :
2407 : // Return if found and not an array
2408 4473 : if (poObjCoords && json_object_get_type(poObjCoords) != json_type_array)
2409 : {
2410 0 : return false;
2411 : }
2412 4473 : else if (poObjCoords)
2413 : {
2414 4455 : return fParseCoords(poObjCoords, poEnvelopeIn);
2415 : }
2416 :
2417 : // Try "geometries"
2418 18 : if (!poObjCoords)
2419 : {
2420 18 : poObjCoords = OGRGeoJSONFindMemberByName(poObjIn, "geometries");
2421 : }
2422 :
2423 : // Return if not found or not an array
2424 28 : if (!poObjCoords ||
2425 10 : json_object_get_type(poObjCoords) != json_type_array)
2426 : {
2427 8 : return false;
2428 : }
2429 : else
2430 : {
2431 : // Loop thgrough the geometries
2432 10 : const auto nItems = json_object_array_length(poObjCoords);
2433 30 : for (auto i = decltype(nItems){0}; i < nItems; ++i)
2434 : {
2435 : json_object *poObjGeometry =
2436 22 : json_object_array_get_idx(poObjCoords, i);
2437 :
2438 : // Recurse
2439 22 : if (!fParseGeometry(poObjGeometry, poEnvelopeIn))
2440 : {
2441 2 : return false;
2442 : }
2443 : }
2444 8 : return true;
2445 : }
2446 4451 : };
2447 :
2448 4451 : return fParseGeometry(poObj, poEnvelope);
2449 : }
|