Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: OpenGIS Simple Features Reference Implementation
4 : * Purpose: GeoJSON feature sequence driver
5 : * Author: Even Rouault <even.rouault at spatialys.com>
6 : *
7 : ******************************************************************************
8 : * Copyright (c) 2018, Even Rouault <even.rouault at spatialys.com>
9 : *
10 : * SPDX-License-Identifier: MIT
11 : ****************************************************************************/
12 :
13 : #include "cpl_port.h"
14 : #include "cpl_vsi_virtual.h"
15 : #include "cpl_http.h"
16 : #include "cpl_vsi_error.h"
17 :
18 : #include "ogr_geojson.h"
19 : #include "ogrlibjsonutils.h"
20 : #include "ogrgeojsonreader.h"
21 : #include "ogrgeojsonwriter.h"
22 : #include "ogrgeojsongeometry.h"
23 :
24 : #include <algorithm>
25 : #include <memory>
26 :
27 : constexpr char RS = '\x1e';
28 :
29 : /************************************************************************/
30 : /* OGRGeoJSONSeqDataSource */
31 : /************************************************************************/
32 :
33 : class OGRGeoJSONSeqDataSource final : public GDALDataset
34 : {
35 : friend class OGRGeoJSONSeqLayer;
36 :
37 : std::vector<std::unique_ptr<OGRLayer>> m_apoLayers{};
38 : CPLString m_osTmpFile;
39 : VSILFILE *m_fp = nullptr;
40 : bool m_bSupportsRead = true;
41 : bool m_bAtEOF = false;
42 : bool m_bIsRSSeparated = false;
43 :
44 : public:
45 : OGRGeoJSONSeqDataSource();
46 : ~OGRGeoJSONSeqDataSource() override;
47 :
48 76 : int GetLayerCount() const override
49 : {
50 76 : return static_cast<int>(m_apoLayers.size());
51 : }
52 :
53 : const OGRLayer *GetLayer(int) const override;
54 : OGRLayer *ICreateLayer(const char *pszName,
55 : const OGRGeomFieldDefn *poGeomFieldDefn,
56 : CSLConstList papszOptions) override;
57 : int TestCapability(const char *pszCap) const override;
58 :
59 : bool Open(GDALOpenInfo *poOpenInfo, GeoJSONSourceType nSrcType);
60 : bool Create(const char *pszName, char **papszOptions);
61 : };
62 :
63 : /************************************************************************/
64 : /* OGRGeoJSONSeqLayer */
65 : /************************************************************************/
66 :
67 : class OGRGeoJSONSeqLayer final : public OGRLayer
68 : {
69 : OGRGeoJSONSeqDataSource *m_poDS = nullptr;
70 : OGRFeatureDefn *m_poFeatureDefn = nullptr;
71 : bool m_bLayerDefnEstablished = false;
72 : bool m_bWriteOnlyLayer = false;
73 :
74 : OGRGeoJSONBaseReader m_oReader;
75 : CPLString m_osFIDColumn;
76 :
77 : size_t m_nMaxObjectSize = 0;
78 : std::string m_osBuffer;
79 : std::string m_osFeatureBuffer;
80 : size_t m_nPosInBuffer = 0;
81 : size_t m_nBufferValidSize = 0;
82 :
83 : vsi_l_offset m_nFileSize = 0;
84 : GIntBig m_nIter = 0;
85 :
86 : GIntBig m_nTotalFeatures = 0;
87 : GIntBig m_nNextFID = 0;
88 :
89 : std::unique_ptr<OGRCoordinateTransformation> m_poCT{};
90 : OGRGeometryFactory::TransformWithOptionsCache m_oTransformCache;
91 : OGRGeoJSONWriteOptions m_oWriteOptions;
92 :
93 : json_object *GetNextObject(bool bLooseIdentification);
94 :
95 : public:
96 : OGRGeoJSONSeqLayer(OGRGeoJSONSeqDataSource *poDS, const char *pszName);
97 :
98 : // Write-only constructor
99 : OGRGeoJSONSeqLayer(OGRGeoJSONSeqDataSource *poDS, const char *pszName,
100 : CSLConstList papszOptions,
101 : std::unique_ptr<OGRCoordinateTransformation> &&poCT);
102 :
103 : ~OGRGeoJSONSeqLayer() override;
104 :
105 : bool Init(bool bLooseIdentification, bool bEstablishLayerDefn);
106 :
107 61 : const char *GetName() const override
108 : {
109 61 : return GetDescription();
110 : }
111 :
112 : void ResetReading() override;
113 : OGRFeature *GetNextFeature() override;
114 : const OGRFeatureDefn *GetLayerDefn() const override;
115 :
116 30 : const char *GetFIDColumn() const override
117 : {
118 30 : return m_osFIDColumn.c_str();
119 : }
120 :
121 : GIntBig GetFeatureCount(int) override;
122 : int TestCapability(const char *) const override;
123 : OGRErr ICreateFeature(OGRFeature *poFeature) override;
124 : OGRErr CreateField(const OGRFieldDefn *, int) override;
125 :
126 22 : GDALDataset *GetDataset() override
127 : {
128 22 : return m_poDS;
129 : }
130 : };
131 :
132 : /************************************************************************/
133 : /* OGRGeoJSONSeqDataSource() */
134 : /************************************************************************/
135 :
136 99 : OGRGeoJSONSeqDataSource::OGRGeoJSONSeqDataSource()
137 : {
138 99 : }
139 :
140 : /************************************************************************/
141 : /* ~OGRGeoJSONSeqDataSource() */
142 : /************************************************************************/
143 :
144 198 : OGRGeoJSONSeqDataSource::~OGRGeoJSONSeqDataSource()
145 : {
146 99 : if (m_fp)
147 : {
148 89 : VSIFCloseL(m_fp);
149 : }
150 99 : if (!m_osTmpFile.empty())
151 : {
152 3 : VSIUnlink(m_osTmpFile);
153 : }
154 198 : }
155 :
156 : /************************************************************************/
157 : /* GetLayer() */
158 : /************************************************************************/
159 :
160 44 : const OGRLayer *OGRGeoJSONSeqDataSource::GetLayer(int nIndex) const
161 : {
162 44 : if (nIndex < 0 || nIndex >= GetLayerCount())
163 2 : return nullptr;
164 42 : return m_apoLayers[nIndex].get();
165 : }
166 :
167 : /************************************************************************/
168 : /* ICreateLayer() */
169 : /************************************************************************/
170 :
171 65 : OGRLayer *OGRGeoJSONSeqDataSource::ICreateLayer(
172 : const char *pszNameIn, const OGRGeomFieldDefn *poSrcGeomFieldDefn,
173 : CSLConstList papszOptions)
174 : {
175 65 : if (!TestCapability(ODsCCreateLayer))
176 3 : return nullptr;
177 :
178 : const auto poSRS =
179 62 : poSrcGeomFieldDefn ? poSrcGeomFieldDefn->GetSpatialRef() : nullptr;
180 :
181 62 : std::unique_ptr<OGRCoordinateTransformation> poCT;
182 62 : if (poSRS == nullptr)
183 : {
184 50 : CPLError(
185 : CE_Warning, CPLE_AppDefined,
186 : "No SRS set on layer. Assuming it is long/lat on WGS84 ellipsoid");
187 : }
188 : else
189 : {
190 12 : OGRSpatialReference oSRSWGS84;
191 12 : oSRSWGS84.SetWellKnownGeogCS("WGS84");
192 12 : oSRSWGS84.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
193 12 : const char *const apszOptions[] = {
194 : "IGNORE_DATA_AXIS_TO_SRS_AXIS_MAPPING=YES", nullptr};
195 12 : if (!poSRS->IsSame(&oSRSWGS84, apszOptions))
196 : {
197 3 : poCT.reset(OGRCreateCoordinateTransformation(poSRS, &oSRSWGS84));
198 3 : if (poCT == nullptr)
199 : {
200 0 : CPLError(
201 : CE_Warning, CPLE_AppDefined,
202 : "Failed to create coordinate transformation between the "
203 : "input coordinate system and WGS84.");
204 :
205 0 : return nullptr;
206 : }
207 : }
208 : }
209 :
210 62 : const char *pszRS = CSLFetchNameValue(papszOptions, "RS");
211 62 : if (pszRS)
212 : {
213 1 : m_bIsRSSeparated = CPLTestBool(pszRS);
214 : }
215 :
216 62 : CPLStringList aosOptions(papszOptions);
217 :
218 62 : double dfXYResolution = OGRGeomCoordinatePrecision::UNKNOWN;
219 62 : double dfZResolution = OGRGeomCoordinatePrecision::UNKNOWN;
220 62 : if (const char *pszCoordPrecision =
221 62 : CSLFetchNameValue(papszOptions, "COORDINATE_PRECISION"))
222 : {
223 1 : dfXYResolution = std::pow(10.0, -CPLAtof(pszCoordPrecision));
224 1 : dfZResolution = dfXYResolution;
225 : }
226 61 : else if (poSrcGeomFieldDefn)
227 : {
228 58 : const auto &oCoordPrec = poSrcGeomFieldDefn->GetCoordinatePrecision();
229 116 : OGRSpatialReference oSRSWGS84;
230 58 : oSRSWGS84.SetWellKnownGeogCS("WGS84");
231 : const auto oCoordPrecWGS84 =
232 116 : oCoordPrec.ConvertToOtherSRS(poSRS, &oSRSWGS84);
233 :
234 58 : if (oCoordPrec.dfXYResolution != OGRGeomCoordinatePrecision::UNKNOWN)
235 : {
236 2 : dfXYResolution = oCoordPrecWGS84.dfXYResolution;
237 :
238 : aosOptions.SetNameValue(
239 : "XY_COORD_PRECISION",
240 : CPLSPrintf("%d",
241 : OGRGeomCoordinatePrecision::ResolutionToPrecision(
242 2 : dfXYResolution)));
243 : }
244 58 : if (oCoordPrec.dfZResolution != OGRGeomCoordinatePrecision::UNKNOWN)
245 : {
246 2 : dfZResolution = oCoordPrecWGS84.dfZResolution;
247 :
248 : aosOptions.SetNameValue(
249 : "Z_COORD_PRECISION",
250 : CPLSPrintf("%d",
251 : OGRGeomCoordinatePrecision::ResolutionToPrecision(
252 2 : dfZResolution)));
253 : }
254 : }
255 :
256 62 : m_apoLayers.emplace_back(std::make_unique<OGRGeoJSONSeqLayer>(
257 62 : this, pszNameIn, aosOptions.List(), std::move(poCT)));
258 :
259 62 : auto poLayer = m_apoLayers.back().get();
260 62 : if (poLayer->GetGeomType() != wkbNone &&
261 : dfXYResolution != OGRGeomCoordinatePrecision::UNKNOWN)
262 : {
263 3 : auto poGeomFieldDefn = poLayer->GetLayerDefn()->GetGeomFieldDefn(0);
264 : OGRGeomCoordinatePrecision oCoordPrec(
265 6 : poGeomFieldDefn->GetCoordinatePrecision());
266 3 : oCoordPrec.dfXYResolution = dfXYResolution;
267 3 : poGeomFieldDefn->SetCoordinatePrecision(oCoordPrec);
268 : }
269 :
270 62 : if (poLayer->GetGeomType() != wkbNone &&
271 : dfZResolution != OGRGeomCoordinatePrecision::UNKNOWN)
272 : {
273 3 : auto poGeomFieldDefn = poLayer->GetLayerDefn()->GetGeomFieldDefn(0);
274 : OGRGeomCoordinatePrecision oCoordPrec(
275 6 : poGeomFieldDefn->GetCoordinatePrecision());
276 3 : oCoordPrec.dfZResolution = dfZResolution;
277 3 : poGeomFieldDefn->SetCoordinatePrecision(oCoordPrec);
278 : }
279 :
280 62 : return poLayer;
281 : }
282 :
283 : /************************************************************************/
284 : /* TestCapability() */
285 : /************************************************************************/
286 :
287 128 : int OGRGeoJSONSeqDataSource::TestCapability(const char *pszCap) const
288 : {
289 128 : if (EQUAL(pszCap, ODsCCreateLayer))
290 105 : return eAccess == GA_Update;
291 :
292 23 : return FALSE;
293 : }
294 :
295 : /************************************************************************/
296 : /* OGRGeoJSONSeqLayer() */
297 : /************************************************************************/
298 :
299 46 : OGRGeoJSONSeqLayer::OGRGeoJSONSeqLayer(OGRGeoJSONSeqDataSource *poDS,
300 46 : const char *pszName)
301 46 : : m_poDS(poDS)
302 : {
303 46 : SetDescription(pszName);
304 46 : m_poFeatureDefn = new OGRFeatureDefn(pszName);
305 46 : m_poFeatureDefn->Reference();
306 :
307 46 : OGRSpatialReference *poSRSWGS84 = new OGRSpatialReference();
308 46 : poSRSWGS84->SetWellKnownGeogCS("WGS84");
309 46 : poSRSWGS84->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
310 46 : m_poFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef(poSRSWGS84);
311 46 : poSRSWGS84->Release();
312 :
313 : const double dfTmp =
314 46 : CPLAtof(CPLGetConfigOption("OGR_GEOJSON_MAX_OBJ_SIZE", "200"));
315 46 : m_nMaxObjectSize = dfTmp > 0 ? static_cast<size_t>(dfTmp * 1024 * 1024) : 0;
316 46 : }
317 :
318 : /************************************************************************/
319 : /* OGRGeoJSONSeqLayer() */
320 : /************************************************************************/
321 :
322 : // Write-only constructor
323 62 : OGRGeoJSONSeqLayer::OGRGeoJSONSeqLayer(
324 : OGRGeoJSONSeqDataSource *poDS, const char *pszName,
325 : CSLConstList papszOptions,
326 62 : std::unique_ptr<OGRCoordinateTransformation> &&poCT)
327 62 : : m_poDS(poDS), m_bWriteOnlyLayer(true)
328 : {
329 62 : m_bLayerDefnEstablished = true;
330 :
331 62 : SetDescription(pszName);
332 62 : m_poFeatureDefn = new OGRFeatureDefn(pszName);
333 62 : m_poFeatureDefn->Reference();
334 62 : m_poFeatureDefn->GetGeomFieldDefn(0)->SetSpatialRef(
335 62 : OGRSpatialReference::GetWGS84SRS());
336 62 : m_poCT = std::move(poCT);
337 :
338 62 : m_oWriteOptions.bWriteBBOX =
339 62 : CPLTestBool(CSLFetchNameValueDef(papszOptions, "WRITE_BBOX", "FALSE"));
340 62 : m_oWriteOptions.SetRFC7946Settings();
341 62 : m_oWriteOptions.SetIDOptions(papszOptions);
342 :
343 : const char *pszCoordPrecision =
344 62 : CSLFetchNameValue(papszOptions, "COORDINATE_PRECISION");
345 62 : if (pszCoordPrecision)
346 : {
347 1 : m_oWriteOptions.nXYCoordPrecision = atoi(pszCoordPrecision);
348 1 : m_oWriteOptions.nZCoordPrecision = atoi(pszCoordPrecision);
349 : }
350 : else
351 : {
352 61 : m_oWriteOptions.nXYCoordPrecision =
353 61 : atoi(CSLFetchNameValueDef(papszOptions, "XY_COORD_PRECISION", "7"));
354 61 : m_oWriteOptions.nZCoordPrecision =
355 61 : atoi(CSLFetchNameValueDef(papszOptions, "Z_COORD_PRECISION", "3"));
356 : }
357 :
358 62 : m_oWriteOptions.nSignificantFigures =
359 62 : atoi(CSLFetchNameValueDef(papszOptions, "SIGNIFICANT_FIGURES", "-1"));
360 62 : m_oWriteOptions.bAllowNonFiniteValues = CPLTestBool(
361 : CSLFetchNameValueDef(papszOptions, "WRITE_NON_FINITE_VALUES", "FALSE"));
362 62 : m_oWriteOptions.bAutodetectJsonStrings = CPLTestBool(
363 : CSLFetchNameValueDef(papszOptions, "AUTODETECT_JSON_STRINGS", "TRUE"));
364 62 : }
365 :
366 : /************************************************************************/
367 : /* ~OGRGeoJSONSeqLayer() */
368 : /************************************************************************/
369 :
370 216 : OGRGeoJSONSeqLayer::~OGRGeoJSONSeqLayer()
371 : {
372 108 : m_poFeatureDefn->Release();
373 216 : }
374 :
375 : /************************************************************************/
376 : /* GetLayerDefn() */
377 : /************************************************************************/
378 :
379 1184 : const OGRFeatureDefn *OGRGeoJSONSeqLayer::GetLayerDefn() const
380 : {
381 1184 : if (!m_bLayerDefnEstablished)
382 : {
383 3 : const_cast<OGRGeoJSONSeqLayer *>(this)->Init(
384 : /* bLooseIdentification = */ false,
385 : /* bEstablishLayerDefn = */ true);
386 : }
387 1184 : return m_poFeatureDefn;
388 : }
389 :
390 : /************************************************************************/
391 : /* Init() */
392 : /************************************************************************/
393 :
394 49 : bool OGRGeoJSONSeqLayer::Init(bool bLooseIdentification,
395 : bool bEstablishLayerDefn)
396 : {
397 55 : if (STARTS_WITH(m_poDS->GetDescription(), "/vsimem/") ||
398 6 : !STARTS_WITH(m_poDS->GetDescription(), "/vsi"))
399 : {
400 49 : VSIFSeekL(m_poDS->m_fp, 0, SEEK_END);
401 49 : m_nFileSize = VSIFTellL(m_poDS->m_fp);
402 : }
403 :
404 : // Set m_bLayerDefnEstablished = true early to avoid infinite recursive
405 : // calls.
406 49 : if (bEstablishLayerDefn)
407 43 : m_bLayerDefnEstablished = true;
408 :
409 49 : ResetReading();
410 :
411 98 : std::map<std::string, int> oMapFieldNameToIdx;
412 98 : std::vector<std::unique_ptr<OGRFieldDefn>> apoFieldDefn;
413 49 : gdal::DirectedAcyclicGraph<int, std::string> dag;
414 49 : bool bOK = false;
415 :
416 : while (true)
417 : {
418 205 : auto poObject = GetNextObject(bLooseIdentification);
419 205 : if (!poObject)
420 43 : break;
421 162 : const auto eObjectType = OGRGeoJSONGetType(poObject);
422 162 : if (bEstablishLayerDefn && eObjectType == GeoJSONObject::eFeature)
423 : {
424 151 : m_oReader.GenerateFeatureDefn(oMapFieldNameToIdx, apoFieldDefn, dag,
425 : this, poObject);
426 : }
427 162 : json_object_put(poObject);
428 162 : if (!bEstablishLayerDefn)
429 : {
430 6 : bOK = (eObjectType == GeoJSONObject::eFeature);
431 6 : break;
432 : }
433 156 : m_nTotalFeatures++;
434 156 : }
435 :
436 49 : if (bEstablishLayerDefn)
437 : {
438 : // CPLDebug("GEOJSONSEQ", "Establish layer definition");
439 :
440 86 : const auto sortedFields = dag.getTopologicalOrdering();
441 43 : CPLAssert(sortedFields.size() == apoFieldDefn.size());
442 158 : for (int idx : sortedFields)
443 : {
444 115 : m_poFeatureDefn->AddFieldDefn(apoFieldDefn[idx].get());
445 : }
446 43 : m_poFeatureDefn->Seal(true);
447 43 : m_oReader.FinalizeLayerDefn(this, m_osFIDColumn);
448 : }
449 :
450 49 : ResetReading();
451 :
452 49 : m_nFileSize = 0;
453 49 : m_nIter = 0;
454 :
455 98 : return bOK || m_nTotalFeatures > 0;
456 : }
457 :
458 : /************************************************************************/
459 : /* ResetReading() */
460 : /************************************************************************/
461 :
462 218 : void OGRGeoJSONSeqLayer::ResetReading()
463 : {
464 436 : if (!m_poDS->m_bSupportsRead ||
465 218 : (m_bWriteOnlyLayer && m_poDS->m_apoLayers.size() > 1))
466 : {
467 0 : return;
468 : }
469 :
470 218 : m_poDS->m_bAtEOF = false;
471 218 : VSIFSeekL(m_poDS->m_fp, 0, SEEK_SET);
472 : // Undocumented: for testing purposes only
473 218 : const size_t nBufferSize = static_cast<size_t>(std::max(
474 218 : 1, atoi(CPLGetConfigOption("OGR_GEOJSONSEQ_CHUNK_SIZE", "40960"))));
475 218 : const size_t nBufferSizeValidated =
476 : nBufferSize > static_cast<size_t>(100 * 1000 * 1000)
477 : ? static_cast<size_t>(100 * 1000 * 1000)
478 : : nBufferSize;
479 218 : m_osBuffer.resize(nBufferSizeValidated);
480 218 : m_osFeatureBuffer.clear();
481 218 : m_nPosInBuffer = nBufferSizeValidated;
482 218 : m_nBufferValidSize = nBufferSizeValidated;
483 218 : m_nNextFID = 0;
484 : }
485 :
486 : /************************************************************************/
487 : /* GetNextObject() */
488 : /************************************************************************/
489 :
490 394 : json_object *OGRGeoJSONSeqLayer::GetNextObject(bool bLooseIdentification)
491 : {
492 394 : m_osFeatureBuffer.clear();
493 : while (true)
494 : {
495 : // If we read all the buffer, then reload it from file
496 450 : if (m_nPosInBuffer >= m_nBufferValidSize)
497 : {
498 264 : if (m_nBufferValidSize < m_osBuffer.size())
499 : {
500 89 : return nullptr;
501 : }
502 175 : m_nBufferValidSize =
503 175 : VSIFReadL(&m_osBuffer[0], 1, m_osBuffer.size(), m_poDS->m_fp);
504 175 : m_nPosInBuffer = 0;
505 302 : if (VSIFTellL(m_poDS->m_fp) == m_nBufferValidSize &&
506 127 : m_nBufferValidSize > 0)
507 : {
508 127 : m_poDS->m_bIsRSSeparated = (m_osBuffer[0] == RS);
509 127 : if (m_poDS->m_bIsRSSeparated)
510 : {
511 26 : m_nPosInBuffer++;
512 : }
513 : }
514 175 : m_nIter++;
515 :
516 221 : if (m_nFileSize > 0 && (m_nBufferValidSize < m_osBuffer.size() ||
517 46 : (m_nIter % 100) == 0))
518 : {
519 48 : CPLDebug("GeoJSONSeq", "First pass: %.2f %%",
520 48 : 100.0 * VSIFTellL(m_poDS->m_fp) / m_nFileSize);
521 : }
522 175 : if (m_nPosInBuffer >= m_nBufferValidSize)
523 : {
524 0 : return nullptr;
525 : }
526 : }
527 :
528 : // Find next feature separator in buffer
529 361 : const size_t nNextSepPos = m_osBuffer.find(
530 361 : m_poDS->m_bIsRSSeparated ? RS : '\n', m_nPosInBuffer);
531 361 : if (nNextSepPos != std::string::npos)
532 : {
533 570 : m_osFeatureBuffer.append(m_osBuffer.data() + m_nPosInBuffer,
534 285 : nNextSepPos - m_nPosInBuffer);
535 285 : m_nPosInBuffer = nNextSepPos + 1;
536 : }
537 : else
538 : {
539 : // No separator ? then accummulate
540 152 : m_osFeatureBuffer.append(m_osBuffer.data() + m_nPosInBuffer,
541 76 : m_nBufferValidSize - m_nPosInBuffer);
542 145 : if (m_nMaxObjectSize > 0 &&
543 69 : m_osFeatureBuffer.size() > m_nMaxObjectSize)
544 : {
545 1 : CPLError(CE_Failure, CPLE_NotSupported,
546 : "Too large feature. You may define the "
547 : "OGR_GEOJSON_MAX_OBJ_SIZE configuration option to "
548 : "a value in megabytes (larger than %u) to allow "
549 : "for larger features, or 0 to remove any size limit.",
550 1 : static_cast<unsigned>(m_osFeatureBuffer.size() / 1024 /
551 : 1024));
552 1 : return nullptr;
553 : }
554 75 : m_nPosInBuffer = m_nBufferValidSize;
555 75 : if (m_nBufferValidSize == m_osBuffer.size())
556 : {
557 48 : continue;
558 : }
559 : }
560 :
561 762 : while (!m_osFeatureBuffer.empty() &&
562 380 : (m_osFeatureBuffer.back() == '\r' ||
563 380 : m_osFeatureBuffer.back() == '\n'))
564 : {
565 70 : m_osFeatureBuffer.pop_back();
566 : }
567 312 : if (!m_osFeatureBuffer.empty())
568 : {
569 310 : json_object *poObject = nullptr;
570 310 : CPL_IGNORE_RET_VAL(
571 310 : OGRJSonParse(m_osFeatureBuffer.c_str(), &poObject));
572 310 : m_osFeatureBuffer.clear();
573 310 : if (json_object_get_type(poObject) == json_type_object)
574 : {
575 304 : return poObject;
576 : }
577 6 : json_object_put(poObject);
578 6 : if (bLooseIdentification)
579 : {
580 0 : return nullptr;
581 : }
582 : }
583 56 : }
584 : }
585 :
586 : /************************************************************************/
587 : /* GetNextFeature() */
588 : /************************************************************************/
589 :
590 169 : OGRFeature *OGRGeoJSONSeqLayer::GetNextFeature()
591 : {
592 169 : if (!m_poDS->m_bSupportsRead)
593 : {
594 0 : return nullptr;
595 : }
596 169 : if (m_bWriteOnlyLayer && m_poDS->m_apoLayers.size() > 1)
597 : {
598 0 : CPLError(CE_Failure, CPLE_NotSupported,
599 : "GetNextFeature() not supported when appending a new layer");
600 0 : return nullptr;
601 : }
602 :
603 169 : GetLayerDefn(); // force scan if not already done
604 : while (true)
605 : {
606 189 : auto poObject = GetNextObject(false);
607 189 : if (!poObject)
608 47 : return nullptr;
609 : OGRFeature *poFeature;
610 142 : auto type = OGRGeoJSONGetType(poObject);
611 142 : if (type == GeoJSONObject::eFeature)
612 : {
613 138 : poFeature = m_oReader.ReadFeature(this, poObject,
614 : m_osFeatureBuffer.c_str());
615 138 : json_object_put(poObject);
616 : }
617 4 : else if (type == GeoJSONObject::eFeatureCollection ||
618 : type == GeoJSONObject::eUnknown)
619 : {
620 0 : json_object_put(poObject);
621 0 : continue;
622 : }
623 : else
624 : {
625 : OGRGeometry *poGeom =
626 4 : m_oReader.ReadGeometry(poObject, GetSpatialRef());
627 4 : json_object_put(poObject);
628 4 : if (!poGeom)
629 : {
630 0 : continue;
631 : }
632 4 : poFeature = new OGRFeature(m_poFeatureDefn);
633 4 : poFeature->SetGeometryDirectly(poGeom);
634 : }
635 :
636 142 : if (poFeature->GetFID() == OGRNullFID)
637 : {
638 142 : poFeature->SetFID(m_nNextFID);
639 142 : m_nNextFID++;
640 : }
641 306 : if ((m_poFilterGeom == nullptr ||
642 276 : FilterGeometry(poFeature->GetGeomFieldRef(m_iGeomFieldFilter))) &&
643 134 : (m_poAttrQuery == nullptr || m_poAttrQuery->Evaluate(poFeature)))
644 : {
645 122 : return poFeature;
646 : }
647 20 : delete poFeature;
648 20 : }
649 : }
650 :
651 : /************************************************************************/
652 : /* GetFeatureCount() */
653 : /************************************************************************/
654 :
655 32 : GIntBig OGRGeoJSONSeqLayer::GetFeatureCount(int bForce)
656 : {
657 32 : if (m_poFilterGeom == nullptr && m_poAttrQuery == nullptr)
658 : {
659 26 : GetLayerDefn(); // force scan if not already done
660 26 : return m_nTotalFeatures;
661 : }
662 6 : return OGRLayer::GetFeatureCount(bForce);
663 : }
664 :
665 : /************************************************************************/
666 : /* TestCapability() */
667 : /************************************************************************/
668 :
669 186 : int OGRGeoJSONSeqLayer::TestCapability(const char *pszCap) const
670 : {
671 186 : if (EQUAL(pszCap, OLCStringsAsUTF8))
672 13 : return true;
673 173 : if (m_poFilterGeom == nullptr && m_poAttrQuery == nullptr &&
674 173 : EQUAL(pszCap, OLCFastFeatureCount))
675 : {
676 0 : return true;
677 : }
678 173 : if (EQUAL(pszCap, OLCCreateField) || EQUAL(pszCap, OLCSequentialWrite))
679 : {
680 47 : return m_poDS->GetAccess() == GA_Update;
681 : }
682 :
683 126 : return false;
684 : }
685 :
686 : /************************************************************************/
687 : /* ICreateFeature() */
688 : /************************************************************************/
689 :
690 106 : OGRErr OGRGeoJSONSeqLayer::ICreateFeature(OGRFeature *poFeature)
691 : {
692 106 : if (m_poDS->GetAccess() != GA_Update)
693 3 : return OGRERR_FAILURE;
694 :
695 103 : if (!m_poDS->m_bAtEOF)
696 : {
697 50 : m_poDS->m_bAtEOF = true;
698 50 : VSIFSeekL(m_poDS->m_fp, 0, SEEK_END);
699 : }
700 :
701 103 : std::unique_ptr<OGRFeature> poFeatureToWrite;
702 103 : if (m_poCT != nullptr)
703 : {
704 3 : poFeatureToWrite.reset(new OGRFeature(m_poFeatureDefn));
705 3 : poFeatureToWrite->SetFrom(poFeature);
706 3 : poFeatureToWrite->SetFID(poFeature->GetFID());
707 3 : OGRGeometry *poGeometry = poFeatureToWrite->GetGeometryRef();
708 3 : if (poGeometry)
709 : {
710 3 : const char *const apszOptions[] = {"WRAPDATELINE=YES", nullptr};
711 3 : OGRGeometry *poNewGeom = OGRGeometryFactory::transformWithOptions(
712 : poGeometry, m_poCT.get(), const_cast<char **>(apszOptions),
713 3 : m_oTransformCache);
714 3 : if (poNewGeom == nullptr)
715 : {
716 0 : return OGRERR_FAILURE;
717 : }
718 :
719 3 : OGREnvelope sEnvelope;
720 3 : poNewGeom->getEnvelope(&sEnvelope);
721 3 : if (sEnvelope.MinX < -180.0 || sEnvelope.MaxX > 180.0 ||
722 3 : sEnvelope.MinY < -90.0 || sEnvelope.MaxY > 90.0)
723 : {
724 0 : CPLError(CE_Failure, CPLE_AppDefined,
725 : "Geometry extent outside of "
726 : "[-180.0,180.0]x[-90.0,90.0] bounds");
727 0 : return OGRERR_FAILURE;
728 : }
729 :
730 3 : poFeatureToWrite->SetGeometryDirectly(poNewGeom);
731 : }
732 : }
733 :
734 103 : ++m_nTotalFeatures;
735 :
736 106 : json_object *poObj = OGRGeoJSONWriteFeature(
737 3 : poFeatureToWrite.get() ? poFeatureToWrite.get() : poFeature,
738 103 : m_oWriteOptions);
739 103 : CPLAssert(nullptr != poObj);
740 :
741 103 : const char *pszJson = json_object_to_json_string(poObj);
742 :
743 103 : char chEOL = '\n';
744 103 : OGRErr eErr = OGRERR_NONE;
745 216 : if ((m_poDS->m_bIsRSSeparated &&
746 10 : VSIFWriteL(&RS, 1, 1, m_poDS->m_fp) != 1) ||
747 216 : VSIFWriteL(pszJson, strlen(pszJson), 1, m_poDS->m_fp) != 1 ||
748 103 : VSIFWriteL(&chEOL, 1, 1, m_poDS->m_fp) != 1)
749 : {
750 0 : CPLError(CE_Failure, CPLE_FileIO, "Cannot write feature");
751 0 : eErr = OGRERR_FAILURE;
752 : }
753 :
754 103 : json_object_put(poObj);
755 :
756 103 : return eErr;
757 : }
758 :
759 : /************************************************************************/
760 : /* CreateField() */
761 : /************************************************************************/
762 :
763 111 : OGRErr OGRGeoJSONSeqLayer::CreateField(const OGRFieldDefn *poField,
764 : int /* bApproxOK */)
765 : {
766 111 : if (m_poDS->GetAccess() != GA_Update)
767 3 : return OGRERR_FAILURE;
768 108 : m_poFeatureDefn->AddFieldDefn(poField);
769 108 : return OGRERR_NONE;
770 : }
771 :
772 : /************************************************************************/
773 : /* Open() */
774 : /************************************************************************/
775 :
776 55 : bool OGRGeoJSONSeqDataSource::Open(GDALOpenInfo *poOpenInfo,
777 : GeoJSONSourceType nSrcType)
778 : {
779 55 : CPLAssert(nullptr == m_fp);
780 :
781 110 : CPLString osLayerName("GeoJSONSeq");
782 :
783 55 : const char *pszUnprefixedFilename = poOpenInfo->pszFilename;
784 55 : if (STARTS_WITH_CI(poOpenInfo->pszFilename, "GeoJSONSeq:"))
785 : {
786 1 : pszUnprefixedFilename = poOpenInfo->pszFilename + strlen("GeoJSONSeq:");
787 : }
788 :
789 55 : if (nSrcType == eGeoJSONSourceFile)
790 : {
791 43 : if (pszUnprefixedFilename != poOpenInfo->pszFilename)
792 : {
793 1 : osLayerName = CPLGetBasenameSafe(pszUnprefixedFilename);
794 1 : m_fp = VSIFOpenL(pszUnprefixedFilename,
795 1 : poOpenInfo->eAccess == GA_Update ? "rb+" : "rb");
796 : }
797 : else
798 : {
799 42 : osLayerName = CPLGetBasenameSafe(poOpenInfo->pszFilename);
800 42 : std::swap(m_fp, poOpenInfo->fpL);
801 : }
802 : }
803 12 : else if (nSrcType == eGeoJSONSourceText)
804 : {
805 3 : if (poOpenInfo->eAccess == GA_Update)
806 0 : return false;
807 :
808 3 : m_osTmpFile = VSIMemGenerateHiddenFilename("geojsonseq");
809 3 : m_fp = VSIFileFromMemBuffer(
810 : m_osTmpFile.c_str(),
811 3 : reinterpret_cast<GByte *>(CPLStrdup(poOpenInfo->pszFilename)),
812 3 : strlen(poOpenInfo->pszFilename), true);
813 : }
814 9 : else if (nSrcType == eGeoJSONSourceService)
815 : {
816 9 : if (poOpenInfo->eAccess == GA_Update)
817 0 : return false;
818 :
819 : char *pszStoredContent =
820 9 : OGRGeoJSONDriverStealStoredContent(pszUnprefixedFilename);
821 9 : if (pszStoredContent)
822 : {
823 9 : if (EQUAL(pszStoredContent, INVALID_CONTENT_FOR_JSON_LIKE) ||
824 0 : !GeoJSONSeqIsObject(pszStoredContent, poOpenInfo))
825 : {
826 9 : OGRGeoJSONDriverStoreContent(poOpenInfo->pszFilename,
827 : pszStoredContent);
828 9 : return false;
829 : }
830 : else
831 : {
832 0 : m_osTmpFile = VSIMemGenerateHiddenFilename("geojsonseq");
833 0 : m_fp = VSIFileFromMemBuffer(
834 : m_osTmpFile.c_str(),
835 : reinterpret_cast<GByte *>(pszStoredContent),
836 0 : strlen(pszStoredContent), true);
837 : }
838 : }
839 : else
840 : {
841 : CPLHTTPResult *pResult =
842 0 : GeoJSONHTTPFetchWithContentTypeHeader(pszUnprefixedFilename);
843 0 : if (!pResult)
844 : {
845 0 : return FALSE;
846 : }
847 :
848 0 : m_osTmpFile = VSIMemGenerateHiddenFilename("geojsonseq");
849 0 : m_fp = VSIFileFromMemBuffer(m_osTmpFile.c_str(), pResult->pabyData,
850 0 : pResult->nDataLen, true);
851 0 : pResult->pabyData = nullptr;
852 0 : pResult->nDataLen = 0;
853 0 : CPLHTTPDestroyResult(pResult);
854 : }
855 : }
856 46 : if (m_fp == nullptr)
857 : {
858 0 : return false;
859 : }
860 46 : SetDescription(poOpenInfo->pszFilename);
861 46 : auto poLayer = new OGRGeoJSONSeqLayer(this, osLayerName.c_str());
862 46 : const bool bLooseIdentification =
863 46 : nSrcType == eGeoJSONSourceService &&
864 0 : !STARTS_WITH_CI(poOpenInfo->pszFilename, "GeoJSONSeq:");
865 46 : if (bLooseIdentification)
866 : {
867 0 : CPLPushErrorHandler(CPLQuietErrorHandler);
868 : }
869 46 : const bool bEstablishLayerDefn = poOpenInfo->eAccess != GA_Update;
870 46 : auto ret = poLayer->Init(bLooseIdentification, bEstablishLayerDefn);
871 46 : if (bLooseIdentification)
872 : {
873 0 : CPLPopErrorHandler();
874 0 : CPLErrorReset();
875 : }
876 46 : if (!ret)
877 : {
878 1 : delete poLayer;
879 1 : return false;
880 : }
881 45 : m_apoLayers.emplace_back(std::move(poLayer));
882 45 : eAccess = poOpenInfo->eAccess;
883 45 : return true;
884 : }
885 :
886 : /************************************************************************/
887 : /* Create() */
888 : /************************************************************************/
889 :
890 44 : bool OGRGeoJSONSeqDataSource::Create(const char *pszName,
891 : char ** /* papszOptions */)
892 : {
893 44 : CPLAssert(nullptr == m_fp);
894 :
895 44 : if (strcmp(pszName, "/dev/stdout") == 0)
896 0 : pszName = "/vsistdout/";
897 :
898 : /* -------------------------------------------------------------------- */
899 : /* Create the output file. */
900 : /* -------------------------------------------------------------------- */
901 44 : m_bSupportsRead =
902 87 : VSIFileManager::GetHandler(pszName)->SupportsRead(pszName) &&
903 86 : VSIFileManager::GetHandler(pszName)->SupportsRandomWrite(pszName,
904 43 : false);
905 44 : m_bAtEOF = !m_bSupportsRead;
906 44 : m_fp = VSIFOpenExL(pszName, m_bSupportsRead ? "wb+" : "wb", true);
907 44 : if (nullptr == m_fp)
908 : {
909 1 : CPLError(CE_Failure, CPLE_OpenFailed, "Failed to create %s: %s",
910 : pszName, VSIGetLastErrorMsg());
911 1 : return false;
912 : }
913 :
914 43 : eAccess = GA_Update;
915 :
916 43 : m_bIsRSSeparated = EQUAL(CPLGetExtensionSafe(pszName).c_str(), "GEOJSONS");
917 :
918 43 : return true;
919 : }
920 :
921 : /************************************************************************/
922 : /* OGRGeoJSONSeqDriverIdentify() */
923 : /************************************************************************/
924 :
925 54754 : static int OGRGeoJSONSeqDriverIdentifyInternal(GDALOpenInfo *poOpenInfo,
926 : GeoJSONSourceType &nSrcType)
927 : {
928 54754 : nSrcType = GeoJSONSeqGetSourceType(poOpenInfo);
929 54754 : if (nSrcType == eGeoJSONSourceUnknown)
930 54635 : return FALSE;
931 119 : if (nSrcType == eGeoJSONSourceService)
932 : {
933 27 : if (poOpenInfo->IsSingleAllowedDriver("GeoJSONSeq"))
934 1 : return TRUE;
935 26 : if (!STARTS_WITH_CI(poOpenInfo->pszFilename, "GeoJSONSeq:"))
936 : {
937 26 : return -1;
938 : }
939 : }
940 92 : return TRUE;
941 : }
942 :
943 : /************************************************************************/
944 : /* OGRGeoJSONSeqDriverIdentify() */
945 : /************************************************************************/
946 :
947 54699 : static int OGRGeoJSONSeqDriverIdentify(GDALOpenInfo *poOpenInfo)
948 : {
949 : GeoJSONSourceType nSrcType;
950 109398 : return OGRGeoJSONSeqDriverIdentifyInternal(poOpenInfo, nSrcType);
951 : }
952 :
953 : /************************************************************************/
954 : /* Open() */
955 : /************************************************************************/
956 :
957 55 : static GDALDataset *OGRGeoJSONSeqDriverOpen(GDALOpenInfo *poOpenInfo)
958 : {
959 : GeoJSONSourceType nSrcType;
960 55 : if (OGRGeoJSONSeqDriverIdentifyInternal(poOpenInfo, nSrcType) == FALSE)
961 : {
962 0 : return nullptr;
963 : }
964 :
965 55 : OGRGeoJSONSeqDataSource *poDS = new OGRGeoJSONSeqDataSource();
966 :
967 55 : if (!poDS->Open(poOpenInfo, nSrcType))
968 : {
969 10 : delete poDS;
970 10 : poDS = nullptr;
971 : }
972 :
973 55 : return poDS;
974 : }
975 :
976 : /************************************************************************/
977 : /* Create() */
978 : /************************************************************************/
979 :
980 : static GDALDataset *
981 44 : OGRGeoJSONSeqDriverCreate(const char *pszName, int /* nBands */,
982 : int /* nXSize */, int /* nYSize */,
983 : GDALDataType /* eDT */, char **papszOptions)
984 : {
985 44 : OGRGeoJSONSeqDataSource *poDS = new OGRGeoJSONSeqDataSource();
986 :
987 44 : if (!poDS->Create(pszName, papszOptions))
988 : {
989 1 : delete poDS;
990 1 : poDS = nullptr;
991 : }
992 :
993 44 : return poDS;
994 : }
995 :
996 : /************************************************************************/
997 : /* RegisterOGRGeoJSONSeq() */
998 : /************************************************************************/
999 :
1000 2024 : void RegisterOGRGeoJSONSeq()
1001 : {
1002 2024 : if (GDALGetDriverByName("GeoJSONSeq") != nullptr)
1003 283 : return;
1004 :
1005 1741 : GDALDriver *poDriver = new GDALDriver();
1006 :
1007 1741 : poDriver->SetDescription("GeoJSONSeq");
1008 1741 : poDriver->SetMetadataItem(GDAL_DCAP_VECTOR, "YES");
1009 1741 : poDriver->SetMetadataItem(GDAL_DCAP_CREATE_LAYER, "YES");
1010 1741 : poDriver->SetMetadataItem(GDAL_DCAP_CREATE_FIELD, "YES");
1011 1741 : poDriver->SetMetadataItem(GDAL_DCAP_Z_GEOMETRIES, "YES");
1012 1741 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "GeoJSON Sequence");
1013 1741 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSIONS, "geojsonl geojsons");
1014 1741 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC,
1015 1741 : "drivers/vector/geojsonseq.html");
1016 :
1017 1741 : poDriver->SetMetadataItem(
1018 : GDAL_DS_LAYER_CREATIONOPTIONLIST,
1019 : "<LayerCreationOptionList>"
1020 : " <Option name='RS' type='boolean' description='whether to prefix "
1021 : "records with RS=0x1e character' default='NO'/>"
1022 : " <Option name='COORDINATE_PRECISION' type='int' description='Number "
1023 : "of decimal for coordinates. Default is 7'/>"
1024 : " <Option name='SIGNIFICANT_FIGURES' type='int' description='Number "
1025 : "of significant figures for floating-point values' default='17'/>"
1026 : " <Option name='ID_FIELD' type='string' description='Name of the "
1027 : "source field that must be used as the id member of Feature features'/>"
1028 : " <Option name='ID_TYPE' type='string-select' description='Type of "
1029 : "the id member of Feature features'>"
1030 : " <Value>AUTO</Value>"
1031 : " <Value>String</Value>"
1032 : " <Value>Integer</Value>"
1033 : " </Option>"
1034 : " <Option name='WRITE_BBOX' type='boolean' description='whether to "
1035 : "write a bbox property with the bounding box of each geometry' "
1036 : "default='NO'/>"
1037 1741 : "</LayerCreationOptionList>");
1038 :
1039 1741 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
1040 1741 : poDriver->SetMetadataItem(GDAL_DMD_CREATIONFIELDDATATYPES,
1041 : "Integer Integer64 Real String IntegerList "
1042 1741 : "Integer64List RealList StringList");
1043 1741 : poDriver->SetMetadataItem(GDAL_DMD_CREATIONFIELDDATASUBTYPES, "Boolean");
1044 1741 : poDriver->SetMetadataItem(GDAL_DMD_SUPPORTED_SQL_DIALECTS, "OGRSQL SQLITE");
1045 1741 : poDriver->SetMetadataItem(GDAL_DCAP_HONOR_GEOM_COORDINATE_PRECISION, "YES");
1046 1741 : poDriver->SetMetadataItem(GDAL_DCAP_APPEND, "YES");
1047 :
1048 1741 : poDriver->pfnOpen = OGRGeoJSONSeqDriverOpen;
1049 1741 : poDriver->pfnIdentify = OGRGeoJSONSeqDriverIdentify;
1050 1741 : poDriver->pfnCreate = OGRGeoJSONSeqDriverCreate;
1051 :
1052 1741 : GetGDALDriverManager()->RegisterDriver(poDriver);
1053 : }
|