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