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