Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: OpenGIS Simple Features Reference Implementation
4 : * Purpose: Implementation of OGRGeoJSONDataSource class (OGR GeoJSON Driver).
5 : * Author: Mateusz Loskot, mateusz@loskot.net
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2007, Mateusz Loskot
9 : * Copyright (c) 2008-2013, Even Rouault <even dot rouault at spatialys.com>
10 : *
11 : * SPDX-License-Identifier: MIT
12 : ****************************************************************************/
13 :
14 : #include "cpl_port.h"
15 : #include "ogr_geojson.h"
16 :
17 : #include <cmath>
18 : #include <cstddef>
19 : #include <cstdlib>
20 : #include <cstring>
21 : #include <string>
22 :
23 : #include "cpl_conv.h"
24 : #include "cpl_error.h"
25 : #include "cpl_http.h"
26 : #include "cpl_string.h"
27 : #include "cpl_vsi.h"
28 : #include "cpl_vsi_error.h"
29 : #include "json.h"
30 : // #include "json_object.h"
31 : #include "gdal_utils.h"
32 : #include "gdal.h"
33 : #include "gdal_priv.h"
34 : #include "ogr_core.h"
35 : #include "ogr_feature.h"
36 : #include "ogr_geometry.h"
37 : #include "ogr_spatialref.h"
38 : #include "ogrlibjsonutils.h"
39 : #include "ogrgeojsonreader.h"
40 : #include "ogrgeojsonutils.h"
41 : #include "ogrgeojsonwriter.h"
42 : #include "ogrsf_frmts.h"
43 : #include "ogr_schema_override.h"
44 :
45 : // #include "symbol_renames.h"
46 :
47 : /************************************************************************/
48 : /* OGRGeoJSONDataSource() */
49 : /************************************************************************/
50 :
51 719 : OGRGeoJSONDataSource::OGRGeoJSONDataSource()
52 : : pszName_(nullptr), pszGeoData_(nullptr), nGeoDataLen_(0),
53 : papoLayers_(nullptr), papoLayersWriter_(nullptr), nLayers_(0),
54 : fpOut_(nullptr), flTransGeom_(OGRGeoJSONDataSource::eGeometryPreserve),
55 : flTransAttrs_(OGRGeoJSONDataSource::eAttributesPreserve),
56 : bOtherPages_(false), bFpOutputIsSeekable_(false), nBBOXInsertLocation_(0),
57 719 : bUpdatable_(false)
58 : {
59 719 : }
60 :
61 : /************************************************************************/
62 : /* ~OGRGeoJSONDataSource() */
63 : /************************************************************************/
64 :
65 1438 : OGRGeoJSONDataSource::~OGRGeoJSONDataSource()
66 : {
67 719 : OGRGeoJSONDataSource::Close();
68 1438 : }
69 :
70 : /************************************************************************/
71 : /* Close() */
72 : /************************************************************************/
73 :
74 1252 : CPLErr OGRGeoJSONDataSource::Close()
75 : {
76 1252 : CPLErr eErr = CE_None;
77 1252 : if (nOpenFlags != OPEN_FLAGS_CLOSED)
78 : {
79 719 : if (OGRGeoJSONDataSource::FlushCache(true) != CE_None)
80 0 : eErr = CE_Failure;
81 :
82 719 : if (!OGRGeoJSONDataSource::Clear())
83 0 : eErr = CE_Failure;
84 :
85 719 : if (GDALDataset::Close() != CE_None)
86 0 : eErr = CE_Failure;
87 : }
88 1252 : return eErr;
89 : }
90 :
91 : /************************************************************************/
92 : /* DealWithOgrSchemaOpenOption() */
93 : /************************************************************************/
94 :
95 533 : bool OGRGeoJSONDataSource::DealWithOgrSchemaOpenOption(
96 : const GDALOpenInfo *poOpenInfo)
97 : {
98 :
99 : std::string osFieldsSchemaOverrideParam =
100 1066 : CSLFetchNameValueDef(poOpenInfo->papszOpenOptions, "OGR_SCHEMA", "");
101 :
102 533 : if (!osFieldsSchemaOverrideParam.empty())
103 : {
104 :
105 8 : if (poOpenInfo->eAccess == GA_Update)
106 : {
107 0 : CPLError(CE_Failure, CPLE_NotSupported,
108 : "OGR_SCHEMA open option is not supported in update mode.");
109 3 : return false;
110 : }
111 :
112 8 : OGRSchemaOverride osSchemaOverride;
113 15 : if (!osSchemaOverride.LoadFromJSON(osFieldsSchemaOverrideParam) ||
114 7 : !osSchemaOverride.IsValid())
115 : {
116 1 : return false;
117 : }
118 :
119 7 : const auto &oLayerOverrides = osSchemaOverride.GetLayerOverrides();
120 12 : for (const auto &oLayer : oLayerOverrides)
121 : {
122 7 : const auto &oLayerName = oLayer.first;
123 7 : const auto &oLayerFieldOverride = oLayer.second;
124 7 : const bool bIsFullOverride{oLayerFieldOverride.IsFullOverride()};
125 7 : auto oFieldOverrides = oLayerFieldOverride.GetFieldOverrides();
126 7 : std::vector<OGRFieldDefn *> aoFields;
127 :
128 7 : CPLDebug("GeoJSON", "Applying schema override for layer %s",
129 : oLayerName.c_str());
130 :
131 : // Fail if the layer name does not exist
132 7 : auto poLayer = GetLayerByName(oLayerName.c_str());
133 7 : if (poLayer == nullptr)
134 : {
135 1 : CPLError(CE_Failure, CPLE_AppDefined,
136 : "Layer %s not found in GeoJSON file",
137 : oLayerName.c_str());
138 1 : return false;
139 : }
140 :
141 : // Patch field definitions
142 6 : auto poLayerDefn = poLayer->GetLayerDefn();
143 54 : for (int i = 0; i < poLayerDefn->GetFieldCount(); i++)
144 : {
145 48 : auto poFieldDefn = poLayerDefn->GetFieldDefn(i);
146 : auto oFieldOverride =
147 48 : oFieldOverrides.find(poFieldDefn->GetNameRef());
148 48 : if (oFieldOverride != oFieldOverrides.cend())
149 : {
150 8 : if (oFieldOverride->second.GetFieldType().has_value())
151 8 : whileUnsealing(poFieldDefn)
152 4 : ->SetType(
153 4 : oFieldOverride->second.GetFieldType().value());
154 8 : if (oFieldOverride->second.GetFieldWidth().has_value())
155 2 : whileUnsealing(poFieldDefn)
156 1 : ->SetWidth(
157 1 : oFieldOverride->second.GetFieldWidth().value());
158 8 : if (oFieldOverride->second.GetFieldPrecision().has_value())
159 2 : whileUnsealing(poFieldDefn)
160 1 : ->SetPrecision(
161 2 : oFieldOverride->second.GetFieldPrecision()
162 1 : .value());
163 8 : if (oFieldOverride->second.GetFieldSubType().has_value())
164 8 : whileUnsealing(poFieldDefn)
165 4 : ->SetSubType(
166 8 : oFieldOverride->second.GetFieldSubType()
167 4 : .value());
168 8 : if (oFieldOverride->second.GetFieldName().has_value())
169 0 : whileUnsealing(poFieldDefn)
170 0 : ->SetName(oFieldOverride->second.GetFieldName()
171 0 : .value()
172 : .c_str());
173 :
174 8 : if (bIsFullOverride)
175 : {
176 2 : aoFields.push_back(poFieldDefn);
177 : }
178 8 : oFieldOverrides.erase(oFieldOverride);
179 : }
180 : }
181 :
182 : // Error if any field override is not found
183 6 : if (!oFieldOverrides.empty())
184 : {
185 2 : CPLError(CE_Failure, CPLE_AppDefined,
186 : "Field %s not found in layer %s",
187 1 : oFieldOverrides.cbegin()->first.c_str(),
188 : oLayerName.c_str());
189 1 : return false;
190 : }
191 :
192 : // Remove fields not in the override
193 5 : if (bIsFullOverride)
194 : {
195 9 : for (int i = poLayerDefn->GetFieldCount() - 1; i >= 0; i--)
196 : {
197 8 : auto poFieldDefn = poLayerDefn->GetFieldDefn(i);
198 8 : if (std::find(aoFields.begin(), aoFields.end(),
199 8 : poFieldDefn) == aoFields.end())
200 : {
201 6 : whileUnsealing(poLayerDefn)->DeleteFieldDefn(i);
202 : }
203 : }
204 : }
205 : }
206 : }
207 530 : return true;
208 : }
209 :
210 : /************************************************************************/
211 : /* Open() */
212 : /************************************************************************/
213 :
214 560 : int OGRGeoJSONDataSource::Open(GDALOpenInfo *poOpenInfo,
215 : GeoJSONSourceType nSrcType,
216 : const char *pszJSonFlavor)
217 : {
218 560 : osJSonFlavor_ = pszJSonFlavor;
219 :
220 560 : const char *pszUnprefixed = poOpenInfo->pszFilename;
221 560 : if (STARTS_WITH_CI(pszUnprefixed, pszJSonFlavor) &&
222 1 : pszUnprefixed[strlen(pszJSonFlavor)] == ':')
223 : {
224 1 : pszUnprefixed += strlen(pszJSonFlavor) + 1;
225 : }
226 :
227 560 : if (eGeoJSONSourceService == nSrcType)
228 : {
229 23 : if (!ReadFromService(poOpenInfo, pszUnprefixed))
230 19 : return FALSE;
231 4 : if (poOpenInfo->eAccess == GA_Update)
232 : {
233 0 : CPLError(CE_Failure, CPLE_NotSupported,
234 : "Update from remote service not supported");
235 0 : return FALSE;
236 : }
237 : }
238 537 : else if (eGeoJSONSourceText == nSrcType)
239 : {
240 182 : if (poOpenInfo->eAccess == GA_Update)
241 : {
242 1 : CPLError(CE_Failure, CPLE_NotSupported,
243 : "Update from inline definition not supported");
244 1 : return FALSE;
245 : }
246 181 : pszGeoData_ = CPLStrdup(pszUnprefixed);
247 : }
248 355 : else if (eGeoJSONSourceFile == nSrcType)
249 : {
250 354 : if (poOpenInfo->eAccess == GA_Update &&
251 22 : !EQUAL(pszJSonFlavor, "GeoJSON"))
252 : {
253 0 : CPLError(CE_Failure, CPLE_NotSupported,
254 : "Update of %s not supported", pszJSonFlavor);
255 0 : return FALSE;
256 : }
257 354 : pszName_ = CPLStrdup(pszUnprefixed);
258 354 : bUpdatable_ = (poOpenInfo->eAccess == GA_Update);
259 :
260 354 : if (!EQUAL(pszUnprefixed, poOpenInfo->pszFilename))
261 : {
262 1 : GDALOpenInfo oOpenInfo(pszUnprefixed, GA_ReadOnly);
263 1 : if (oOpenInfo.fpL == nullptr || oOpenInfo.pabyHeader == nullptr)
264 0 : return FALSE;
265 1 : pszGeoData_ =
266 1 : CPLStrdup(reinterpret_cast<const char *>(oOpenInfo.pabyHeader));
267 : }
268 353 : else if (poOpenInfo->fpL == nullptr)
269 6 : return FALSE;
270 : else
271 : {
272 347 : pszGeoData_ = CPLStrdup(
273 347 : reinterpret_cast<const char *>(poOpenInfo->pabyHeader));
274 : }
275 : }
276 : else
277 : {
278 1 : Clear();
279 1 : return FALSE;
280 : }
281 :
282 : /* -------------------------------------------------------------------- */
283 : /* Construct OGR layer and feature objects from */
284 : /* GeoJSON text tree. */
285 : /* -------------------------------------------------------------------- */
286 533 : if (nullptr == pszGeoData_ ||
287 533 : STARTS_WITH(pszGeoData_, "{\"couchdb\":\"Welcome\"") ||
288 533 : STARTS_WITH(pszGeoData_, "{\"db_name\":\"") ||
289 533 : STARTS_WITH(pszGeoData_, "{\"total_rows\":") ||
290 533 : STARTS_WITH(pszGeoData_, "{\"rows\":["))
291 : {
292 0 : Clear();
293 0 : return FALSE;
294 : }
295 :
296 533 : SetDescription(poOpenInfo->pszFilename);
297 533 : LoadLayers(poOpenInfo, nSrcType, pszUnprefixed, pszJSonFlavor);
298 :
299 533 : if (!DealWithOgrSchemaOpenOption(poOpenInfo))
300 : {
301 3 : Clear();
302 3 : return FALSE;
303 : }
304 :
305 530 : if (nLayers_ == 0)
306 : {
307 33 : bool bEmitError = true;
308 33 : if (eGeoJSONSourceService == nSrcType)
309 : {
310 : const CPLString osTmpFilename =
311 : VSIMemGenerateHiddenFilename(CPLSPrintf(
312 0 : "geojson_%s", CPLGetFilename(poOpenInfo->pszFilename)));
313 0 : VSIFCloseL(VSIFileFromMemBuffer(osTmpFilename, (GByte *)pszGeoData_,
314 : nGeoDataLen_, TRUE));
315 0 : pszGeoData_ = nullptr;
316 0 : if (GDALIdentifyDriver(osTmpFilename, nullptr))
317 0 : bEmitError = false;
318 0 : VSIUnlink(osTmpFilename);
319 : }
320 33 : Clear();
321 :
322 33 : if (bEmitError)
323 : {
324 33 : CPLError(CE_Failure, CPLE_OpenFailed, "Failed to read %s data",
325 : pszJSonFlavor);
326 : }
327 33 : return FALSE;
328 : }
329 :
330 497 : return TRUE;
331 : }
332 :
333 : /************************************************************************/
334 : /* GetLayerCount() */
335 : /************************************************************************/
336 :
337 449 : int OGRGeoJSONDataSource::GetLayerCount()
338 : {
339 449 : return nLayers_;
340 : }
341 :
342 : /************************************************************************/
343 : /* GetLayer() */
344 : /************************************************************************/
345 :
346 592 : OGRLayer *OGRGeoJSONDataSource::GetLayer(int nLayer)
347 : {
348 592 : if (0 <= nLayer && nLayer < nLayers_)
349 : {
350 588 : if (papoLayers_)
351 587 : return papoLayers_[nLayer];
352 : else
353 1 : return papoLayersWriter_[nLayer];
354 : }
355 :
356 4 : return nullptr;
357 : }
358 :
359 : /************************************************************************/
360 : /* ICreateLayer() */
361 : /************************************************************************/
362 :
363 : OGRLayer *
364 179 : OGRGeoJSONDataSource::ICreateLayer(const char *pszNameIn,
365 : const OGRGeomFieldDefn *poSrcGeomFieldDefn,
366 : CSLConstList papszOptions)
367 : {
368 179 : if (nullptr == fpOut_)
369 : {
370 0 : CPLError(CE_Failure, CPLE_NotSupported,
371 : "GeoJSON driver doesn't support creating a layer "
372 : "on a read-only datasource");
373 0 : return nullptr;
374 : }
375 :
376 179 : if (nLayers_ != 0)
377 : {
378 16 : CPLError(CE_Failure, CPLE_NotSupported,
379 : "GeoJSON driver doesn't support creating more than one layer");
380 16 : return nullptr;
381 : }
382 :
383 : const auto eGType =
384 163 : poSrcGeomFieldDefn ? poSrcGeomFieldDefn->GetType() : wkbNone;
385 : const auto poSRS =
386 163 : poSrcGeomFieldDefn ? poSrcGeomFieldDefn->GetSpatialRef() : nullptr;
387 :
388 : const char *pszForeignMembersCollection =
389 163 : CSLFetchNameValue(papszOptions, "FOREIGN_MEMBERS_COLLECTION");
390 163 : if (pszForeignMembersCollection)
391 : {
392 4 : if (pszForeignMembersCollection[0] != '{' ||
393 3 : pszForeignMembersCollection[strlen(pszForeignMembersCollection) -
394 3 : 1] != '}')
395 : {
396 2 : CPLError(CE_Failure, CPLE_AppDefined,
397 : "Value of FOREIGN_MEMBERS_COLLECTION should start with { "
398 : "and end with }");
399 3 : return nullptr;
400 : }
401 2 : json_object *poTmp = nullptr;
402 2 : if (!OGRJSonParse(pszForeignMembersCollection, &poTmp, false))
403 : {
404 1 : pszForeignMembersCollection = nullptr;
405 : }
406 2 : json_object_put(poTmp);
407 2 : if (!pszForeignMembersCollection)
408 : {
409 1 : CPLError(CE_Failure, CPLE_AppDefined,
410 : "Value of FOREIGN_MEMBERS_COLLECTION is invalid JSON");
411 1 : return nullptr;
412 : }
413 : }
414 :
415 : std::string osForeignMembersFeature =
416 320 : CSLFetchNameValueDef(papszOptions, "FOREIGN_MEMBERS_FEATURE", "");
417 160 : if (!osForeignMembersFeature.empty())
418 : {
419 7 : if (osForeignMembersFeature.front() != '{' ||
420 3 : osForeignMembersFeature.back() != '}')
421 : {
422 2 : CPLError(CE_Failure, CPLE_AppDefined,
423 : "Value of FOREIGN_MEMBERS_FEATURE should start with { and "
424 : "end with }");
425 3 : return nullptr;
426 : }
427 2 : json_object *poTmp = nullptr;
428 2 : if (!OGRJSonParse(osForeignMembersFeature.c_str(), &poTmp, false))
429 : {
430 1 : osForeignMembersFeature.clear();
431 : }
432 2 : json_object_put(poTmp);
433 2 : if (osForeignMembersFeature.empty())
434 : {
435 1 : CPLError(CE_Failure, CPLE_AppDefined,
436 : "Value of FOREIGN_MEMBERS_FEATURE is invalid JSON");
437 1 : return nullptr;
438 : }
439 : }
440 :
441 157 : VSIFPrintfL(fpOut_, "{\n\"type\": \"FeatureCollection\",\n");
442 :
443 157 : if (pszForeignMembersCollection)
444 : {
445 1 : VSIFWriteL(pszForeignMembersCollection + 1, 1,
446 1 : strlen(pszForeignMembersCollection) - 2, fpOut_);
447 1 : VSIFWriteL(",\n", 2, 1, fpOut_);
448 : }
449 :
450 : bool bWriteFC_BBOX =
451 157 : CPLTestBool(CSLFetchNameValueDef(papszOptions, "WRITE_BBOX", "FALSE"));
452 :
453 : const bool bRFC7946 =
454 157 : CPLTestBool(CSLFetchNameValueDef(papszOptions, "RFC7946", "FALSE"));
455 :
456 157 : const char *pszNativeData = CSLFetchNameValue(papszOptions, "NATIVE_DATA");
457 : const char *pszNativeMediaType =
458 157 : CSLFetchNameValue(papszOptions, "NATIVE_MEDIA_TYPE");
459 157 : bool bWriteCRSIfWGS84 = true;
460 157 : bool bFoundNameInNativeData = false;
461 157 : if (pszNativeData && pszNativeMediaType &&
462 26 : EQUAL(pszNativeMediaType, "application/vnd.geo+json"))
463 : {
464 26 : json_object *poObj = nullptr;
465 52 : if (OGRJSonParse(pszNativeData, &poObj) &&
466 26 : json_object_get_type(poObj) == json_type_object)
467 : {
468 : json_object_iter it;
469 26 : it.key = nullptr;
470 26 : it.val = nullptr;
471 26 : it.entry = nullptr;
472 52 : CPLString osNativeData;
473 26 : bWriteCRSIfWGS84 = false;
474 69 : json_object_object_foreachC(poObj, it)
475 : {
476 43 : if (strcmp(it.key, "type") == 0 ||
477 42 : strcmp(it.key, "features") == 0)
478 : {
479 2 : continue;
480 : }
481 41 : if (strcmp(it.key, "bbox") == 0)
482 : {
483 3 : if (CSLFetchNameValue(papszOptions, "WRITE_BBOX") ==
484 : nullptr)
485 3 : bWriteFC_BBOX = true;
486 3 : continue;
487 : }
488 38 : if (strcmp(it.key, "crs") == 0)
489 : {
490 8 : if (!bRFC7946)
491 7 : bWriteCRSIfWGS84 = true;
492 8 : continue;
493 : }
494 : // See https://tools.ietf.org/html/rfc7946#section-7.1
495 30 : if (bRFC7946 && (strcmp(it.key, "coordinates") == 0 ||
496 4 : strcmp(it.key, "geometries") == 0 ||
497 3 : strcmp(it.key, "geometry") == 0 ||
498 2 : strcmp(it.key, "properties") == 0))
499 : {
500 4 : continue;
501 : }
502 :
503 26 : if (strcmp(it.key, "name") == 0)
504 : {
505 17 : bFoundNameInNativeData = true;
506 34 : if (!CPLFetchBool(papszOptions, "WRITE_NAME", true) ||
507 17 : CSLFetchNameValue(papszOptions, "@NAME") != nullptr)
508 : {
509 0 : continue;
510 : }
511 : }
512 :
513 : // If a native description exists, ignore it if an explicit
514 : // DESCRIPTION option has been provided.
515 26 : if (strcmp(it.key, "description") == 0 &&
516 0 : CSLFetchNameValue(papszOptions, "DESCRIPTION"))
517 : {
518 0 : continue;
519 : }
520 :
521 26 : if (strcmp(it.key, "xy_coordinate_resolution") == 0 ||
522 25 : strcmp(it.key, "z_coordinate_resolution") == 0)
523 : {
524 2 : continue;
525 : }
526 :
527 24 : json_object *poKey = json_object_new_string(it.key);
528 24 : VSIFPrintfL(fpOut_, "%s: ", json_object_to_json_string(poKey));
529 24 : json_object_put(poKey);
530 24 : VSIFPrintfL(fpOut_, "%s,\n",
531 : json_object_to_json_string(it.val));
532 : }
533 26 : json_object_put(poObj);
534 : }
535 : }
536 :
537 : // Used by ogr2ogr in -nln mode
538 157 : const char *pszAtName = CSLFetchNameValue(papszOptions, "@NAME");
539 157 : if (pszAtName && CPLFetchBool(papszOptions, "WRITE_NAME", true))
540 : {
541 1 : json_object *poName = json_object_new_string(pszAtName);
542 1 : VSIFPrintfL(fpOut_, "\"name\": %s,\n",
543 : json_object_to_json_string(poName));
544 1 : json_object_put(poName);
545 : }
546 451 : else if (!bFoundNameInNativeData &&
547 139 : CPLFetchBool(papszOptions, "WRITE_NAME", true) &&
548 406 : !EQUAL(pszNameIn, OGRGeoJSONLayer::DefaultName) &&
549 111 : !EQUAL(pszNameIn, ""))
550 : {
551 111 : json_object *poName = json_object_new_string(pszNameIn);
552 111 : VSIFPrintfL(fpOut_, "\"name\": %s,\n",
553 : json_object_to_json_string(poName));
554 111 : json_object_put(poName);
555 : }
556 :
557 157 : const char *pszDescription = CSLFetchNameValue(papszOptions, "DESCRIPTION");
558 157 : if (pszDescription)
559 : {
560 1 : json_object *poDesc = json_object_new_string(pszDescription);
561 1 : VSIFPrintfL(fpOut_, "\"description\": %s,\n",
562 : json_object_to_json_string(poDesc));
563 1 : json_object_put(poDesc);
564 : }
565 :
566 157 : OGRCoordinateTransformation *poCT = nullptr;
567 157 : if (bRFC7946)
568 : {
569 23 : if (poSRS == nullptr)
570 : {
571 0 : CPLError(CE_Warning, CPLE_AppDefined,
572 : "No SRS set on layer. Assuming it is long/lat on WGS84 "
573 : "ellipsoid");
574 : }
575 23 : else if (poSRS->GetAxesCount() == 3)
576 : {
577 2 : OGRSpatialReference oSRS_EPSG_4979;
578 2 : oSRS_EPSG_4979.importFromEPSG(4979);
579 2 : oSRS_EPSG_4979.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
580 2 : if (!poSRS->IsSame(&oSRS_EPSG_4979))
581 : {
582 : poCT =
583 2 : OGRCreateCoordinateTransformation(poSRS, &oSRS_EPSG_4979);
584 2 : if (poCT == nullptr)
585 : {
586 0 : CPLError(CE_Warning, CPLE_AppDefined,
587 : "Failed to create coordinate transformation "
588 : "between the "
589 : "input coordinate system and WGS84.");
590 :
591 0 : return nullptr;
592 : }
593 : }
594 : }
595 : else
596 : {
597 21 : OGRSpatialReference oSRSWGS84;
598 21 : oSRSWGS84.SetWellKnownGeogCS("WGS84");
599 21 : oSRSWGS84.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
600 21 : if (!poSRS->IsSame(&oSRSWGS84))
601 : {
602 9 : poCT = OGRCreateCoordinateTransformation(poSRS, &oSRSWGS84);
603 9 : if (poCT == nullptr)
604 : {
605 0 : CPLError(CE_Warning, CPLE_AppDefined,
606 : "Failed to create coordinate transformation "
607 : "between the "
608 : "input coordinate system and WGS84.");
609 :
610 0 : return nullptr;
611 : }
612 : }
613 : }
614 : }
615 134 : else if (poSRS)
616 : {
617 56 : char *pszOGCURN = poSRS->GetOGCURN();
618 56 : if (pszOGCURN != nullptr &&
619 17 : (bWriteCRSIfWGS84 ||
620 17 : !EQUAL(pszOGCURN, "urn:ogc:def:crs:EPSG::4326")))
621 : {
622 40 : json_object *poObjCRS = json_object_new_object();
623 40 : json_object_object_add(poObjCRS, "type",
624 : json_object_new_string("name"));
625 40 : json_object *poObjProperties = json_object_new_object();
626 40 : json_object_object_add(poObjCRS, "properties", poObjProperties);
627 :
628 40 : if (EQUAL(pszOGCURN, "urn:ogc:def:crs:EPSG::4326"))
629 : {
630 12 : json_object_object_add(
631 : poObjProperties, "name",
632 : json_object_new_string("urn:ogc:def:crs:OGC:1.3:CRS84"));
633 : }
634 : else
635 : {
636 28 : json_object_object_add(poObjProperties, "name",
637 : json_object_new_string(pszOGCURN));
638 : }
639 :
640 40 : const char *pszCRS = json_object_to_json_string(poObjCRS);
641 40 : VSIFPrintfL(fpOut_, "\"crs\": %s,\n", pszCRS);
642 :
643 40 : json_object_put(poObjCRS);
644 : }
645 56 : CPLFree(pszOGCURN);
646 : }
647 :
648 157 : CPLStringList aosOptions(papszOptions);
649 :
650 157 : double dfXYResolution = OGRGeomCoordinatePrecision::UNKNOWN;
651 157 : double dfZResolution = OGRGeomCoordinatePrecision::UNKNOWN;
652 :
653 157 : if (const char *pszCoordPrecision =
654 157 : CSLFetchNameValue(papszOptions, "COORDINATE_PRECISION"))
655 : {
656 3 : dfXYResolution = std::pow(10.0, -CPLAtof(pszCoordPrecision));
657 3 : dfZResolution = dfXYResolution;
658 3 : VSIFPrintfL(fpOut_, "\"xy_coordinate_resolution\": %g,\n",
659 : dfXYResolution);
660 3 : if (poSRS && poSRS->GetAxesCount() == 3)
661 : {
662 0 : VSIFPrintfL(fpOut_, "\"z_coordinate_resolution\": %g,\n",
663 : dfZResolution);
664 : }
665 : }
666 154 : else if (poSrcGeomFieldDefn)
667 : {
668 150 : const auto &oCoordPrec = poSrcGeomFieldDefn->GetCoordinatePrecision();
669 300 : OGRSpatialReference oSRSWGS84;
670 150 : oSRSWGS84.SetWellKnownGeogCS("WGS84");
671 : const auto oCoordPrecWGS84 =
672 300 : oCoordPrec.ConvertToOtherSRS(poSRS, &oSRSWGS84);
673 :
674 150 : if (oCoordPrec.dfXYResolution != OGRGeomCoordinatePrecision::UNKNOWN)
675 : {
676 3 : dfXYResolution = poSRS && bRFC7946 ? oCoordPrecWGS84.dfXYResolution
677 : : oCoordPrec.dfXYResolution;
678 :
679 : aosOptions.SetNameValue(
680 : "XY_COORD_PRECISION",
681 : CPLSPrintf("%d",
682 : OGRGeomCoordinatePrecision::ResolutionToPrecision(
683 3 : dfXYResolution)));
684 3 : VSIFPrintfL(fpOut_, "\"xy_coordinate_resolution\": %g,\n",
685 : dfXYResolution);
686 : }
687 150 : if (oCoordPrec.dfZResolution != OGRGeomCoordinatePrecision::UNKNOWN)
688 : {
689 3 : dfZResolution = poSRS && bRFC7946 ? oCoordPrecWGS84.dfZResolution
690 : : oCoordPrec.dfZResolution;
691 :
692 : aosOptions.SetNameValue(
693 : "Z_COORD_PRECISION",
694 : CPLSPrintf("%d",
695 : OGRGeomCoordinatePrecision::ResolutionToPrecision(
696 3 : dfZResolution)));
697 3 : VSIFPrintfL(fpOut_, "\"z_coordinate_resolution\": %g,\n",
698 : dfZResolution);
699 : }
700 : }
701 :
702 157 : if (bFpOutputIsSeekable_ && bWriteFC_BBOX)
703 : {
704 23 : nBBOXInsertLocation_ = static_cast<int>(VSIFTellL(fpOut_));
705 :
706 46 : const std::string osSpaceForBBOX(SPACE_FOR_BBOX + 1, ' ');
707 23 : VSIFPrintfL(fpOut_, "%s\n", osSpaceForBBOX.c_str());
708 : }
709 :
710 157 : VSIFPrintfL(fpOut_, "\"features\": [\n");
711 :
712 : OGRGeoJSONWriteLayer *poLayer = new OGRGeoJSONWriteLayer(
713 157 : pszNameIn, eGType, aosOptions.List(), bWriteFC_BBOX, poCT, this);
714 :
715 157 : if (eGType != wkbNone &&
716 : dfXYResolution != OGRGeomCoordinatePrecision::UNKNOWN)
717 : {
718 6 : auto poGeomFieldDefn = poLayer->GetLayerDefn()->GetGeomFieldDefn(0);
719 : OGRGeomCoordinatePrecision oCoordPrec(
720 12 : poGeomFieldDefn->GetCoordinatePrecision());
721 6 : oCoordPrec.dfXYResolution = dfXYResolution;
722 6 : poGeomFieldDefn->SetCoordinatePrecision(oCoordPrec);
723 : }
724 :
725 157 : if (eGType != wkbNone &&
726 : dfZResolution != OGRGeomCoordinatePrecision::UNKNOWN)
727 : {
728 6 : auto poGeomFieldDefn = poLayer->GetLayerDefn()->GetGeomFieldDefn(0);
729 : OGRGeomCoordinatePrecision oCoordPrec(
730 12 : poGeomFieldDefn->GetCoordinatePrecision());
731 6 : oCoordPrec.dfZResolution = dfZResolution;
732 6 : poGeomFieldDefn->SetCoordinatePrecision(oCoordPrec);
733 : }
734 :
735 : /* -------------------------------------------------------------------- */
736 : /* Add layer to data source layer list. */
737 : /* -------------------------------------------------------------------- */
738 157 : CPLAssert(papoLayers_ == nullptr);
739 314 : papoLayersWriter_ = static_cast<OGRGeoJSONWriteLayer **>(CPLRealloc(
740 157 : papoLayers_, sizeof(OGRGeoJSONWriteLayer *) * (nLayers_ + 1)));
741 :
742 157 : papoLayersWriter_[nLayers_++] = poLayer;
743 :
744 157 : return poLayer;
745 : }
746 :
747 : /************************************************************************/
748 : /* TestCapability() */
749 : /************************************************************************/
750 :
751 342 : int OGRGeoJSONDataSource::TestCapability(const char *pszCap)
752 : {
753 342 : if (EQUAL(pszCap, ODsCCreateLayer))
754 100 : return fpOut_ != nullptr && nLayers_ == 0;
755 242 : else if (EQUAL(pszCap, ODsCMeasuredGeometries))
756 2 : return m_bSupportsMGeometries;
757 240 : else if (EQUAL(pszCap, ODsCZGeometries))
758 4 : return m_bSupportsZGeometries;
759 :
760 236 : return FALSE;
761 : }
762 :
763 : /************************************************************************/
764 : /* Create() */
765 : /************************************************************************/
766 :
767 159 : int OGRGeoJSONDataSource::Create(const char *pszName,
768 : char ** /* papszOptions */)
769 : {
770 159 : CPLAssert(nullptr == fpOut_);
771 :
772 159 : if (strcmp(pszName, "/dev/stdout") == 0)
773 0 : pszName = "/vsistdout/";
774 :
775 317 : bFpOutputIsSeekable_ = !(strcmp(pszName, "/vsistdout/") == 0 ||
776 158 : STARTS_WITH(pszName, "/vsigzip/") ||
777 152 : STARTS_WITH(pszName, "/vsizip/"));
778 :
779 : /* -------------------------------------------------------------------- */
780 : /* File overwrite not supported. */
781 : /* -------------------------------------------------------------------- */
782 : VSIStatBufL sStatBuf;
783 159 : if (0 == VSIStatL(pszName, &sStatBuf))
784 : {
785 0 : CPLError(CE_Failure, CPLE_NotSupported,
786 : "The GeoJSON driver does not overwrite existing files.");
787 0 : return FALSE;
788 : }
789 :
790 : /* -------------------------------------------------------------------- */
791 : /* Create the output file. */
792 : /* -------------------------------------------------------------------- */
793 159 : fpOut_ = VSIFOpenExL(pszName, "w", true);
794 159 : if (nullptr == fpOut_)
795 : {
796 2 : CPLError(CE_Failure, CPLE_OpenFailed,
797 : "Failed to create GeoJSON datasource: %s: %s", pszName,
798 : VSIGetLastErrorMsg());
799 2 : return FALSE;
800 : }
801 :
802 157 : pszName_ = CPLStrdup(pszName);
803 :
804 157 : return TRUE;
805 : }
806 :
807 : /************************************************************************/
808 : /* SetGeometryTranslation() */
809 : /************************************************************************/
810 :
811 538 : void OGRGeoJSONDataSource::SetGeometryTranslation(GeometryTranslation type)
812 : {
813 538 : flTransGeom_ = type;
814 538 : }
815 :
816 : /************************************************************************/
817 : /* SetAttributesTranslation() */
818 : /************************************************************************/
819 :
820 538 : void OGRGeoJSONDataSource::SetAttributesTranslation(AttributesTranslation type)
821 : {
822 538 : flTransAttrs_ = type;
823 538 : }
824 :
825 : /************************************************************************/
826 : /* PRIVATE FUNCTIONS IMPLEMENTATION */
827 : /************************************************************************/
828 :
829 756 : bool OGRGeoJSONDataSource::Clear()
830 : {
831 1420 : for (int i = 0; i < nLayers_; i++)
832 : {
833 664 : if (papoLayers_ != nullptr)
834 507 : delete papoLayers_[i];
835 : else
836 157 : delete papoLayersWriter_[i];
837 : }
838 :
839 756 : CPLFree(papoLayers_);
840 756 : papoLayers_ = nullptr;
841 756 : CPLFree(papoLayersWriter_);
842 756 : papoLayersWriter_ = nullptr;
843 756 : nLayers_ = 0;
844 :
845 756 : CPLFree(pszName_);
846 756 : pszName_ = nullptr;
847 :
848 756 : CPLFree(pszGeoData_);
849 756 : pszGeoData_ = nullptr;
850 756 : nGeoDataLen_ = 0;
851 :
852 756 : bool bRet = true;
853 756 : if (fpOut_)
854 : {
855 157 : if (VSIFCloseL(fpOut_) != 0)
856 0 : bRet = false;
857 157 : fpOut_ = nullptr;
858 : }
859 756 : return bRet;
860 : }
861 :
862 : /************************************************************************/
863 : /* ReadFromFile() */
864 : /************************************************************************/
865 :
866 66 : int OGRGeoJSONDataSource::ReadFromFile(GDALOpenInfo *poOpenInfo,
867 : const char *pszUnprefixed)
868 : {
869 66 : GByte *pabyOut = nullptr;
870 66 : if (!EQUAL(poOpenInfo->pszFilename, pszUnprefixed))
871 : {
872 1 : GDALOpenInfo oOpenInfo(pszUnprefixed, GA_ReadOnly);
873 1 : if (oOpenInfo.fpL == nullptr || oOpenInfo.pabyHeader == nullptr)
874 0 : return FALSE;
875 1 : VSIFSeekL(oOpenInfo.fpL, 0, SEEK_SET);
876 1 : if (!VSIIngestFile(oOpenInfo.fpL, pszUnprefixed, &pabyOut, nullptr, -1))
877 : {
878 0 : return FALSE;
879 : }
880 : }
881 : else
882 : {
883 65 : if (poOpenInfo->fpL == nullptr)
884 0 : return FALSE;
885 65 : VSIFSeekL(poOpenInfo->fpL, 0, SEEK_SET);
886 65 : if (!VSIIngestFile(poOpenInfo->fpL, poOpenInfo->pszFilename, &pabyOut,
887 : nullptr, -1))
888 : {
889 0 : return FALSE;
890 : }
891 :
892 65 : VSIFCloseL(poOpenInfo->fpL);
893 65 : poOpenInfo->fpL = nullptr;
894 : }
895 :
896 66 : CPLFree(pszGeoData_);
897 66 : pszGeoData_ = reinterpret_cast<char *>(pabyOut);
898 :
899 66 : CPLAssert(nullptr != pszGeoData_);
900 :
901 66 : return TRUE;
902 : }
903 :
904 : /************************************************************************/
905 : /* ReadFromService() */
906 : /************************************************************************/
907 :
908 23 : int OGRGeoJSONDataSource::ReadFromService(GDALOpenInfo *poOpenInfo,
909 : const char *pszSource)
910 : {
911 23 : CPLAssert(nullptr == pszGeoData_);
912 23 : CPLAssert(nullptr != pszSource);
913 :
914 23 : CPLErrorReset();
915 :
916 : /* -------------------------------------------------------------------- */
917 : /* Look if we already cached the content. */
918 : /* -------------------------------------------------------------------- */
919 23 : char *pszStoredContent = OGRGeoJSONDriverStealStoredContent(pszSource);
920 23 : if (pszStoredContent != nullptr)
921 : {
922 16 : if (!EQUAL(pszStoredContent, INVALID_CONTENT_FOR_JSON_LIKE) &&
923 0 : ((osJSonFlavor_ == "ESRIJSON" &&
924 0 : ESRIJSONIsObject(pszStoredContent, poOpenInfo)) ||
925 0 : (osJSonFlavor_ == "TopoJSON" &&
926 0 : TopoJSONIsObject(pszStoredContent, poOpenInfo))))
927 : {
928 0 : pszGeoData_ = pszStoredContent;
929 0 : nGeoDataLen_ = strlen(pszGeoData_);
930 :
931 0 : pszName_ = CPLStrdup(pszSource);
932 0 : return true;
933 : }
934 :
935 16 : OGRGeoJSONDriverStoreContent(pszSource, pszStoredContent);
936 16 : return false;
937 : }
938 :
939 : /* -------------------------------------------------------------------- */
940 : /* Fetch the GeoJSON result. */
941 : /* -------------------------------------------------------------------- */
942 7 : CPLHTTPResult *pResult = GeoJSONHTTPFetchWithContentTypeHeader(pszSource);
943 7 : if (!pResult)
944 : {
945 0 : return FALSE;
946 : }
947 :
948 : /* -------------------------------------------------------------------- */
949 : /* Copy returned GeoJSON data to text buffer. */
950 : /* -------------------------------------------------------------------- */
951 7 : char *pszData = reinterpret_cast<char *>(pResult->pabyData);
952 :
953 : // Directly assign CPLHTTPResult::pabyData to pszGeoData_.
954 7 : pszGeoData_ = pszData;
955 7 : nGeoDataLen_ = pResult->nDataLen;
956 7 : pResult->pabyData = nullptr;
957 7 : pResult->nDataLen = 0;
958 :
959 7 : pszName_ = CPLStrdup(pszSource);
960 :
961 : /* -------------------------------------------------------------------- */
962 : /* Cleanup HTTP resources. */
963 : /* -------------------------------------------------------------------- */
964 7 : CPLHTTPDestroyResult(pResult);
965 :
966 7 : CPLAssert(nullptr != pszGeoData_);
967 :
968 : /* -------------------------------------------------------------------- */
969 : /* Cache the content if it is not handled by this driver, but */
970 : /* another related one. */
971 : /* -------------------------------------------------------------------- */
972 7 : if (EQUAL(pszSource, poOpenInfo->pszFilename) && osJSonFlavor_ == "GeoJSON")
973 : {
974 7 : if (!GeoJSONIsObject(pszGeoData_, poOpenInfo))
975 : {
976 3 : if (ESRIJSONIsObject(pszGeoData_, poOpenInfo) ||
977 3 : TopoJSONIsObject(pszGeoData_, poOpenInfo) ||
978 9 : GeoJSONSeqIsObject(pszGeoData_, poOpenInfo) ||
979 3 : JSONFGIsObject(pszGeoData_, poOpenInfo))
980 : {
981 0 : OGRGeoJSONDriverStoreContent(pszSource, pszGeoData_);
982 0 : pszGeoData_ = nullptr;
983 0 : nGeoDataLen_ = 0;
984 : }
985 : else
986 : {
987 3 : OGRGeoJSONDriverStoreContent(
988 : pszSource, CPLStrdup(INVALID_CONTENT_FOR_JSON_LIKE));
989 : }
990 3 : return false;
991 : }
992 : }
993 :
994 4 : return TRUE;
995 : }
996 :
997 : /************************************************************************/
998 : /* RemoveJSonPStuff() */
999 : /************************************************************************/
1000 :
1001 227 : void OGRGeoJSONDataSource::RemoveJSonPStuff()
1002 : {
1003 227 : const char *const apszPrefix[] = {"loadGeoJSON(", "jsonp("};
1004 681 : for (size_t iP = 0; iP < CPL_ARRAYSIZE(apszPrefix); iP++)
1005 : {
1006 454 : if (strncmp(pszGeoData_, apszPrefix[iP], strlen(apszPrefix[iP])) == 0)
1007 : {
1008 2 : const size_t nDataLen = strlen(pszGeoData_);
1009 2 : memmove(pszGeoData_, pszGeoData_ + strlen(apszPrefix[iP]),
1010 2 : nDataLen - strlen(apszPrefix[iP]));
1011 2 : size_t i = nDataLen - strlen(apszPrefix[iP]);
1012 2 : pszGeoData_[i] = '\0';
1013 4 : while (i > 0 && pszGeoData_[i] != ')')
1014 : {
1015 2 : i--;
1016 : }
1017 2 : pszGeoData_[i] = '\0';
1018 : }
1019 : }
1020 227 : }
1021 :
1022 : /************************************************************************/
1023 : /* LoadLayers() */
1024 : /************************************************************************/
1025 :
1026 533 : void OGRGeoJSONDataSource::LoadLayers(GDALOpenInfo *poOpenInfo,
1027 : GeoJSONSourceType nSrcType,
1028 : const char *pszUnprefixed,
1029 : const char *pszJSonFlavor)
1030 : {
1031 533 : if (nullptr == pszGeoData_)
1032 : {
1033 0 : CPLError(CE_Failure, CPLE_ObjectNull, "%s data buffer empty",
1034 : pszJSonFlavor);
1035 0 : return;
1036 : }
1037 :
1038 533 : if (nSrcType != eGeoJSONSourceFile)
1039 : {
1040 185 : RemoveJSonPStuff();
1041 : }
1042 :
1043 : /* -------------------------------------------------------------------- */
1044 : /* Is it ESRI Feature Service data ? */
1045 : /* -------------------------------------------------------------------- */
1046 533 : if (EQUAL(pszJSonFlavor, "ESRIJSON"))
1047 : {
1048 42 : OGRESRIJSONReader reader;
1049 21 : if (nSrcType == eGeoJSONSourceFile)
1050 : {
1051 19 : if (!ReadFromFile(poOpenInfo, pszUnprefixed))
1052 0 : return;
1053 : }
1054 21 : OGRErr err = reader.Parse(pszGeoData_);
1055 21 : if (OGRERR_NONE == err)
1056 : {
1057 21 : json_object *poObj = reader.GetJSonObject();
1058 21 : CheckExceededTransferLimit(poObj);
1059 21 : reader.ReadLayers(this, nSrcType);
1060 : }
1061 21 : return;
1062 : }
1063 :
1064 : /* -------------------------------------------------------------------- */
1065 : /* Is it TopoJSON data ? */
1066 : /* -------------------------------------------------------------------- */
1067 512 : if (EQUAL(pszJSonFlavor, "TOPOJSON"))
1068 : {
1069 10 : OGRTopoJSONReader reader;
1070 5 : if (nSrcType == eGeoJSONSourceFile)
1071 : {
1072 5 : if (!ReadFromFile(poOpenInfo, pszUnprefixed))
1073 0 : return;
1074 : }
1075 10 : OGRErr err = reader.Parse(
1076 5 : pszGeoData_,
1077 5 : nSrcType == eGeoJSONSourceService &&
1078 0 : !STARTS_WITH_CI(poOpenInfo->pszFilename, "TopoJSON:"));
1079 5 : if (OGRERR_NONE == err)
1080 : {
1081 5 : reader.ReadLayers(this);
1082 : }
1083 5 : return;
1084 : }
1085 :
1086 507 : VSILFILE *fp = nullptr;
1087 507 : if (nSrcType == eGeoJSONSourceFile &&
1088 324 : !EQUAL(poOpenInfo->pszFilename, pszUnprefixed))
1089 : {
1090 0 : GDALOpenInfo oOpenInfo(pszUnprefixed, GA_ReadOnly);
1091 0 : if (oOpenInfo.fpL == nullptr || oOpenInfo.pabyHeader == nullptr)
1092 0 : return;
1093 0 : CPL_IGNORE_RET_VAL(oOpenInfo.TryToIngest(6000));
1094 0 : CPLFree(pszGeoData_);
1095 0 : pszGeoData_ =
1096 0 : CPLStrdup(reinterpret_cast<const char *>(oOpenInfo.pabyHeader));
1097 0 : fp = oOpenInfo.fpL;
1098 0 : oOpenInfo.fpL = nullptr;
1099 : }
1100 :
1101 507 : if (!GeoJSONIsObject(pszGeoData_, poOpenInfo))
1102 : {
1103 0 : CPLDebug(pszJSonFlavor, "No valid %s data found in source '%s'",
1104 : pszJSonFlavor, pszName_);
1105 0 : if (fp)
1106 0 : VSIFCloseL(fp);
1107 0 : return;
1108 : }
1109 :
1110 : /* -------------------------------------------------------------------- */
1111 : /* Configure GeoJSON format translator. */
1112 : /* -------------------------------------------------------------------- */
1113 507 : OGRGeoJSONReader *poReader = new OGRGeoJSONReader();
1114 507 : SetOptionsOnReader(poOpenInfo, poReader);
1115 :
1116 : /* -------------------------------------------------------------------- */
1117 : /* Parse GeoJSON and build valid OGRLayer instance. */
1118 : /* -------------------------------------------------------------------- */
1119 507 : bool bUseStreamingInterface = false;
1120 507 : const GIntBig nMaxBytesFirstPass = CPLAtoGIntBig(
1121 : CPLGetConfigOption("OGR_GEOJSON_MAX_BYTES_FIRST_PASS", "0"));
1122 507 : if ((fp != nullptr || poOpenInfo->fpL != nullptr) &&
1123 324 : (!STARTS_WITH(pszUnprefixed, "/vsistdin/") ||
1124 0 : (nMaxBytesFirstPass > 0 && nMaxBytesFirstPass <= 1000000)))
1125 : {
1126 324 : const char *pszStr = strstr(pszGeoData_, "\"features\"");
1127 324 : if (pszStr)
1128 : {
1129 283 : pszStr += strlen("\"features\"");
1130 306 : while (*pszStr && isspace(static_cast<unsigned char>(*pszStr)))
1131 23 : pszStr++;
1132 283 : if (*pszStr == ':')
1133 : {
1134 283 : pszStr++;
1135 640 : while (*pszStr && isspace(static_cast<unsigned char>(*pszStr)))
1136 357 : pszStr++;
1137 283 : if (*pszStr == '[')
1138 : {
1139 283 : bUseStreamingInterface = true;
1140 : }
1141 : }
1142 : }
1143 : }
1144 :
1145 507 : if (bUseStreamingInterface)
1146 : {
1147 283 : bool bTryStandardReading = false;
1148 283 : if (poReader->FirstPassReadLayer(this, fp ? fp : poOpenInfo->fpL,
1149 : bTryStandardReading))
1150 : {
1151 280 : if (fp)
1152 0 : fp = nullptr;
1153 : else
1154 280 : poOpenInfo->fpL = nullptr;
1155 280 : CheckExceededTransferLimit(poReader->GetJSonObject());
1156 : }
1157 : else
1158 : {
1159 3 : delete poReader;
1160 : }
1161 283 : if (!bTryStandardReading)
1162 : {
1163 282 : if (fp)
1164 0 : VSIFCloseL(fp);
1165 282 : return;
1166 : }
1167 :
1168 1 : poReader = new OGRGeoJSONReader();
1169 1 : SetOptionsOnReader(poOpenInfo, poReader);
1170 : }
1171 :
1172 225 : if (fp)
1173 0 : VSIFCloseL(fp);
1174 225 : if (nSrcType == eGeoJSONSourceFile)
1175 : {
1176 42 : if (!ReadFromFile(poOpenInfo, pszUnprefixed))
1177 : {
1178 0 : delete poReader;
1179 0 : return;
1180 : }
1181 42 : RemoveJSonPStuff();
1182 : }
1183 225 : const OGRErr err = poReader->Parse(pszGeoData_);
1184 225 : if (OGRERR_NONE == err)
1185 : {
1186 225 : CheckExceededTransferLimit(poReader->GetJSonObject());
1187 : }
1188 :
1189 225 : poReader->ReadLayers(this);
1190 225 : delete poReader;
1191 : }
1192 :
1193 : /************************************************************************/
1194 : /* SetOptionsOnReader() */
1195 : /************************************************************************/
1196 :
1197 508 : void OGRGeoJSONDataSource::SetOptionsOnReader(GDALOpenInfo *poOpenInfo,
1198 : OGRGeoJSONReader *poReader)
1199 : {
1200 508 : if (eGeometryAsCollection == flTransGeom_)
1201 : {
1202 0 : poReader->SetPreserveGeometryType(false);
1203 0 : CPLDebug("GeoJSON", "Geometry as OGRGeometryCollection type.");
1204 : }
1205 :
1206 508 : if (eAttributesSkip == flTransAttrs_)
1207 : {
1208 0 : poReader->SetSkipAttributes(true);
1209 0 : CPLDebug("GeoJSON", "Skip all attributes.");
1210 : }
1211 :
1212 1524 : poReader->SetFlattenNestedAttributes(
1213 508 : CPLFetchBool(poOpenInfo->papszOpenOptions, "FLATTEN_NESTED_ATTRIBUTES",
1214 : false),
1215 508 : CSLFetchNameValueDef(poOpenInfo->papszOpenOptions,
1216 508 : "NESTED_ATTRIBUTE_SEPARATOR", "_")[0]);
1217 :
1218 508 : const bool bDefaultNativeData = bUpdatable_;
1219 508 : poReader->SetStoreNativeData(CPLFetchBool(
1220 508 : poOpenInfo->papszOpenOptions, "NATIVE_DATA", bDefaultNativeData));
1221 :
1222 1016 : poReader->SetArrayAsString(CPLTestBool(CSLFetchNameValueDef(
1223 508 : poOpenInfo->papszOpenOptions, "ARRAY_AS_STRING",
1224 : CPLGetConfigOption("OGR_GEOJSON_ARRAY_AS_STRING", "NO"))));
1225 :
1226 1016 : poReader->SetDateAsString(CPLTestBool(CSLFetchNameValueDef(
1227 508 : poOpenInfo->papszOpenOptions, "DATE_AS_STRING",
1228 : CPLGetConfigOption("OGR_GEOJSON_DATE_AS_STRING", "NO"))));
1229 :
1230 1016 : const char *pszForeignMembers = CSLFetchNameValueDef(
1231 508 : poOpenInfo->papszOpenOptions, "FOREIGN_MEMBERS", "AUTO");
1232 508 : if (EQUAL(pszForeignMembers, "AUTO"))
1233 : {
1234 504 : poReader->SetForeignMemberProcessing(
1235 : OGRGeoJSONBaseReader::ForeignMemberProcessing::AUTO);
1236 : }
1237 4 : else if (EQUAL(pszForeignMembers, "ALL"))
1238 : {
1239 1 : poReader->SetForeignMemberProcessing(
1240 : OGRGeoJSONBaseReader::ForeignMemberProcessing::ALL);
1241 : }
1242 3 : else if (EQUAL(pszForeignMembers, "NONE"))
1243 : {
1244 2 : poReader->SetForeignMemberProcessing(
1245 : OGRGeoJSONBaseReader::ForeignMemberProcessing::NONE);
1246 : }
1247 1 : else if (EQUAL(pszForeignMembers, "STAC"))
1248 : {
1249 1 : poReader->SetForeignMemberProcessing(
1250 : OGRGeoJSONBaseReader::ForeignMemberProcessing::STAC);
1251 : }
1252 508 : }
1253 :
1254 : /************************************************************************/
1255 : /* CheckExceededTransferLimit() */
1256 : /************************************************************************/
1257 :
1258 526 : void OGRGeoJSONDataSource::CheckExceededTransferLimit(json_object *poObj)
1259 : {
1260 1560 : for (int i = 0; i < 2; i++)
1261 : {
1262 1050 : if (i == 1)
1263 : {
1264 524 : if (poObj && json_object_get_type(poObj) == json_type_object)
1265 : {
1266 524 : poObj = CPL_json_object_object_get(poObj, "properties");
1267 : }
1268 : }
1269 1050 : if (poObj && json_object_get_type(poObj) == json_type_object)
1270 : {
1271 : json_object *poExceededTransferLimit =
1272 566 : CPL_json_object_object_get(poObj, "exceededTransferLimit");
1273 582 : if (poExceededTransferLimit &&
1274 16 : json_object_get_type(poExceededTransferLimit) ==
1275 : json_type_boolean)
1276 : {
1277 16 : bOtherPages_ = CPL_TO_BOOL(
1278 : json_object_get_boolean(poExceededTransferLimit));
1279 16 : return;
1280 : }
1281 : }
1282 : }
1283 : }
1284 :
1285 : /************************************************************************/
1286 : /* AddLayer() */
1287 : /************************************************************************/
1288 :
1289 507 : void OGRGeoJSONDataSource::AddLayer(OGRGeoJSONLayer *poLayer)
1290 : {
1291 507 : CPLAssert(papoLayersWriter_ == nullptr);
1292 :
1293 : // Return layer in readable state.
1294 507 : poLayer->ResetReading();
1295 :
1296 507 : papoLayers_ = static_cast<OGRGeoJSONLayer **>(
1297 507 : CPLRealloc(papoLayers_, sizeof(OGRGeoJSONLayer *) * (nLayers_ + 1)));
1298 507 : papoLayers_[nLayers_] = poLayer;
1299 507 : nLayers_++;
1300 507 : }
1301 :
1302 : /************************************************************************/
1303 : /* FlushCache() */
1304 : /************************************************************************/
1305 :
1306 801 : CPLErr OGRGeoJSONDataSource::FlushCache(bool /*bAtClosing*/)
1307 : {
1308 801 : if (papoLayersWriter_ != nullptr)
1309 : {
1310 236 : return papoLayersWriter_[0]->SyncToDisk() == OGRERR_NONE ? CE_None
1311 236 : : CE_Failure;
1312 : }
1313 :
1314 565 : CPLErr eErr = CE_None;
1315 1072 : for (int i = 0; i < nLayers_; i++)
1316 : {
1317 507 : if (papoLayers_[i]->HasBeenUpdated())
1318 : {
1319 15 : papoLayers_[i]->SetUpdated(false);
1320 :
1321 15 : bool bOK = false;
1322 :
1323 : // Disable all filters.
1324 15 : OGRFeatureQuery *poAttrQueryBak = papoLayers_[i]->m_poAttrQuery;
1325 15 : papoLayers_[i]->m_poAttrQuery = nullptr;
1326 15 : OGRGeometry *poFilterGeomBak = papoLayers_[i]->m_poFilterGeom;
1327 15 : papoLayers_[i]->m_poFilterGeom = nullptr;
1328 :
1329 : // If the source data only contained one single feature and
1330 : // that's still the case, then do not use a FeatureCollection
1331 : // on writing.
1332 15 : bool bAlreadyDone = false;
1333 23 : if (papoLayers_[i]->GetFeatureCount(TRUE) == 1 &&
1334 8 : papoLayers_[i]->GetMetadata("NATIVE_DATA") == nullptr)
1335 : {
1336 1 : papoLayers_[i]->ResetReading();
1337 1 : OGRFeature *poFeature = papoLayers_[i]->GetNextFeature();
1338 1 : if (poFeature != nullptr)
1339 : {
1340 1 : if (poFeature->GetNativeData() != nullptr)
1341 : {
1342 1 : bAlreadyDone = true;
1343 2 : OGRGeoJSONWriteOptions oOptions;
1344 : json_object *poObj =
1345 1 : OGRGeoJSONWriteFeature(poFeature, oOptions);
1346 1 : VSILFILE *fp = VSIFOpenL(pszName_, "wb");
1347 1 : if (fp != nullptr)
1348 : {
1349 1 : bOK = VSIFPrintfL(
1350 : fp, "%s",
1351 : json_object_to_json_string(poObj)) > 0;
1352 1 : VSIFCloseL(fp);
1353 : }
1354 1 : json_object_put(poObj);
1355 : }
1356 1 : delete poFeature;
1357 : }
1358 : }
1359 :
1360 : // Otherwise do layer translation.
1361 15 : if (!bAlreadyDone)
1362 : {
1363 14 : char **papszOptions = CSLAddString(nullptr, "-f");
1364 14 : papszOptions = CSLAddString(papszOptions, "GeoJSON");
1365 : GDALVectorTranslateOptions *psOptions =
1366 14 : GDALVectorTranslateOptionsNew(papszOptions, nullptr);
1367 14 : CSLDestroy(papszOptions);
1368 14 : GDALDatasetH hSrcDS = this;
1369 28 : CPLString osNewFilename(pszName_);
1370 14 : osNewFilename += ".tmp";
1371 14 : GDALDatasetH hOutDS = GDALVectorTranslate(
1372 : osNewFilename, nullptr, 1, &hSrcDS, psOptions, nullptr);
1373 14 : GDALVectorTranslateOptionsFree(psOptions);
1374 :
1375 14 : if (hOutDS != nullptr)
1376 : {
1377 14 : CPLErrorReset();
1378 14 : GDALClose(hOutDS);
1379 14 : bOK = (CPLGetLastErrorType() == CE_None);
1380 : }
1381 14 : if (bOK)
1382 : {
1383 14 : const bool bOverwrite = CPLTestBool(
1384 : CPLGetConfigOption("OGR_GEOJSON_REWRITE_IN_PLACE",
1385 : #ifdef _WIN32
1386 : "YES"
1387 : #else
1388 : "NO"
1389 : #endif
1390 : ));
1391 14 : if (bOverwrite)
1392 : {
1393 1 : VSILFILE *fpTarget = nullptr;
1394 1 : for (int attempt = 0; attempt < 10; attempt++)
1395 : {
1396 1 : fpTarget = VSIFOpenL(pszName_, "rb+");
1397 1 : if (fpTarget)
1398 1 : break;
1399 0 : CPLSleep(0.1);
1400 : }
1401 1 : if (!fpTarget)
1402 : {
1403 0 : CPLError(CE_Failure, CPLE_AppDefined,
1404 : "Cannot rewrite %s", pszName_);
1405 : }
1406 : else
1407 : {
1408 1 : bool bCopyOK = CPL_TO_BOOL(
1409 : VSIOverwriteFile(fpTarget, osNewFilename));
1410 1 : if (VSIFCloseL(fpTarget) != 0)
1411 0 : bCopyOK = false;
1412 1 : if (bCopyOK)
1413 : {
1414 1 : VSIUnlink(osNewFilename);
1415 : }
1416 : else
1417 : {
1418 0 : CPLError(CE_Failure, CPLE_AppDefined,
1419 : "Cannot rewrite %s with content of %s",
1420 : pszName_, osNewFilename.c_str());
1421 : }
1422 : }
1423 : }
1424 : else
1425 : {
1426 26 : CPLString osBackup(pszName_);
1427 13 : osBackup += ".bak";
1428 13 : if (VSIRename(pszName_, osBackup) < 0)
1429 : {
1430 0 : CPLError(CE_Failure, CPLE_AppDefined,
1431 : "Cannot create backup copy");
1432 : }
1433 13 : else if (VSIRename(osNewFilename, pszName_) < 0)
1434 : {
1435 0 : CPLError(CE_Failure, CPLE_AppDefined,
1436 : "Cannot rename %s to %s",
1437 : osNewFilename.c_str(), pszName_);
1438 : }
1439 : else
1440 : {
1441 13 : VSIUnlink(osBackup);
1442 : }
1443 : }
1444 : }
1445 : }
1446 15 : if (!bOK)
1447 0 : eErr = CE_Failure;
1448 :
1449 : // Restore filters.
1450 15 : papoLayers_[i]->m_poAttrQuery = poAttrQueryBak;
1451 15 : papoLayers_[i]->m_poFilterGeom = poFilterGeomBak;
1452 : }
1453 : }
1454 565 : return eErr;
1455 : }
|