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 665 : 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 665 : bUpdatable_(false)
58 : {
59 665 : }
60 :
61 : /************************************************************************/
62 : /* ~OGRGeoJSONDataSource() */
63 : /************************************************************************/
64 :
65 1330 : OGRGeoJSONDataSource::~OGRGeoJSONDataSource()
66 : {
67 665 : OGRGeoJSONDataSource::Close();
68 1330 : }
69 :
70 : /************************************************************************/
71 : /* Close() */
72 : /************************************************************************/
73 :
74 1180 : CPLErr OGRGeoJSONDataSource::Close()
75 : {
76 1180 : CPLErr eErr = CE_None;
77 1180 : if (nOpenFlags != OPEN_FLAGS_CLOSED)
78 : {
79 665 : if (OGRGeoJSONDataSource::FlushCache(true) != CE_None)
80 0 : eErr = CE_Failure;
81 :
82 665 : if (!OGRGeoJSONDataSource::Clear())
83 0 : eErr = CE_Failure;
84 :
85 665 : if (GDALDataset::Close() != CE_None)
86 0 : eErr = CE_Failure;
87 : }
88 1180 : return eErr;
89 : }
90 :
91 : /************************************************************************/
92 : /* DealWithOgrSchemaOpenOption() */
93 : /************************************************************************/
94 :
95 480 : bool OGRGeoJSONDataSource::DealWithOgrSchemaOpenOption(
96 : const GDALOpenInfo *poOpenInfo)
97 : {
98 :
99 : std::string osFieldsSchemaOverrideParam =
100 960 : CSLFetchNameValueDef(poOpenInfo->papszOpenOptions, "OGR_SCHEMA", "");
101 :
102 480 : 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 477 : return true;
208 : }
209 :
210 : /************************************************************************/
211 : /* Open() */
212 : /************************************************************************/
213 :
214 507 : int OGRGeoJSONDataSource::Open(GDALOpenInfo *poOpenInfo,
215 : GeoJSONSourceType nSrcType,
216 : const char *pszJSonFlavor)
217 : {
218 507 : osJSonFlavor_ = pszJSonFlavor;
219 :
220 507 : const char *pszUnprefixed = poOpenInfo->pszFilename;
221 507 : if (STARTS_WITH_CI(pszUnprefixed, pszJSonFlavor) &&
222 1 : pszUnprefixed[strlen(pszJSonFlavor)] == ':')
223 : {
224 1 : pszUnprefixed += strlen(pszJSonFlavor) + 1;
225 : }
226 :
227 507 : 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 484 : else if (eGeoJSONSourceText == nSrcType)
239 : {
240 139 : 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 138 : pszGeoData_ = CPLStrdup(pszUnprefixed);
247 : }
248 345 : else if (eGeoJSONSourceFile == nSrcType)
249 : {
250 344 : 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 344 : pszName_ = CPLStrdup(pszUnprefixed);
258 344 : bUpdatable_ = (poOpenInfo->eAccess == GA_Update);
259 :
260 344 : 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 343 : else if (poOpenInfo->fpL == nullptr)
269 6 : return FALSE;
270 : else
271 : {
272 337 : pszGeoData_ = CPLStrdup(
273 337 : 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 480 : if (nullptr == pszGeoData_ ||
287 480 : STARTS_WITH(pszGeoData_, "{\"couchdb\":\"Welcome\"") ||
288 480 : STARTS_WITH(pszGeoData_, "{\"db_name\":\"") ||
289 480 : STARTS_WITH(pszGeoData_, "{\"total_rows\":") ||
290 480 : STARTS_WITH(pszGeoData_, "{\"rows\":["))
291 : {
292 0 : Clear();
293 0 : return FALSE;
294 : }
295 :
296 480 : SetDescription(poOpenInfo->pszFilename);
297 480 : LoadLayers(poOpenInfo, nSrcType, pszUnprefixed, pszJSonFlavor);
298 :
299 480 : if (!DealWithOgrSchemaOpenOption(poOpenInfo))
300 : {
301 3 : Clear();
302 3 : return FALSE;
303 : }
304 :
305 477 : if (nLayers_ == 0)
306 : {
307 4 : bool bEmitError = true;
308 4 : 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 4 : Clear();
321 :
322 4 : if (bEmitError)
323 : {
324 4 : CPLError(CE_Failure, CPLE_OpenFailed, "Failed to read %s data",
325 : pszJSonFlavor);
326 : }
327 4 : return FALSE;
328 : }
329 :
330 473 : return TRUE;
331 : }
332 :
333 : /************************************************************************/
334 : /* GetLayerCount() */
335 : /************************************************************************/
336 :
337 444 : int OGRGeoJSONDataSource::GetLayerCount()
338 : {
339 444 : return nLayers_;
340 : }
341 :
342 : /************************************************************************/
343 : /* GetLayer() */
344 : /************************************************************************/
345 :
346 576 : OGRLayer *OGRGeoJSONDataSource::GetLayer(int nLayer)
347 : {
348 576 : if (0 <= nLayer && nLayer < nLayers_)
349 : {
350 572 : if (papoLayers_)
351 571 : 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 178 : OGRGeoJSONDataSource::ICreateLayer(const char *pszNameIn,
365 : const OGRGeomFieldDefn *poSrcGeomFieldDefn,
366 : CSLConstList papszOptions)
367 : {
368 178 : 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 178 : 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 162 : poSrcGeomFieldDefn ? poSrcGeomFieldDefn->GetType() : wkbNone;
385 : const auto poSRS =
386 162 : poSrcGeomFieldDefn ? poSrcGeomFieldDefn->GetSpatialRef() : nullptr;
387 :
388 : const char *pszForeignMembersCollection =
389 162 : CSLFetchNameValue(papszOptions, "FOREIGN_MEMBERS_COLLECTION");
390 162 : 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 318 : CSLFetchNameValueDef(papszOptions, "FOREIGN_MEMBERS_FEATURE", "");
417 159 : 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 156 : VSIFPrintfL(fpOut_, "{\n\"type\": \"FeatureCollection\",\n");
442 :
443 156 : 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 156 : CPLTestBool(CSLFetchNameValueDef(papszOptions, "WRITE_BBOX", "FALSE"));
452 :
453 : const bool bRFC7946 =
454 156 : CPLTestBool(CSLFetchNameValueDef(papszOptions, "RFC7946", "FALSE"));
455 :
456 156 : const char *pszNativeData = CSLFetchNameValue(papszOptions, "NATIVE_DATA");
457 : const char *pszNativeMediaType =
458 156 : CSLFetchNameValue(papszOptions, "NATIVE_MEDIA_TYPE");
459 156 : bool bWriteCRSIfWGS84 = true;
460 156 : bool bFoundNameInNativeData = false;
461 156 : 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 156 : const char *pszAtName = CSLFetchNameValue(papszOptions, "@NAME");
539 156 : 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 448 : else if (!bFoundNameInNativeData &&
547 138 : CPLFetchBool(papszOptions, "WRITE_NAME", true) &&
548 403 : !EQUAL(pszNameIn, OGRGeoJSONLayer::DefaultName) &&
549 110 : !EQUAL(pszNameIn, ""))
550 : {
551 110 : json_object *poName = json_object_new_string(pszNameIn);
552 110 : VSIFPrintfL(fpOut_, "\"name\": %s,\n",
553 : json_object_to_json_string(poName));
554 110 : json_object_put(poName);
555 : }
556 :
557 156 : const char *pszDescription = CSLFetchNameValue(papszOptions, "DESCRIPTION");
558 156 : 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 156 : OGRCoordinateTransformation *poCT = nullptr;
567 156 : 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 133 : else if (poSRS)
616 : {
617 55 : char *pszOGCURN = poSRS->GetOGCURN();
618 55 : if (pszOGCURN != nullptr &&
619 17 : (bWriteCRSIfWGS84 ||
620 17 : !EQUAL(pszOGCURN, "urn:ogc:def:crs:EPSG::4326")))
621 : {
622 39 : json_object *poObjCRS = json_object_new_object();
623 39 : json_object_object_add(poObjCRS, "type",
624 : json_object_new_string("name"));
625 39 : json_object *poObjProperties = json_object_new_object();
626 39 : json_object_object_add(poObjCRS, "properties", poObjProperties);
627 :
628 39 : 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 27 : json_object_object_add(poObjProperties, "name",
637 : json_object_new_string(pszOGCURN));
638 : }
639 :
640 39 : const char *pszCRS = json_object_to_json_string(poObjCRS);
641 39 : VSIFPrintfL(fpOut_, "\"crs\": %s,\n", pszCRS);
642 :
643 39 : json_object_put(poObjCRS);
644 : }
645 55 : CPLFree(pszOGCURN);
646 : }
647 :
648 156 : CPLStringList aosOptions(papszOptions);
649 :
650 156 : double dfXYResolution = OGRGeomCoordinatePrecision::UNKNOWN;
651 156 : double dfZResolution = OGRGeomCoordinatePrecision::UNKNOWN;
652 :
653 156 : if (const char *pszCoordPrecision =
654 156 : 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 153 : else if (poSrcGeomFieldDefn)
667 : {
668 149 : const auto &oCoordPrec = poSrcGeomFieldDefn->GetCoordinatePrecision();
669 298 : OGRSpatialReference oSRSWGS84;
670 149 : oSRSWGS84.SetWellKnownGeogCS("WGS84");
671 : const auto oCoordPrecWGS84 =
672 298 : oCoordPrec.ConvertToOtherSRS(poSRS, &oSRSWGS84);
673 :
674 149 : 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 149 : 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 156 : 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 156 : VSIFPrintfL(fpOut_, "\"features\": [\n");
711 :
712 : OGRGeoJSONWriteLayer *poLayer = new OGRGeoJSONWriteLayer(
713 156 : pszNameIn, eGType, aosOptions.List(), bWriteFC_BBOX, poCT, this);
714 :
715 156 : 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 156 : 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 156 : CPLAssert(papoLayers_ == nullptr);
739 312 : papoLayersWriter_ = static_cast<OGRGeoJSONWriteLayer **>(CPLRealloc(
740 156 : papoLayers_, sizeof(OGRGeoJSONWriteLayer *) * (nLayers_ + 1)));
741 :
742 156 : papoLayersWriter_[nLayers_++] = poLayer;
743 :
744 156 : return poLayer;
745 : }
746 :
747 : /************************************************************************/
748 : /* TestCapability() */
749 : /************************************************************************/
750 :
751 341 : int OGRGeoJSONDataSource::TestCapability(const char *pszCap)
752 : {
753 341 : if (EQUAL(pszCap, ODsCCreateLayer))
754 99 : return fpOut_ != nullptr && nLayers_ == 0;
755 242 : else if (EQUAL(pszCap, ODsCZGeometries) ||
756 238 : EQUAL(pszCap, ODsCMeasuredGeometries))
757 8 : return TRUE;
758 :
759 234 : return FALSE;
760 : }
761 :
762 : /************************************************************************/
763 : /* Create() */
764 : /************************************************************************/
765 :
766 158 : int OGRGeoJSONDataSource::Create(const char *pszName,
767 : char ** /* papszOptions */)
768 : {
769 158 : CPLAssert(nullptr == fpOut_);
770 :
771 158 : if (strcmp(pszName, "/dev/stdout") == 0)
772 0 : pszName = "/vsistdout/";
773 :
774 315 : bFpOutputIsSeekable_ = !(strcmp(pszName, "/vsistdout/") == 0 ||
775 157 : STARTS_WITH(pszName, "/vsigzip/") ||
776 151 : STARTS_WITH(pszName, "/vsizip/"));
777 :
778 : /* -------------------------------------------------------------------- */
779 : /* File overwrite not supported. */
780 : /* -------------------------------------------------------------------- */
781 : VSIStatBufL sStatBuf;
782 158 : if (0 == VSIStatL(pszName, &sStatBuf))
783 : {
784 0 : CPLError(CE_Failure, CPLE_NotSupported,
785 : "The GeoJSON driver does not overwrite existing files.");
786 0 : return FALSE;
787 : }
788 :
789 : /* -------------------------------------------------------------------- */
790 : /* Create the output file. */
791 : /* -------------------------------------------------------------------- */
792 158 : fpOut_ = VSIFOpenExL(pszName, "w", true);
793 158 : if (nullptr == fpOut_)
794 : {
795 2 : CPLError(CE_Failure, CPLE_OpenFailed,
796 : "Failed to create GeoJSON datasource: %s: %s", pszName,
797 : VSIGetLastErrorMsg());
798 2 : return FALSE;
799 : }
800 :
801 156 : pszName_ = CPLStrdup(pszName);
802 :
803 156 : return TRUE;
804 : }
805 :
806 : /************************************************************************/
807 : /* SetGeometryTranslation() */
808 : /************************************************************************/
809 :
810 485 : void OGRGeoJSONDataSource::SetGeometryTranslation(GeometryTranslation type)
811 : {
812 485 : flTransGeom_ = type;
813 485 : }
814 :
815 : /************************************************************************/
816 : /* SetAttributesTranslation() */
817 : /************************************************************************/
818 :
819 485 : void OGRGeoJSONDataSource::SetAttributesTranslation(AttributesTranslation type)
820 : {
821 485 : flTransAttrs_ = type;
822 485 : }
823 :
824 : /************************************************************************/
825 : /* PRIVATE FUNCTIONS IMPLEMENTATION */
826 : /************************************************************************/
827 :
828 673 : bool OGRGeoJSONDataSource::Clear()
829 : {
830 1311 : for (int i = 0; i < nLayers_; i++)
831 : {
832 638 : if (papoLayers_ != nullptr)
833 482 : delete papoLayers_[i];
834 : else
835 156 : delete papoLayersWriter_[i];
836 : }
837 :
838 673 : CPLFree(papoLayers_);
839 673 : papoLayers_ = nullptr;
840 673 : CPLFree(papoLayersWriter_);
841 673 : papoLayersWriter_ = nullptr;
842 673 : nLayers_ = 0;
843 :
844 673 : CPLFree(pszName_);
845 673 : pszName_ = nullptr;
846 :
847 673 : CPLFree(pszGeoData_);
848 673 : pszGeoData_ = nullptr;
849 673 : nGeoDataLen_ = 0;
850 :
851 673 : bool bRet = true;
852 673 : if (fpOut_)
853 : {
854 156 : if (VSIFCloseL(fpOut_) != 0)
855 0 : bRet = false;
856 156 : fpOut_ = nullptr;
857 : }
858 673 : return bRet;
859 : }
860 :
861 : /************************************************************************/
862 : /* ReadFromFile() */
863 : /************************************************************************/
864 :
865 58 : int OGRGeoJSONDataSource::ReadFromFile(GDALOpenInfo *poOpenInfo,
866 : const char *pszUnprefixed)
867 : {
868 58 : GByte *pabyOut = nullptr;
869 58 : if (!EQUAL(poOpenInfo->pszFilename, pszUnprefixed))
870 : {
871 1 : GDALOpenInfo oOpenInfo(pszUnprefixed, GA_ReadOnly);
872 1 : if (oOpenInfo.fpL == nullptr || oOpenInfo.pabyHeader == nullptr)
873 0 : return FALSE;
874 1 : VSIFSeekL(oOpenInfo.fpL, 0, SEEK_SET);
875 1 : if (!VSIIngestFile(oOpenInfo.fpL, pszUnprefixed, &pabyOut, nullptr, -1))
876 : {
877 0 : return FALSE;
878 : }
879 : }
880 : else
881 : {
882 57 : if (poOpenInfo->fpL == nullptr)
883 0 : return FALSE;
884 57 : VSIFSeekL(poOpenInfo->fpL, 0, SEEK_SET);
885 57 : if (!VSIIngestFile(poOpenInfo->fpL, poOpenInfo->pszFilename, &pabyOut,
886 : nullptr, -1))
887 : {
888 0 : return FALSE;
889 : }
890 :
891 57 : VSIFCloseL(poOpenInfo->fpL);
892 57 : poOpenInfo->fpL = nullptr;
893 : }
894 :
895 58 : CPLFree(pszGeoData_);
896 58 : pszGeoData_ = reinterpret_cast<char *>(pabyOut);
897 :
898 58 : CPLAssert(nullptr != pszGeoData_);
899 :
900 58 : return TRUE;
901 : }
902 :
903 : /************************************************************************/
904 : /* ReadFromService() */
905 : /************************************************************************/
906 :
907 23 : int OGRGeoJSONDataSource::ReadFromService(GDALOpenInfo *poOpenInfo,
908 : const char *pszSource)
909 : {
910 23 : CPLAssert(nullptr == pszGeoData_);
911 23 : CPLAssert(nullptr != pszSource);
912 :
913 23 : CPLErrorReset();
914 :
915 : /* -------------------------------------------------------------------- */
916 : /* Look if we already cached the content. */
917 : /* -------------------------------------------------------------------- */
918 23 : char *pszStoredContent = OGRGeoJSONDriverStealStoredContent(pszSource);
919 23 : if (pszStoredContent != nullptr)
920 : {
921 16 : if (!EQUAL(pszStoredContent, INVALID_CONTENT_FOR_JSON_LIKE) &&
922 0 : ((osJSonFlavor_ == "ESRIJSON" &&
923 0 : ESRIJSONIsObject(pszStoredContent, poOpenInfo)) ||
924 0 : (osJSonFlavor_ == "TopoJSON" &&
925 0 : TopoJSONIsObject(pszStoredContent, poOpenInfo))))
926 : {
927 0 : pszGeoData_ = pszStoredContent;
928 0 : nGeoDataLen_ = strlen(pszGeoData_);
929 :
930 0 : pszName_ = CPLStrdup(pszSource);
931 0 : return true;
932 : }
933 :
934 16 : OGRGeoJSONDriverStoreContent(pszSource, pszStoredContent);
935 16 : return false;
936 : }
937 :
938 : /* -------------------------------------------------------------------- */
939 : /* Fetch the GeoJSON result. */
940 : /* -------------------------------------------------------------------- */
941 7 : CPLHTTPResult *pResult = GeoJSONHTTPFetchWithContentTypeHeader(pszSource);
942 7 : if (!pResult)
943 : {
944 0 : return FALSE;
945 : }
946 :
947 : /* -------------------------------------------------------------------- */
948 : /* Copy returned GeoJSON data to text buffer. */
949 : /* -------------------------------------------------------------------- */
950 7 : char *pszData = reinterpret_cast<char *>(pResult->pabyData);
951 :
952 : // Directly assign CPLHTTPResult::pabyData to pszGeoData_.
953 7 : pszGeoData_ = pszData;
954 7 : nGeoDataLen_ = pResult->nDataLen;
955 7 : pResult->pabyData = nullptr;
956 7 : pResult->nDataLen = 0;
957 :
958 7 : pszName_ = CPLStrdup(pszSource);
959 :
960 : /* -------------------------------------------------------------------- */
961 : /* Cleanup HTTP resources. */
962 : /* -------------------------------------------------------------------- */
963 7 : CPLHTTPDestroyResult(pResult);
964 :
965 7 : CPLAssert(nullptr != pszGeoData_);
966 :
967 : /* -------------------------------------------------------------------- */
968 : /* Cache the content if it is not handled by this driver, but */
969 : /* another related one. */
970 : /* -------------------------------------------------------------------- */
971 7 : if (EQUAL(pszSource, poOpenInfo->pszFilename) && osJSonFlavor_ == "GeoJSON")
972 : {
973 7 : if (!GeoJSONIsObject(pszGeoData_, poOpenInfo))
974 : {
975 3 : if (ESRIJSONIsObject(pszGeoData_, poOpenInfo) ||
976 3 : TopoJSONIsObject(pszGeoData_, poOpenInfo) ||
977 9 : GeoJSONSeqIsObject(pszGeoData_, poOpenInfo) ||
978 3 : JSONFGIsObject(pszGeoData_, poOpenInfo))
979 : {
980 0 : OGRGeoJSONDriverStoreContent(pszSource, pszGeoData_);
981 0 : pszGeoData_ = nullptr;
982 0 : nGeoDataLen_ = 0;
983 : }
984 : else
985 : {
986 3 : OGRGeoJSONDriverStoreContent(
987 : pszSource, CPLStrdup(INVALID_CONTENT_FOR_JSON_LIKE));
988 : }
989 3 : return false;
990 : }
991 : }
992 :
993 4 : return TRUE;
994 : }
995 :
996 : /************************************************************************/
997 : /* RemoveJSonPStuff() */
998 : /************************************************************************/
999 :
1000 177 : void OGRGeoJSONDataSource::RemoveJSonPStuff()
1001 : {
1002 177 : const char *const apszPrefix[] = {"loadGeoJSON(", "jsonp("};
1003 531 : for (size_t iP = 0; iP < CPL_ARRAYSIZE(apszPrefix); iP++)
1004 : {
1005 354 : if (strncmp(pszGeoData_, apszPrefix[iP], strlen(apszPrefix[iP])) == 0)
1006 : {
1007 2 : const size_t nDataLen = strlen(pszGeoData_);
1008 2 : memmove(pszGeoData_, pszGeoData_ + strlen(apszPrefix[iP]),
1009 2 : nDataLen - strlen(apszPrefix[iP]));
1010 2 : size_t i = nDataLen - strlen(apszPrefix[iP]);
1011 2 : pszGeoData_[i] = '\0';
1012 4 : while (i > 0 && pszGeoData_[i] != ')')
1013 : {
1014 2 : i--;
1015 : }
1016 2 : pszGeoData_[i] = '\0';
1017 : }
1018 : }
1019 177 : }
1020 :
1021 : /************************************************************************/
1022 : /* LoadLayers() */
1023 : /************************************************************************/
1024 :
1025 480 : void OGRGeoJSONDataSource::LoadLayers(GDALOpenInfo *poOpenInfo,
1026 : GeoJSONSourceType nSrcType,
1027 : const char *pszUnprefixed,
1028 : const char *pszJSonFlavor)
1029 : {
1030 480 : if (nullptr == pszGeoData_)
1031 : {
1032 0 : CPLError(CE_Failure, CPLE_ObjectNull, "%s data buffer empty",
1033 : pszJSonFlavor);
1034 0 : return;
1035 : }
1036 :
1037 480 : if (nSrcType != eGeoJSONSourceFile)
1038 : {
1039 142 : RemoveJSonPStuff();
1040 : }
1041 :
1042 : /* -------------------------------------------------------------------- */
1043 : /* Is it ESRI Feature Service data ? */
1044 : /* -------------------------------------------------------------------- */
1045 480 : if (EQUAL(pszJSonFlavor, "ESRIJSON"))
1046 : {
1047 42 : OGRESRIJSONReader reader;
1048 21 : if (nSrcType == eGeoJSONSourceFile)
1049 : {
1050 19 : if (!ReadFromFile(poOpenInfo, pszUnprefixed))
1051 0 : return;
1052 : }
1053 21 : OGRErr err = reader.Parse(pszGeoData_);
1054 21 : if (OGRERR_NONE == err)
1055 : {
1056 21 : json_object *poObj = reader.GetJSonObject();
1057 21 : CheckExceededTransferLimit(poObj);
1058 21 : reader.ReadLayers(this, nSrcType);
1059 : }
1060 21 : return;
1061 : }
1062 :
1063 : /* -------------------------------------------------------------------- */
1064 : /* Is it TopoJSON data ? */
1065 : /* -------------------------------------------------------------------- */
1066 459 : if (EQUAL(pszJSonFlavor, "TOPOJSON"))
1067 : {
1068 8 : OGRTopoJSONReader reader;
1069 4 : if (nSrcType == eGeoJSONSourceFile)
1070 : {
1071 4 : if (!ReadFromFile(poOpenInfo, pszUnprefixed))
1072 0 : return;
1073 : }
1074 8 : OGRErr err = reader.Parse(
1075 4 : pszGeoData_,
1076 4 : nSrcType == eGeoJSONSourceService &&
1077 0 : !STARTS_WITH_CI(poOpenInfo->pszFilename, "TopoJSON:"));
1078 4 : if (OGRERR_NONE == err)
1079 : {
1080 4 : reader.ReadLayers(this);
1081 : }
1082 4 : return;
1083 : }
1084 :
1085 455 : VSILFILE *fp = nullptr;
1086 455 : if (nSrcType == eGeoJSONSourceFile &&
1087 315 : !EQUAL(poOpenInfo->pszFilename, pszUnprefixed))
1088 : {
1089 0 : GDALOpenInfo oOpenInfo(pszUnprefixed, GA_ReadOnly);
1090 0 : if (oOpenInfo.fpL == nullptr || oOpenInfo.pabyHeader == nullptr)
1091 0 : return;
1092 0 : CPL_IGNORE_RET_VAL(oOpenInfo.TryToIngest(6000));
1093 0 : CPLFree(pszGeoData_);
1094 0 : pszGeoData_ =
1095 0 : CPLStrdup(reinterpret_cast<const char *>(oOpenInfo.pabyHeader));
1096 0 : fp = oOpenInfo.fpL;
1097 0 : oOpenInfo.fpL = nullptr;
1098 : }
1099 :
1100 455 : if (!GeoJSONIsObject(pszGeoData_, poOpenInfo))
1101 : {
1102 0 : CPLDebug(pszJSonFlavor, "No valid %s data found in source '%s'",
1103 : pszJSonFlavor, pszName_);
1104 0 : if (fp)
1105 0 : VSIFCloseL(fp);
1106 0 : return;
1107 : }
1108 :
1109 : /* -------------------------------------------------------------------- */
1110 : /* Configure GeoJSON format translator. */
1111 : /* -------------------------------------------------------------------- */
1112 455 : OGRGeoJSONReader *poReader = new OGRGeoJSONReader();
1113 455 : SetOptionsOnReader(poOpenInfo, poReader);
1114 :
1115 : /* -------------------------------------------------------------------- */
1116 : /* Parse GeoJSON and build valid OGRLayer instance. */
1117 : /* -------------------------------------------------------------------- */
1118 455 : bool bUseStreamingInterface = false;
1119 455 : const GIntBig nMaxBytesFirstPass = CPLAtoGIntBig(
1120 : CPLGetConfigOption("OGR_GEOJSON_MAX_BYTES_FIRST_PASS", "0"));
1121 455 : if ((fp != nullptr || poOpenInfo->fpL != nullptr) &&
1122 315 : (!STARTS_WITH(pszUnprefixed, "/vsistdin/") ||
1123 0 : (nMaxBytesFirstPass > 0 && nMaxBytesFirstPass <= 1000000)))
1124 : {
1125 315 : const char *pszStr = strstr(pszGeoData_, "\"features\"");
1126 315 : if (pszStr)
1127 : {
1128 281 : pszStr += strlen("\"features\"");
1129 304 : while (*pszStr && isspace(static_cast<unsigned char>(*pszStr)))
1130 23 : pszStr++;
1131 281 : if (*pszStr == ':')
1132 : {
1133 281 : pszStr++;
1134 637 : while (*pszStr && isspace(static_cast<unsigned char>(*pszStr)))
1135 356 : pszStr++;
1136 281 : if (*pszStr == '[')
1137 : {
1138 281 : bUseStreamingInterface = true;
1139 : }
1140 : }
1141 : }
1142 : }
1143 :
1144 455 : if (bUseStreamingInterface)
1145 : {
1146 281 : bool bTryStandardReading = false;
1147 281 : if (poReader->FirstPassReadLayer(this, fp ? fp : poOpenInfo->fpL,
1148 : bTryStandardReading))
1149 : {
1150 278 : if (fp)
1151 0 : fp = nullptr;
1152 : else
1153 278 : poOpenInfo->fpL = nullptr;
1154 278 : CheckExceededTransferLimit(poReader->GetJSonObject());
1155 : }
1156 : else
1157 : {
1158 3 : delete poReader;
1159 : }
1160 281 : if (!bTryStandardReading)
1161 : {
1162 280 : if (fp)
1163 0 : VSIFCloseL(fp);
1164 280 : return;
1165 : }
1166 :
1167 1 : poReader = new OGRGeoJSONReader();
1168 1 : SetOptionsOnReader(poOpenInfo, poReader);
1169 : }
1170 :
1171 175 : if (fp)
1172 0 : VSIFCloseL(fp);
1173 175 : if (nSrcType == eGeoJSONSourceFile)
1174 : {
1175 35 : if (!ReadFromFile(poOpenInfo, pszUnprefixed))
1176 : {
1177 0 : delete poReader;
1178 0 : return;
1179 : }
1180 35 : RemoveJSonPStuff();
1181 : }
1182 175 : const OGRErr err = poReader->Parse(pszGeoData_);
1183 175 : if (OGRERR_NONE == err)
1184 : {
1185 175 : CheckExceededTransferLimit(poReader->GetJSonObject());
1186 : }
1187 :
1188 175 : poReader->ReadLayers(this);
1189 175 : delete poReader;
1190 : }
1191 :
1192 : /************************************************************************/
1193 : /* SetOptionsOnReader() */
1194 : /************************************************************************/
1195 :
1196 456 : void OGRGeoJSONDataSource::SetOptionsOnReader(GDALOpenInfo *poOpenInfo,
1197 : OGRGeoJSONReader *poReader)
1198 : {
1199 456 : if (eGeometryAsCollection == flTransGeom_)
1200 : {
1201 0 : poReader->SetPreserveGeometryType(false);
1202 0 : CPLDebug("GeoJSON", "Geometry as OGRGeometryCollection type.");
1203 : }
1204 :
1205 456 : if (eAttributesSkip == flTransAttrs_)
1206 : {
1207 0 : poReader->SetSkipAttributes(true);
1208 0 : CPLDebug("GeoJSON", "Skip all attributes.");
1209 : }
1210 :
1211 1368 : poReader->SetFlattenNestedAttributes(
1212 456 : CPLFetchBool(poOpenInfo->papszOpenOptions, "FLATTEN_NESTED_ATTRIBUTES",
1213 : false),
1214 456 : CSLFetchNameValueDef(poOpenInfo->papszOpenOptions,
1215 456 : "NESTED_ATTRIBUTE_SEPARATOR", "_")[0]);
1216 :
1217 456 : const bool bDefaultNativeData = bUpdatable_;
1218 456 : poReader->SetStoreNativeData(CPLFetchBool(
1219 456 : poOpenInfo->papszOpenOptions, "NATIVE_DATA", bDefaultNativeData));
1220 :
1221 912 : poReader->SetArrayAsString(CPLTestBool(CSLFetchNameValueDef(
1222 456 : poOpenInfo->papszOpenOptions, "ARRAY_AS_STRING",
1223 : CPLGetConfigOption("OGR_GEOJSON_ARRAY_AS_STRING", "NO"))));
1224 :
1225 912 : poReader->SetDateAsString(CPLTestBool(CSLFetchNameValueDef(
1226 456 : poOpenInfo->papszOpenOptions, "DATE_AS_STRING",
1227 : CPLGetConfigOption("OGR_GEOJSON_DATE_AS_STRING", "NO"))));
1228 :
1229 912 : const char *pszForeignMembers = CSLFetchNameValueDef(
1230 456 : poOpenInfo->papszOpenOptions, "FOREIGN_MEMBERS", "AUTO");
1231 456 : if (EQUAL(pszForeignMembers, "AUTO"))
1232 : {
1233 452 : poReader->SetForeignMemberProcessing(
1234 : OGRGeoJSONBaseReader::ForeignMemberProcessing::AUTO);
1235 : }
1236 4 : else if (EQUAL(pszForeignMembers, "ALL"))
1237 : {
1238 1 : poReader->SetForeignMemberProcessing(
1239 : OGRGeoJSONBaseReader::ForeignMemberProcessing::ALL);
1240 : }
1241 3 : else if (EQUAL(pszForeignMembers, "NONE"))
1242 : {
1243 2 : poReader->SetForeignMemberProcessing(
1244 : OGRGeoJSONBaseReader::ForeignMemberProcessing::NONE);
1245 : }
1246 1 : else if (EQUAL(pszForeignMembers, "STAC"))
1247 : {
1248 1 : poReader->SetForeignMemberProcessing(
1249 : OGRGeoJSONBaseReader::ForeignMemberProcessing::STAC);
1250 : }
1251 456 : }
1252 :
1253 : /************************************************************************/
1254 : /* CheckExceededTransferLimit() */
1255 : /************************************************************************/
1256 :
1257 474 : void OGRGeoJSONDataSource::CheckExceededTransferLimit(json_object *poObj)
1258 : {
1259 1404 : for (int i = 0; i < 2; i++)
1260 : {
1261 946 : if (i == 1)
1262 : {
1263 472 : if (poObj && json_object_get_type(poObj) == json_type_object)
1264 : {
1265 472 : poObj = CPL_json_object_object_get(poObj, "properties");
1266 : }
1267 : }
1268 946 : if (poObj && json_object_get_type(poObj) == json_type_object)
1269 : {
1270 : json_object *poExceededTransferLimit =
1271 507 : CPL_json_object_object_get(poObj, "exceededTransferLimit");
1272 523 : if (poExceededTransferLimit &&
1273 16 : json_object_get_type(poExceededTransferLimit) ==
1274 : json_type_boolean)
1275 : {
1276 16 : bOtherPages_ = CPL_TO_BOOL(
1277 : json_object_get_boolean(poExceededTransferLimit));
1278 16 : return;
1279 : }
1280 : }
1281 : }
1282 : }
1283 :
1284 : /************************************************************************/
1285 : /* AddLayer() */
1286 : /************************************************************************/
1287 :
1288 482 : void OGRGeoJSONDataSource::AddLayer(OGRGeoJSONLayer *poLayer)
1289 : {
1290 482 : CPLAssert(papoLayersWriter_ == nullptr);
1291 :
1292 : // Return layer in readable state.
1293 482 : poLayer->ResetReading();
1294 :
1295 482 : papoLayers_ = static_cast<OGRGeoJSONLayer **>(
1296 482 : CPLRealloc(papoLayers_, sizeof(OGRGeoJSONLayer *) * (nLayers_ + 1)));
1297 482 : papoLayers_[nLayers_] = poLayer;
1298 482 : nLayers_++;
1299 482 : }
1300 :
1301 : /************************************************************************/
1302 : /* FlushCache() */
1303 : /************************************************************************/
1304 :
1305 746 : CPLErr OGRGeoJSONDataSource::FlushCache(bool /*bAtClosing*/)
1306 : {
1307 746 : if (papoLayersWriter_ != nullptr)
1308 : {
1309 234 : return papoLayersWriter_[0]->SyncToDisk() == OGRERR_NONE ? CE_None
1310 234 : : CE_Failure;
1311 : }
1312 :
1313 512 : CPLErr eErr = CE_None;
1314 994 : for (int i = 0; i < nLayers_; i++)
1315 : {
1316 482 : if (papoLayers_[i]->HasBeenUpdated())
1317 : {
1318 15 : papoLayers_[i]->SetUpdated(false);
1319 :
1320 15 : bool bOK = false;
1321 :
1322 : // Disable all filters.
1323 15 : OGRFeatureQuery *poAttrQueryBak = papoLayers_[i]->m_poAttrQuery;
1324 15 : papoLayers_[i]->m_poAttrQuery = nullptr;
1325 15 : OGRGeometry *poFilterGeomBak = papoLayers_[i]->m_poFilterGeom;
1326 15 : papoLayers_[i]->m_poFilterGeom = nullptr;
1327 :
1328 : // If the source data only contained one single feature and
1329 : // that's still the case, then do not use a FeatureCollection
1330 : // on writing.
1331 15 : bool bAlreadyDone = false;
1332 23 : if (papoLayers_[i]->GetFeatureCount(TRUE) == 1 &&
1333 8 : papoLayers_[i]->GetMetadata("NATIVE_DATA") == nullptr)
1334 : {
1335 1 : papoLayers_[i]->ResetReading();
1336 1 : OGRFeature *poFeature = papoLayers_[i]->GetNextFeature();
1337 1 : if (poFeature != nullptr)
1338 : {
1339 1 : if (poFeature->GetNativeData() != nullptr)
1340 : {
1341 1 : bAlreadyDone = true;
1342 2 : OGRGeoJSONWriteOptions oOptions;
1343 : json_object *poObj =
1344 1 : OGRGeoJSONWriteFeature(poFeature, oOptions);
1345 1 : VSILFILE *fp = VSIFOpenL(pszName_, "wb");
1346 1 : if (fp != nullptr)
1347 : {
1348 1 : bOK = VSIFPrintfL(
1349 : fp, "%s",
1350 : json_object_to_json_string(poObj)) > 0;
1351 1 : VSIFCloseL(fp);
1352 : }
1353 1 : json_object_put(poObj);
1354 : }
1355 1 : delete poFeature;
1356 : }
1357 : }
1358 :
1359 : // Otherwise do layer translation.
1360 15 : if (!bAlreadyDone)
1361 : {
1362 14 : char **papszOptions = CSLAddString(nullptr, "-f");
1363 14 : papszOptions = CSLAddString(papszOptions, "GeoJSON");
1364 : GDALVectorTranslateOptions *psOptions =
1365 14 : GDALVectorTranslateOptionsNew(papszOptions, nullptr);
1366 14 : CSLDestroy(papszOptions);
1367 14 : GDALDatasetH hSrcDS = this;
1368 28 : CPLString osNewFilename(pszName_);
1369 14 : osNewFilename += ".tmp";
1370 14 : GDALDatasetH hOutDS = GDALVectorTranslate(
1371 : osNewFilename, nullptr, 1, &hSrcDS, psOptions, nullptr);
1372 14 : GDALVectorTranslateOptionsFree(psOptions);
1373 :
1374 14 : if (hOutDS != nullptr)
1375 : {
1376 14 : CPLErrorReset();
1377 14 : GDALClose(hOutDS);
1378 14 : bOK = (CPLGetLastErrorType() == CE_None);
1379 : }
1380 14 : if (bOK)
1381 : {
1382 14 : const bool bOverwrite = CPLTestBool(
1383 : CPLGetConfigOption("OGR_GEOJSON_REWRITE_IN_PLACE",
1384 : #ifdef _WIN32
1385 : "YES"
1386 : #else
1387 : "NO"
1388 : #endif
1389 : ));
1390 14 : if (bOverwrite)
1391 : {
1392 1 : VSILFILE *fpTarget = nullptr;
1393 1 : for (int attempt = 0; attempt < 10; attempt++)
1394 : {
1395 1 : fpTarget = VSIFOpenL(pszName_, "rb+");
1396 1 : if (fpTarget)
1397 1 : break;
1398 0 : CPLSleep(0.1);
1399 : }
1400 1 : if (!fpTarget)
1401 : {
1402 0 : CPLError(CE_Failure, CPLE_AppDefined,
1403 : "Cannot rewrite %s", pszName_);
1404 : }
1405 : else
1406 : {
1407 1 : bool bCopyOK = CPL_TO_BOOL(
1408 : VSIOverwriteFile(fpTarget, osNewFilename));
1409 1 : if (VSIFCloseL(fpTarget) != 0)
1410 0 : bCopyOK = false;
1411 1 : if (bCopyOK)
1412 : {
1413 1 : VSIUnlink(osNewFilename);
1414 : }
1415 : else
1416 : {
1417 0 : CPLError(CE_Failure, CPLE_AppDefined,
1418 : "Cannot rewrite %s with content of %s",
1419 : pszName_, osNewFilename.c_str());
1420 : }
1421 : }
1422 : }
1423 : else
1424 : {
1425 26 : CPLString osBackup(pszName_);
1426 13 : osBackup += ".bak";
1427 13 : if (VSIRename(pszName_, osBackup) < 0)
1428 : {
1429 0 : CPLError(CE_Failure, CPLE_AppDefined,
1430 : "Cannot create backup copy");
1431 : }
1432 13 : else if (VSIRename(osNewFilename, pszName_) < 0)
1433 : {
1434 0 : CPLError(CE_Failure, CPLE_AppDefined,
1435 : "Cannot rename %s to %s",
1436 : osNewFilename.c_str(), pszName_);
1437 : }
1438 : else
1439 : {
1440 13 : VSIUnlink(osBackup);
1441 : }
1442 : }
1443 : }
1444 : }
1445 15 : if (!bOK)
1446 0 : eErr = CE_Failure;
1447 :
1448 : // Restore filters.
1449 15 : papoLayers_[i]->m_poAttrQuery = poAttrQueryBak;
1450 15 : papoLayers_[i]->m_poFilterGeom = poFilterGeomBak;
1451 : }
1452 : }
1453 512 : return eErr;
1454 : }
|