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