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();
47 :
48 76 : int GetLayerCount() override
49 : {
50 76 : return static_cast<int>(m_apoLayers.size());
51 : }
52 :
53 : OGRLayer *GetLayer(int) override;
54 : OGRLayer *ICreateLayer(const char *pszName,
55 : const OGRGeomFieldDefn *poGeomFieldDefn,
56 : CSLConstList papszOptions) override;
57 : int TestCapability(const char *pszCap) 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();
104 :
105 : bool Init(bool bLooseIdentification, bool bEstablishLayerDefn);
106 :
107 61 : const char *GetName() override
108 : {
109 61 : return GetDescription();
110 : }
111 :
112 : void ResetReading() override;
113 : OGRFeature *GetNextFeature() override;
114 : OGRFeatureDefn *GetLayerDefn() override;
115 :
116 30 : const char *GetFIDColumn() override
117 : {
118 30 : return m_osFIDColumn.c_str();
119 : }
120 :
121 : GIntBig GetFeatureCount(int) override;
122 : int TestCapability(const char *) 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 : OGRLayer *OGRGeoJSONSeqDataSource::GetLayer(int nIndex)
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)
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 1306 : OGRFeatureDefn *OGRGeoJSONSeqLayer::GetLayerDefn()
380 : {
381 1306 : if (!m_bLayerDefnEstablished)
382 : {
383 3 : Init(/* bLooseIdentification = */ false,
384 : /* bEstablishLayerDefn = */ true);
385 : }
386 1306 : return m_poFeatureDefn;
387 : }
388 :
389 : /************************************************************************/
390 : /* Init() */
391 : /************************************************************************/
392 :
393 49 : bool OGRGeoJSONSeqLayer::Init(bool bLooseIdentification,
394 : bool bEstablishLayerDefn)
395 : {
396 55 : if (STARTS_WITH(m_poDS->GetDescription(), "/vsimem/") ||
397 6 : !STARTS_WITH(m_poDS->GetDescription(), "/vsi"))
398 : {
399 49 : VSIFSeekL(m_poDS->m_fp, 0, SEEK_END);
400 49 : m_nFileSize = VSIFTellL(m_poDS->m_fp);
401 : }
402 :
403 : // Set m_bLayerDefnEstablished = true early to avoid infinite recursive
404 : // calls.
405 49 : if (bEstablishLayerDefn)
406 43 : m_bLayerDefnEstablished = true;
407 :
408 49 : ResetReading();
409 :
410 98 : std::map<std::string, int> oMapFieldNameToIdx;
411 98 : std::vector<std::unique_ptr<OGRFieldDefn>> apoFieldDefn;
412 49 : gdal::DirectedAcyclicGraph<int, std::string> dag;
413 49 : bool bOK = false;
414 :
415 : while (true)
416 : {
417 205 : auto poObject = GetNextObject(bLooseIdentification);
418 205 : if (!poObject)
419 43 : break;
420 162 : const auto eObjectType = OGRGeoJSONGetType(poObject);
421 162 : if (bEstablishLayerDefn && eObjectType == GeoJSONObject::eFeature)
422 : {
423 151 : m_oReader.GenerateFeatureDefn(oMapFieldNameToIdx, apoFieldDefn, dag,
424 : this, poObject);
425 : }
426 162 : json_object_put(poObject);
427 162 : if (!bEstablishLayerDefn)
428 : {
429 6 : bOK = (eObjectType == GeoJSONObject::eFeature);
430 6 : break;
431 : }
432 156 : m_nTotalFeatures++;
433 156 : }
434 :
435 49 : if (bEstablishLayerDefn)
436 : {
437 : // CPLDebug("GEOJSONSEQ", "Establish layer definition");
438 :
439 86 : const auto sortedFields = dag.getTopologicalOrdering();
440 43 : CPLAssert(sortedFields.size() == apoFieldDefn.size());
441 158 : for (int idx : sortedFields)
442 : {
443 115 : m_poFeatureDefn->AddFieldDefn(apoFieldDefn[idx].get());
444 : }
445 43 : m_poFeatureDefn->Seal(true);
446 43 : m_oReader.FinalizeLayerDefn(this, m_osFIDColumn);
447 : }
448 :
449 49 : ResetReading();
450 :
451 49 : m_nFileSize = 0;
452 49 : m_nIter = 0;
453 :
454 98 : return bOK || m_nTotalFeatures > 0;
455 : }
456 :
457 : /************************************************************************/
458 : /* ResetReading() */
459 : /************************************************************************/
460 :
461 216 : void OGRGeoJSONSeqLayer::ResetReading()
462 : {
463 432 : if (!m_poDS->m_bSupportsRead ||
464 216 : (m_bWriteOnlyLayer && m_poDS->m_apoLayers.size() > 1))
465 : {
466 0 : return;
467 : }
468 :
469 216 : m_poDS->m_bAtEOF = false;
470 216 : VSIFSeekL(m_poDS->m_fp, 0, SEEK_SET);
471 : // Undocumented: for testing purposes only
472 216 : const size_t nBufferSize = static_cast<size_t>(std::max(
473 216 : 1, atoi(CPLGetConfigOption("OGR_GEOJSONSEQ_CHUNK_SIZE", "40960"))));
474 216 : const size_t nBufferSizeValidated =
475 : nBufferSize > static_cast<size_t>(100 * 1000 * 1000)
476 : ? static_cast<size_t>(100 * 1000 * 1000)
477 : : nBufferSize;
478 216 : m_osBuffer.resize(nBufferSizeValidated);
479 216 : m_osFeatureBuffer.clear();
480 216 : m_nPosInBuffer = nBufferSizeValidated;
481 216 : m_nBufferValidSize = nBufferSizeValidated;
482 216 : m_nNextFID = 0;
483 : }
484 :
485 : /************************************************************************/
486 : /* GetNextObject() */
487 : /************************************************************************/
488 :
489 388 : json_object *OGRGeoJSONSeqLayer::GetNextObject(bool bLooseIdentification)
490 : {
491 388 : m_osFeatureBuffer.clear();
492 : while (true)
493 : {
494 : // If we read all the buffer, then reload it from file
495 444 : if (m_nPosInBuffer >= m_nBufferValidSize)
496 : {
497 259 : if (m_nBufferValidSize < m_osBuffer.size())
498 : {
499 86 : return nullptr;
500 : }
501 173 : m_nBufferValidSize =
502 173 : VSIFReadL(&m_osBuffer[0], 1, m_osBuffer.size(), m_poDS->m_fp);
503 173 : m_nPosInBuffer = 0;
504 298 : if (VSIFTellL(m_poDS->m_fp) == m_nBufferValidSize &&
505 125 : m_nBufferValidSize > 0)
506 : {
507 125 : m_poDS->m_bIsRSSeparated = (m_osBuffer[0] == RS);
508 125 : if (m_poDS->m_bIsRSSeparated)
509 : {
510 26 : m_nPosInBuffer++;
511 : }
512 : }
513 173 : m_nIter++;
514 :
515 219 : if (m_nFileSize > 0 && (m_nBufferValidSize < m_osBuffer.size() ||
516 46 : (m_nIter % 100) == 0))
517 : {
518 48 : CPLDebug("GeoJSONSeq", "First pass: %.2f %%",
519 48 : 100.0 * VSIFTellL(m_poDS->m_fp) / m_nFileSize);
520 : }
521 173 : if (m_nPosInBuffer >= m_nBufferValidSize)
522 : {
523 0 : return nullptr;
524 : }
525 : }
526 :
527 : // Find next feature separator in buffer
528 358 : const size_t nNextSepPos = m_osBuffer.find(
529 358 : m_poDS->m_bIsRSSeparated ? RS : '\n', m_nPosInBuffer);
530 358 : if (nNextSepPos != std::string::npos)
531 : {
532 564 : m_osFeatureBuffer.append(m_osBuffer.data() + m_nPosInBuffer,
533 282 : nNextSepPos - m_nPosInBuffer);
534 282 : m_nPosInBuffer = nNextSepPos + 1;
535 : }
536 : else
537 : {
538 : // No separator ? then accummulate
539 152 : m_osFeatureBuffer.append(m_osBuffer.data() + m_nPosInBuffer,
540 76 : m_nBufferValidSize - m_nPosInBuffer);
541 145 : if (m_nMaxObjectSize > 0 &&
542 69 : m_osFeatureBuffer.size() > m_nMaxObjectSize)
543 : {
544 1 : CPLError(CE_Failure, CPLE_NotSupported,
545 : "Too large feature. You may define the "
546 : "OGR_GEOJSON_MAX_OBJ_SIZE configuration option to "
547 : "a value in megabytes (larger than %u) to allow "
548 : "for larger features, or 0 to remove any size limit.",
549 1 : static_cast<unsigned>(m_osFeatureBuffer.size() / 1024 /
550 : 1024));
551 1 : return nullptr;
552 : }
553 75 : m_nPosInBuffer = m_nBufferValidSize;
554 75 : if (m_nBufferValidSize == m_osBuffer.size())
555 : {
556 48 : continue;
557 : }
558 : }
559 :
560 756 : while (!m_osFeatureBuffer.empty() &&
561 377 : (m_osFeatureBuffer.back() == '\r' ||
562 377 : m_osFeatureBuffer.back() == '\n'))
563 : {
564 70 : m_osFeatureBuffer.pop_back();
565 : }
566 309 : if (!m_osFeatureBuffer.empty())
567 : {
568 307 : json_object *poObject = nullptr;
569 307 : CPL_IGNORE_RET_VAL(
570 307 : OGRJSonParse(m_osFeatureBuffer.c_str(), &poObject));
571 307 : m_osFeatureBuffer.clear();
572 307 : if (json_object_get_type(poObject) == json_type_object)
573 : {
574 301 : return poObject;
575 : }
576 6 : json_object_put(poObject);
577 6 : if (bLooseIdentification)
578 : {
579 0 : return nullptr;
580 : }
581 : }
582 56 : }
583 : }
584 :
585 : /************************************************************************/
586 : /* GetNextFeature() */
587 : /************************************************************************/
588 :
589 163 : OGRFeature *OGRGeoJSONSeqLayer::GetNextFeature()
590 : {
591 163 : if (!m_poDS->m_bSupportsRead)
592 : {
593 0 : return nullptr;
594 : }
595 163 : if (m_bWriteOnlyLayer && m_poDS->m_apoLayers.size() > 1)
596 : {
597 0 : CPLError(CE_Failure, CPLE_NotSupported,
598 : "GetNextFeature() not supported when appending a new layer");
599 0 : return nullptr;
600 : }
601 :
602 163 : GetLayerDefn(); // force scan if not already done
603 : while (true)
604 : {
605 183 : auto poObject = GetNextObject(false);
606 183 : if (!poObject)
607 44 : return nullptr;
608 : OGRFeature *poFeature;
609 139 : auto type = OGRGeoJSONGetType(poObject);
610 139 : if (type == GeoJSONObject::eFeature)
611 : {
612 135 : poFeature = m_oReader.ReadFeature(this, poObject,
613 : m_osFeatureBuffer.c_str());
614 135 : json_object_put(poObject);
615 : }
616 4 : else if (type == GeoJSONObject::eFeatureCollection ||
617 : type == GeoJSONObject::eUnknown)
618 : {
619 0 : json_object_put(poObject);
620 0 : continue;
621 : }
622 : else
623 : {
624 : OGRGeometry *poGeom =
625 4 : m_oReader.ReadGeometry(poObject, GetSpatialRef());
626 4 : json_object_put(poObject);
627 4 : if (!poGeom)
628 : {
629 0 : continue;
630 : }
631 4 : poFeature = new OGRFeature(m_poFeatureDefn);
632 4 : poFeature->SetGeometryDirectly(poGeom);
633 : }
634 :
635 139 : if (poFeature->GetFID() == OGRNullFID)
636 : {
637 139 : poFeature->SetFID(m_nNextFID);
638 139 : m_nNextFID++;
639 : }
640 300 : if ((m_poFilterGeom == nullptr ||
641 270 : FilterGeometry(poFeature->GetGeomFieldRef(m_iGeomFieldFilter))) &&
642 131 : (m_poAttrQuery == nullptr || m_poAttrQuery->Evaluate(poFeature)))
643 : {
644 119 : return poFeature;
645 : }
646 20 : delete poFeature;
647 20 : }
648 : }
649 :
650 : /************************************************************************/
651 : /* GetFeatureCount() */
652 : /************************************************************************/
653 :
654 32 : GIntBig OGRGeoJSONSeqLayer::GetFeatureCount(int bForce)
655 : {
656 32 : if (m_poFilterGeom == nullptr && m_poAttrQuery == nullptr)
657 : {
658 26 : GetLayerDefn(); // force scan if not already done
659 26 : return m_nTotalFeatures;
660 : }
661 6 : return OGRLayer::GetFeatureCount(bForce);
662 : }
663 :
664 : /************************************************************************/
665 : /* TestCapability() */
666 : /************************************************************************/
667 :
668 185 : int OGRGeoJSONSeqLayer::TestCapability(const char *pszCap)
669 : {
670 185 : if (EQUAL(pszCap, OLCStringsAsUTF8))
671 13 : return true;
672 172 : if (m_poFilterGeom == nullptr && m_poAttrQuery == nullptr &&
673 172 : EQUAL(pszCap, OLCFastFeatureCount))
674 : {
675 0 : return true;
676 : }
677 172 : if (EQUAL(pszCap, OLCCreateField) || EQUAL(pszCap, OLCSequentialWrite))
678 : {
679 47 : return m_poDS->GetAccess() == GA_Update;
680 : }
681 :
682 125 : return false;
683 : }
684 :
685 : /************************************************************************/
686 : /* ICreateFeature() */
687 : /************************************************************************/
688 :
689 106 : OGRErr OGRGeoJSONSeqLayer::ICreateFeature(OGRFeature *poFeature)
690 : {
691 106 : if (m_poDS->GetAccess() != GA_Update)
692 3 : return OGRERR_FAILURE;
693 :
694 103 : if (!m_poDS->m_bAtEOF)
695 : {
696 50 : m_poDS->m_bAtEOF = true;
697 50 : VSIFSeekL(m_poDS->m_fp, 0, SEEK_END);
698 : }
699 :
700 103 : std::unique_ptr<OGRFeature> poFeatureToWrite;
701 103 : if (m_poCT != nullptr)
702 : {
703 3 : poFeatureToWrite.reset(new OGRFeature(m_poFeatureDefn));
704 3 : poFeatureToWrite->SetFrom(poFeature);
705 3 : poFeatureToWrite->SetFID(poFeature->GetFID());
706 3 : OGRGeometry *poGeometry = poFeatureToWrite->GetGeometryRef();
707 3 : if (poGeometry)
708 : {
709 3 : const char *const apszOptions[] = {"WRAPDATELINE=YES", nullptr};
710 3 : OGRGeometry *poNewGeom = OGRGeometryFactory::transformWithOptions(
711 : poGeometry, m_poCT.get(), const_cast<char **>(apszOptions),
712 3 : m_oTransformCache);
713 3 : if (poNewGeom == nullptr)
714 : {
715 0 : return OGRERR_FAILURE;
716 : }
717 :
718 3 : OGREnvelope sEnvelope;
719 3 : poNewGeom->getEnvelope(&sEnvelope);
720 3 : if (sEnvelope.MinX < -180.0 || sEnvelope.MaxX > 180.0 ||
721 3 : sEnvelope.MinY < -90.0 || sEnvelope.MaxY > 90.0)
722 : {
723 0 : CPLError(CE_Failure, CPLE_AppDefined,
724 : "Geometry extent outside of "
725 : "[-180.0,180.0]x[-90.0,90.0] bounds");
726 0 : return OGRERR_FAILURE;
727 : }
728 :
729 3 : poFeatureToWrite->SetGeometryDirectly(poNewGeom);
730 : }
731 : }
732 :
733 103 : ++m_nTotalFeatures;
734 :
735 106 : json_object *poObj = OGRGeoJSONWriteFeature(
736 3 : poFeatureToWrite.get() ? poFeatureToWrite.get() : poFeature,
737 103 : m_oWriteOptions);
738 103 : CPLAssert(nullptr != poObj);
739 :
740 103 : const char *pszJson = json_object_to_json_string(poObj);
741 :
742 103 : char chEOL = '\n';
743 103 : OGRErr eErr = OGRERR_NONE;
744 216 : if ((m_poDS->m_bIsRSSeparated &&
745 10 : VSIFWriteL(&RS, 1, 1, m_poDS->m_fp) != 1) ||
746 216 : VSIFWriteL(pszJson, strlen(pszJson), 1, m_poDS->m_fp) != 1 ||
747 103 : VSIFWriteL(&chEOL, 1, 1, m_poDS->m_fp) != 1)
748 : {
749 0 : CPLError(CE_Failure, CPLE_FileIO, "Cannot write feature");
750 0 : eErr = OGRERR_FAILURE;
751 : }
752 :
753 103 : json_object_put(poObj);
754 :
755 103 : return eErr;
756 : }
757 :
758 : /************************************************************************/
759 : /* CreateField() */
760 : /************************************************************************/
761 :
762 111 : OGRErr OGRGeoJSONSeqLayer::CreateField(const OGRFieldDefn *poField,
763 : int /* bApproxOK */)
764 : {
765 111 : if (m_poDS->GetAccess() != GA_Update)
766 3 : return OGRERR_FAILURE;
767 108 : m_poFeatureDefn->AddFieldDefn(poField);
768 108 : return OGRERR_NONE;
769 : }
770 :
771 : /************************************************************************/
772 : /* Open() */
773 : /************************************************************************/
774 :
775 55 : bool OGRGeoJSONSeqDataSource::Open(GDALOpenInfo *poOpenInfo,
776 : GeoJSONSourceType nSrcType)
777 : {
778 55 : CPLAssert(nullptr == m_fp);
779 :
780 110 : CPLString osLayerName("GeoJSONSeq");
781 :
782 55 : const char *pszUnprefixedFilename = poOpenInfo->pszFilename;
783 55 : if (STARTS_WITH_CI(poOpenInfo->pszFilename, "GeoJSONSeq:"))
784 : {
785 1 : pszUnprefixedFilename = poOpenInfo->pszFilename + strlen("GeoJSONSeq:");
786 : }
787 :
788 55 : if (nSrcType == eGeoJSONSourceFile)
789 : {
790 43 : if (pszUnprefixedFilename != poOpenInfo->pszFilename)
791 : {
792 1 : osLayerName = CPLGetBasename(pszUnprefixedFilename);
793 1 : m_fp = VSIFOpenL(pszUnprefixedFilename,
794 1 : poOpenInfo->eAccess == GA_Update ? "rb+" : "rb");
795 : }
796 : else
797 : {
798 42 : osLayerName = CPLGetBasename(poOpenInfo->pszFilename);
799 42 : std::swap(m_fp, poOpenInfo->fpL);
800 : }
801 : }
802 12 : else if (nSrcType == eGeoJSONSourceText)
803 : {
804 3 : if (poOpenInfo->eAccess == GA_Update)
805 0 : return false;
806 :
807 3 : m_osTmpFile = VSIMemGenerateHiddenFilename("geojsonseq");
808 3 : m_fp = VSIFileFromMemBuffer(
809 : m_osTmpFile.c_str(),
810 3 : reinterpret_cast<GByte *>(CPLStrdup(poOpenInfo->pszFilename)),
811 3 : strlen(poOpenInfo->pszFilename), true);
812 : }
813 9 : else if (nSrcType == eGeoJSONSourceService)
814 : {
815 9 : if (poOpenInfo->eAccess == GA_Update)
816 0 : return false;
817 :
818 : char *pszStoredContent =
819 9 : OGRGeoJSONDriverStealStoredContent(pszUnprefixedFilename);
820 9 : if (pszStoredContent)
821 : {
822 9 : if (EQUAL(pszStoredContent, INVALID_CONTENT_FOR_JSON_LIKE) ||
823 0 : !GeoJSONSeqIsObject(pszStoredContent, poOpenInfo))
824 : {
825 9 : OGRGeoJSONDriverStoreContent(poOpenInfo->pszFilename,
826 : pszStoredContent);
827 9 : return false;
828 : }
829 : else
830 : {
831 0 : m_osTmpFile = VSIMemGenerateHiddenFilename("geojsonseq");
832 0 : m_fp = VSIFileFromMemBuffer(
833 : m_osTmpFile.c_str(),
834 : reinterpret_cast<GByte *>(pszStoredContent),
835 0 : strlen(pszStoredContent), true);
836 : }
837 : }
838 : else
839 : {
840 0 : const char *const papsOptions[] = {
841 : "HEADERS=Accept: text/plain, application/json", nullptr};
842 :
843 : CPLHTTPResult *pResult =
844 0 : CPLHTTPFetch(pszUnprefixedFilename, papsOptions);
845 :
846 0 : if (nullptr == pResult || 0 == pResult->nDataLen ||
847 0 : 0 != CPLGetLastErrorNo())
848 : {
849 0 : CPLHTTPDestroyResult(pResult);
850 0 : return false;
851 : }
852 :
853 0 : if (0 != pResult->nStatus)
854 : {
855 0 : CPLError(CE_Failure, CPLE_AppDefined,
856 : "Curl reports error: %d: %s", pResult->nStatus,
857 : pResult->pszErrBuf);
858 0 : CPLHTTPDestroyResult(pResult);
859 0 : return false;
860 : }
861 :
862 0 : m_osTmpFile = VSIMemGenerateHiddenFilename("geojsonseq");
863 0 : m_fp = VSIFileFromMemBuffer(m_osTmpFile.c_str(), pResult->pabyData,
864 0 : pResult->nDataLen, true);
865 0 : pResult->pabyData = nullptr;
866 0 : pResult->nDataLen = 0;
867 0 : CPLHTTPDestroyResult(pResult);
868 : }
869 : }
870 46 : if (m_fp == nullptr)
871 : {
872 0 : return false;
873 : }
874 46 : SetDescription(poOpenInfo->pszFilename);
875 46 : auto poLayer = new OGRGeoJSONSeqLayer(this, osLayerName.c_str());
876 46 : const bool bLooseIdentification =
877 46 : nSrcType == eGeoJSONSourceService &&
878 0 : !STARTS_WITH_CI(poOpenInfo->pszFilename, "GeoJSONSeq:");
879 46 : if (bLooseIdentification)
880 : {
881 0 : CPLPushErrorHandler(CPLQuietErrorHandler);
882 : }
883 46 : const bool bEstablishLayerDefn = poOpenInfo->eAccess != GA_Update;
884 46 : auto ret = poLayer->Init(bLooseIdentification, bEstablishLayerDefn);
885 46 : if (bLooseIdentification)
886 : {
887 0 : CPLPopErrorHandler();
888 0 : CPLErrorReset();
889 : }
890 46 : if (!ret)
891 : {
892 1 : delete poLayer;
893 1 : return false;
894 : }
895 45 : m_apoLayers.emplace_back(std::move(poLayer));
896 45 : eAccess = poOpenInfo->eAccess;
897 45 : return true;
898 : }
899 :
900 : /************************************************************************/
901 : /* Create() */
902 : /************************************************************************/
903 :
904 44 : bool OGRGeoJSONSeqDataSource::Create(const char *pszName,
905 : char ** /* papszOptions */)
906 : {
907 44 : CPLAssert(nullptr == m_fp);
908 :
909 44 : if (strcmp(pszName, "/dev/stdout") == 0)
910 0 : pszName = "/vsistdout/";
911 :
912 : /* -------------------------------------------------------------------- */
913 : /* Create the output file. */
914 : /* -------------------------------------------------------------------- */
915 44 : m_bSupportsRead =
916 87 : VSIFileManager::GetHandler(pszName)->SupportsRead(pszName) &&
917 86 : VSIFileManager::GetHandler(pszName)->SupportsRandomWrite(pszName,
918 43 : false);
919 44 : m_bAtEOF = !m_bSupportsRead;
920 44 : m_fp = VSIFOpenExL(pszName, m_bSupportsRead ? "wb+" : "wb", true);
921 44 : if (nullptr == m_fp)
922 : {
923 1 : CPLError(CE_Failure, CPLE_OpenFailed, "Failed to create %s: %s",
924 : pszName, VSIGetLastErrorMsg());
925 1 : return false;
926 : }
927 :
928 43 : eAccess = GA_Update;
929 :
930 43 : m_bIsRSSeparated = EQUAL(CPLGetExtension(pszName), "GEOJSONS");
931 :
932 43 : return true;
933 : }
934 :
935 : /************************************************************************/
936 : /* OGRGeoJSONSeqDriverIdentify() */
937 : /************************************************************************/
938 :
939 47475 : static int OGRGeoJSONSeqDriverIdentifyInternal(GDALOpenInfo *poOpenInfo,
940 : GeoJSONSourceType &nSrcType)
941 : {
942 47475 : nSrcType = GeoJSONSeqGetSourceType(poOpenInfo);
943 47475 : if (nSrcType == eGeoJSONSourceUnknown)
944 47356 : return FALSE;
945 119 : if (nSrcType == eGeoJSONSourceService)
946 : {
947 27 : if (poOpenInfo->IsSingleAllowedDriver("GeoJSONSeq"))
948 1 : return TRUE;
949 26 : if (!STARTS_WITH_CI(poOpenInfo->pszFilename, "GeoJSONSeq:"))
950 : {
951 26 : return -1;
952 : }
953 : }
954 92 : return TRUE;
955 : }
956 :
957 : /************************************************************************/
958 : /* OGRGeoJSONSeqDriverIdentify() */
959 : /************************************************************************/
960 :
961 47420 : static int OGRGeoJSONSeqDriverIdentify(GDALOpenInfo *poOpenInfo)
962 : {
963 : GeoJSONSourceType nSrcType;
964 94840 : return OGRGeoJSONSeqDriverIdentifyInternal(poOpenInfo, nSrcType);
965 : }
966 :
967 : /************************************************************************/
968 : /* Open() */
969 : /************************************************************************/
970 :
971 55 : static GDALDataset *OGRGeoJSONSeqDriverOpen(GDALOpenInfo *poOpenInfo)
972 : {
973 : GeoJSONSourceType nSrcType;
974 55 : if (OGRGeoJSONSeqDriverIdentifyInternal(poOpenInfo, nSrcType) == FALSE)
975 : {
976 0 : return nullptr;
977 : }
978 :
979 55 : OGRGeoJSONSeqDataSource *poDS = new OGRGeoJSONSeqDataSource();
980 :
981 55 : if (!poDS->Open(poOpenInfo, nSrcType))
982 : {
983 10 : delete poDS;
984 10 : poDS = nullptr;
985 : }
986 :
987 55 : return poDS;
988 : }
989 :
990 : /************************************************************************/
991 : /* Create() */
992 : /************************************************************************/
993 :
994 : static GDALDataset *
995 44 : OGRGeoJSONSeqDriverCreate(const char *pszName, int /* nBands */,
996 : int /* nXSize */, int /* nYSize */,
997 : GDALDataType /* eDT */, char **papszOptions)
998 : {
999 44 : OGRGeoJSONSeqDataSource *poDS = new OGRGeoJSONSeqDataSource();
1000 :
1001 44 : if (!poDS->Create(pszName, papszOptions))
1002 : {
1003 1 : delete poDS;
1004 1 : poDS = nullptr;
1005 : }
1006 :
1007 44 : return poDS;
1008 : }
1009 :
1010 : /************************************************************************/
1011 : /* RegisterOGRGeoJSONSeq() */
1012 : /************************************************************************/
1013 :
1014 1595 : void RegisterOGRGeoJSONSeq()
1015 : {
1016 1595 : if (GDALGetDriverByName("GeoJSONSeq") != nullptr)
1017 302 : return;
1018 :
1019 1293 : GDALDriver *poDriver = new GDALDriver();
1020 :
1021 1293 : poDriver->SetDescription("GeoJSONSeq");
1022 1293 : poDriver->SetMetadataItem(GDAL_DCAP_VECTOR, "YES");
1023 1293 : poDriver->SetMetadataItem(GDAL_DCAP_CREATE_LAYER, "YES");
1024 1293 : poDriver->SetMetadataItem(GDAL_DCAP_CREATE_FIELD, "YES");
1025 1293 : poDriver->SetMetadataItem(GDAL_DCAP_Z_GEOMETRIES, "YES");
1026 1293 : poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "GeoJSON Sequence");
1027 1293 : poDriver->SetMetadataItem(GDAL_DMD_EXTENSIONS, "geojsonl geojsons");
1028 1293 : poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC,
1029 1293 : "drivers/vector/geojsonseq.html");
1030 :
1031 1293 : poDriver->SetMetadataItem(
1032 : GDAL_DS_LAYER_CREATIONOPTIONLIST,
1033 : "<LayerCreationOptionList>"
1034 : " <Option name='RS' type='boolean' description='whether to prefix "
1035 : "records with RS=0x1e character' default='NO'/>"
1036 : " <Option name='COORDINATE_PRECISION' type='int' description='Number "
1037 : "of decimal for coordinates. Default is 7'/>"
1038 : " <Option name='SIGNIFICANT_FIGURES' type='int' description='Number "
1039 : "of significant figures for floating-point values' default='17'/>"
1040 : " <Option name='ID_FIELD' type='string' description='Name of the "
1041 : "source field that must be used as the id member of Feature features'/>"
1042 : " <Option name='ID_TYPE' type='string-select' description='Type of "
1043 : "the id member of Feature features'>"
1044 : " <Value>AUTO</Value>"
1045 : " <Value>String</Value>"
1046 : " <Value>Integer</Value>"
1047 : " </Option>"
1048 : " <Option name='WRITE_BBOX' type='boolean' description='whether to "
1049 : "write a bbox property with the bounding box of each geometry' "
1050 : "default='NO'/>"
1051 1293 : "</LayerCreationOptionList>");
1052 :
1053 1293 : poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
1054 1293 : poDriver->SetMetadataItem(GDAL_DMD_CREATIONFIELDDATATYPES,
1055 : "Integer Integer64 Real String IntegerList "
1056 1293 : "Integer64List RealList StringList");
1057 1293 : poDriver->SetMetadataItem(GDAL_DMD_CREATIONFIELDDATASUBTYPES, "Boolean");
1058 1293 : poDriver->SetMetadataItem(GDAL_DMD_SUPPORTED_SQL_DIALECTS, "OGRSQL SQLITE");
1059 1293 : poDriver->SetMetadataItem(GDAL_DCAP_HONOR_GEOM_COORDINATE_PRECISION, "YES");
1060 :
1061 1293 : poDriver->pfnOpen = OGRGeoJSONSeqDriverOpen;
1062 1293 : poDriver->pfnIdentify = OGRGeoJSONSeqDriverIdentify;
1063 1293 : poDriver->pfnCreate = OGRGeoJSONSeqDriverCreate;
1064 :
1065 1293 : GetGDALDriverManager()->RegisterDriver(poDriver);
1066 : }
|