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