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