/src/gdal/ogr/ogrsf_frmts/jsonfg/ogr_jsonfg.h
Line | Count | Source |
1 | | /****************************************************************************** |
2 | | * |
3 | | * Project: OpenGIS Simple Features Reference Implementation |
4 | | * Purpose: Implementation of OGC Features and Geometries JSON (JSON-FG) |
5 | | * Author: Even Rouault <even.rouault at spatialys.com> |
6 | | * |
7 | | ****************************************************************************** |
8 | | * Copyright (c) 2023, Even Rouault <even.rouault at spatialys.com> |
9 | | * |
10 | | * SPDX-License-Identifier: MIT |
11 | | ****************************************************************************/ |
12 | | |
13 | | #ifndef OGR_JSONFG_H_INCLUDED |
14 | | #define OGR_JSONFG_H_INCLUDED |
15 | | |
16 | | #include "cpl_vsi_virtual.h" |
17 | | |
18 | | #include "gdal_priv.h" |
19 | | #include "ogrsf_frmts.h" |
20 | | #include "ogrgeojsonutils.h" |
21 | | #include "ogrgeojsonwriter.h" |
22 | | #include "ogrjsoncollectionstreamingparser.h" |
23 | | #include "memdataset.h" |
24 | | #include "directedacyclicgraph.hpp" |
25 | | |
26 | | #include <map> |
27 | | #include <set> |
28 | | #include <utility> |
29 | | |
30 | | /************************************************************************/ |
31 | | /* OGRJSONFGMemLayer */ |
32 | | /************************************************************************/ |
33 | | |
34 | | /** Layer with all features ingested into memory. */ |
35 | | class OGRJSONFGMemLayer final : public OGRMemLayer |
36 | | { |
37 | | public: |
38 | | OGRJSONFGMemLayer(GDALDataset *poDS, const char *pszName, |
39 | | OGRSpatialReference *poSRS, OGRwkbGeometryType eGType); |
40 | | ~OGRJSONFGMemLayer() override; |
41 | | |
42 | | const char *GetFIDColumn() const override |
43 | 4 | { |
44 | 4 | return osFIDColumn_.c_str(); |
45 | 4 | } |
46 | | |
47 | | void SetFIDColumn(const char *pszName) |
48 | 0 | { |
49 | 0 | osFIDColumn_ = pszName; |
50 | 0 | } |
51 | | |
52 | | void AddFeature(std::unique_ptr<OGRFeature> poFeature); |
53 | | |
54 | | GDALDataset *GetDataset() override |
55 | 0 | { |
56 | 0 | return m_poDS; |
57 | 0 | } |
58 | | |
59 | | private: |
60 | | GDALDataset *m_poDS = nullptr; |
61 | | std::string osFIDColumn_{}; |
62 | | bool bOriginalIdModified_ = false; |
63 | | |
64 | | CPL_DISALLOW_COPY_ASSIGN(OGRJSONFGMemLayer) |
65 | | }; |
66 | | |
67 | | /************************************************************************/ |
68 | | /* OGRJSONFGStreamedLayer */ |
69 | | /************************************************************************/ |
70 | | |
71 | | class OGRJSONFGStreamingParser; |
72 | | |
73 | | /** Layer with features being acquired progressively through a streaming |
74 | | parser. |
75 | | |
76 | | Only applies for FeatureCollection read through a file |
77 | | */ |
78 | | class OGRJSONFGStreamedLayer final |
79 | | : public OGRLayer, |
80 | | public OGRGetNextFeatureThroughRaw<OGRJSONFGStreamedLayer> |
81 | | { |
82 | | public: |
83 | | OGRJSONFGStreamedLayer(GDALDataset *poDS, const char *pszName, |
84 | | OGRSpatialReference *poSRS, |
85 | | OGRwkbGeometryType eGType); |
86 | | ~OGRJSONFGStreamedLayer() override; |
87 | | |
88 | | // BEGIN specific public API |
89 | | |
90 | | //! Set the FID column name |
91 | | void SetFIDColumn(const char *pszName) |
92 | 0 | { |
93 | 0 | osFIDColumn_ = pszName; |
94 | 0 | } |
95 | | |
96 | | //! Set the total feature count |
97 | | void SetFeatureCount(GIntBig nCount) |
98 | 12 | { |
99 | 12 | nFeatureCount_ = nCount; |
100 | 12 | } |
101 | | |
102 | | /** Set the file handle. |
103 | | |
104 | | Must be called before GetNextFeature() is called |
105 | | */ |
106 | | void SetFile(VSIVirtualHandleUniquePtr &&poFile); |
107 | | |
108 | | /** Set the streaming parser |
109 | | |
110 | | Must be called before GetNextFeature() is called |
111 | | */ |
112 | | void SetStreamingParser( |
113 | | std::unique_ptr<OGRJSONFGStreamingParser> &&poStreamingParser); |
114 | | |
115 | | // END specific public API |
116 | | |
117 | | const char *GetFIDColumn() const override |
118 | 12 | { |
119 | 12 | return osFIDColumn_.c_str(); |
120 | 12 | } |
121 | | |
122 | | const OGRFeatureDefn *GetLayerDefn() const override |
123 | 120 | { |
124 | 120 | return poFeatureDefn_; |
125 | 120 | } |
126 | | |
127 | | int TestCapability(const char *pszCap) const override; |
128 | | |
129 | | GIntBig GetFeatureCount(int bForce) override; |
130 | | |
131 | | void ResetReading() override; |
132 | | |
133 | | DEFINE_GET_NEXT_FEATURE_THROUGH_RAW(OGRJSONFGStreamedLayer) |
134 | | |
135 | | GDALDataset *GetDataset() override |
136 | 0 | { |
137 | 0 | return m_poDS; |
138 | 0 | } |
139 | | |
140 | | private: |
141 | | GDALDataset *m_poDS = nullptr; |
142 | | OGRFeatureDefn *poFeatureDefn_ = nullptr; |
143 | | std::string osFIDColumn_{}; |
144 | | |
145 | | /** Total number of features. */ |
146 | | GIntBig nFeatureCount_ = -1; |
147 | | |
148 | | VSIVirtualHandleUniquePtr poFile_{}; |
149 | | |
150 | | std::unique_ptr<OGRJSONFGStreamingParser> poStreamingParser_{}; |
151 | | |
152 | | /** Whether a warning has been emitted about feature IDs having been |
153 | | * modified */ |
154 | | bool bOriginalIdModified_ = false; |
155 | | /** Set of feature IDs read/allocated up to that point */ |
156 | | std::set<GIntBig> oSetUsedFIDs_{}; |
157 | | |
158 | | /** Ensure the FID of the feature is unique */ |
159 | | OGRFeature *EnsureUniqueFID(OGRFeature *poFeat); |
160 | | |
161 | | /** Return next feature (without filter) */ |
162 | | OGRFeature *GetNextRawFeature(); |
163 | | |
164 | | CPL_DISALLOW_COPY_ASSIGN(OGRJSONFGStreamedLayer) |
165 | | }; |
166 | | |
167 | | /************************************************************************/ |
168 | | /* OGRJSONFGWriteLayer */ |
169 | | /************************************************************************/ |
170 | | |
171 | | class OGRJSONFGDataset; |
172 | | |
173 | | class OGRJSONFGWriteLayer final : public OGRLayer |
174 | | { |
175 | | public: |
176 | | OGRJSONFGWriteLayer( |
177 | | const char *pszName, const OGRSpatialReference *poSRS, |
178 | | std::unique_ptr<OGRCoordinateTransformation> &&poCTToWGS84, |
179 | | const std::string &osCoordRefSys, OGRwkbGeometryType eGType, |
180 | | CSLConstList papszOptions, OGRJSONFGDataset *poDS); |
181 | | ~OGRJSONFGWriteLayer() override; |
182 | | |
183 | | // |
184 | | // OGRLayer Interface |
185 | | // |
186 | | const OGRFeatureDefn *GetLayerDefn() const override |
187 | 0 | { |
188 | 0 | return poFeatureDefn_; |
189 | 0 | } |
190 | | |
191 | | const OGRSpatialReference *GetSpatialRef() const override |
192 | 0 | { |
193 | 0 | return nullptr; |
194 | 0 | } |
195 | | |
196 | | void ResetReading() override |
197 | 0 | { |
198 | 0 | } |
199 | | |
200 | | OGRFeature *GetNextFeature() override |
201 | 0 | { |
202 | 0 | return nullptr; |
203 | 0 | } |
204 | | |
205 | | OGRErr ICreateFeature(OGRFeature *poFeature) override; |
206 | | OGRErr CreateField(const OGRFieldDefn *poField, int bApproxOK) override; |
207 | | int TestCapability(const char *pszCap) const override; |
208 | | |
209 | | OGRErr SyncToDisk() override; |
210 | | |
211 | | GDALDataset *GetDataset() override; |
212 | | |
213 | | bool HasPolyhedra() const |
214 | 0 | { |
215 | 0 | return m_bPolyhedraWritten; |
216 | 0 | } |
217 | | |
218 | | bool HasCurve() const |
219 | 0 | { |
220 | 0 | return m_bCurveWritten; |
221 | 0 | } |
222 | | |
223 | | bool HasMeasure() const |
224 | 0 | { |
225 | 0 | return m_bMeasureWritten; |
226 | 0 | } |
227 | | |
228 | | private: |
229 | | OGRJSONFGDataset *poDS_{}; |
230 | | OGRFeatureDefn *poFeatureDefn_ = nullptr; |
231 | | std::unique_ptr<OGRCoordinateTransformation> poCTToWGS84_; |
232 | | bool bIsWGS84CRS_ = false; |
233 | | bool m_bMustSwapForPlace = false; |
234 | | int nOutCounter_ = 0; |
235 | | std::string osCoordRefSys_{}; |
236 | | bool m_bPolyhedraWritten = false; |
237 | | bool m_bCurveWritten = false; |
238 | | bool m_bMeasureWritten = false; |
239 | | bool bLayerLevelMeasuresWritten_ = false; |
240 | | std::string osMeasureUnit_{}; |
241 | | std::string osMeasureDescription_{}; |
242 | | |
243 | | OGRGeoJSONWriteOptions oWriteOptions_{}; |
244 | | OGRGeoJSONWriteOptions oWriteOptionsPlace_{}; |
245 | | bool bWriteFallbackGeometry_ = true; |
246 | | |
247 | | CPL_DISALLOW_COPY_ASSIGN(OGRJSONFGWriteLayer) |
248 | | }; |
249 | | |
250 | | /************************************************************************/ |
251 | | /* OGRJSONFGDataset */ |
252 | | /************************************************************************/ |
253 | | |
254 | | class OGRJSONFGReader; |
255 | | |
256 | | class OGRJSONFGDataset final : public GDALDataset |
257 | | { |
258 | | public: |
259 | 1.64k | OGRJSONFGDataset() = default; |
260 | | ~OGRJSONFGDataset() override; |
261 | | |
262 | | CPLErr Close(GDALProgressFunc = nullptr, void * = nullptr) override; |
263 | | |
264 | | bool Open(GDALOpenInfo *poOpenInfo, GeoJSONSourceType nSrcType); |
265 | | bool Create(const char *pszName, CSLConstList papszOptions); |
266 | | |
267 | | int GetLayerCount() const override |
268 | 16 | { |
269 | 16 | return static_cast<int>(apoLayers_.size()); |
270 | 16 | } |
271 | | |
272 | | const OGRLayer *GetLayer(int i) const override; |
273 | | |
274 | | //! Return the output file handle. Used by OGRJSONFGWriteLayer |
275 | | VSILFILE *GetOutputFile() const |
276 | 0 | { |
277 | 0 | return fpOut_; |
278 | 0 | } |
279 | | |
280 | | /** Return whether there is a single output layer. |
281 | | * Used by OGRJSONFGWriteLayer |
282 | | */ |
283 | | bool IsSingleOutputLayer() const |
284 | 0 | { |
285 | 0 | return bSingleOutputLayer_; |
286 | 0 | } |
287 | | |
288 | | //! Return whether the output file is seekable |
289 | | bool GetFpOutputIsSeekable() const |
290 | 0 | { |
291 | 0 | return bFpOutputIsSeekable_; |
292 | 0 | } |
293 | | |
294 | | void BeforeCreateFeature(); |
295 | | |
296 | | OGRLayer *ICreateLayer(const char *pszName, |
297 | | const OGRGeomFieldDefn *poGeomFieldDefn, |
298 | | CSLConstList papszOptions) override; |
299 | | |
300 | | int TestCapability(const char *pszCap) const override; |
301 | | |
302 | | OGRErr SyncToDiskInternal(); |
303 | | |
304 | | protected: |
305 | | friend class OGRJSONFGReader; |
306 | | OGRJSONFGMemLayer *AddLayer(std::unique_ptr<OGRJSONFGMemLayer> &&poLayer); |
307 | | OGRJSONFGStreamedLayer * |
308 | | AddLayer(std::unique_ptr<OGRJSONFGStreamedLayer> &&poLayer); |
309 | | |
310 | | private: |
311 | | char *pszGeoData_ = nullptr; |
312 | | size_t nGeoDataLen_ = 0; |
313 | | std::vector<std::unique_ptr<OGRLayer>> apoLayers_{}; |
314 | | std::unique_ptr<OGRJSONFGReader> poReader_{}; |
315 | | |
316 | | // Write side |
317 | | VSILFILE *fpOut_ = nullptr; |
318 | | vsi_l_offset m_nPositionBeforeConformsTo = 0; |
319 | | vsi_l_offset m_nPositionAfterConformsTo = 0; |
320 | | bool bSingleOutputLayer_ = false; |
321 | | bool bHasEmittedFeatures_ = false; |
322 | | bool bFpOutputIsSeekable_ = false; |
323 | | |
324 | | /** Offset at which the '] }' terminating sequence has already been |
325 | | * written by SyncToDisk(). 0 if it has not been written. |
326 | | */ |
327 | | vsi_l_offset m_nPositionBeforeFCClosed = 0; |
328 | | |
329 | | bool ReadFromFile(GDALOpenInfo *poOpenInfo, const char *pszUnprefixed); |
330 | | bool ReadFromService(GDALOpenInfo *poOpenInfo, const char *pszSource); |
331 | | |
332 | | bool FinishWriting(); |
333 | | |
334 | | bool EmitStartFeaturesIfNeededAndReturnIfFirstFeature(); |
335 | | |
336 | | CPL_DISALLOW_COPY_ASSIGN(OGRJSONFGDataset) |
337 | | }; |
338 | | |
339 | | /************************************************************************/ |
340 | | /* OGRJSONFGReader */ |
341 | | /************************************************************************/ |
342 | | |
343 | | class OGRJSONFGReader |
344 | | { |
345 | | public: |
346 | 938 | OGRJSONFGReader() = default; |
347 | | ~OGRJSONFGReader(); |
348 | | |
349 | | /** Load all features from the passed in JSON text in OGRJSONFGMemLayer(s) |
350 | | * |
351 | | * This method should only be called once, and is exclusive with |
352 | | * AnalyzeWithStreamingParser() |
353 | | */ |
354 | | bool Load(OGRJSONFGDataset *poDS, const char *pszText, |
355 | | const std::string &osDefaultLayerName); |
356 | | |
357 | | /** Do a first pass analysis of the content of the passed file to create |
358 | | * OGRJSONFGStreamedLayer's |
359 | | * |
360 | | * It is the responsibility of the caller to call |
361 | | * SetFile() and SetStreamingParser() on the created layers afterwards |
362 | | * |
363 | | * This method should only be called once, and is exclusive with |
364 | | * Load() |
365 | | */ |
366 | | bool AnalyzeWithStreamingParser(OGRJSONFGDataset *poDS, VSILFILE *fp, |
367 | | const std::string &osDefaultLayerName, |
368 | | bool &bCanTryWithNonStreamingParserOut, |
369 | | bool &bHasTopLevelMeasures); |
370 | | |
371 | | /** Geometry element we are interested in. */ |
372 | | enum class GeometryElement |
373 | | { |
374 | | /** Use "place" when possible, fallback to "geometry" otherwise. */ |
375 | | AUTO, |
376 | | /** Only use "place" */ |
377 | | PLACE, |
378 | | /** Only use "geometry" */ |
379 | | GEOMETRY, |
380 | | }; |
381 | | |
382 | | /** Sets the geometry element we are interested in. */ |
383 | | void SetGeometryElement(GeometryElement elt) |
384 | 0 | { |
385 | 0 | eGeometryElement_ = elt; |
386 | 0 | } |
387 | | |
388 | | /** Returns a OGRFeature built from the passed in JSON object. |
389 | | * |
390 | | * @param poObj JSON feature |
391 | | * @param pszRequestedLayer name of the layer of interest, or nullptr if |
392 | | * no filtering needed on the layer name. If the feature does not belong |
393 | | * to the requested layer, nullptr is returned. |
394 | | * @param bHasM Whether the upper level of this object has measures |
395 | | * @param pOutMemLayer Pointer to the OGRJSONFGMemLayer* layer to which |
396 | | * the returned feature belongs to. May be nullptr. Only applies when |
397 | | * the Load() method has been used. |
398 | | * @param pOutStreamedLayer Pointer to the OGRJSONFGStreamedLayer* layer to |
399 | | * which the returned feature belongs to. May be nullptr. Only applies when |
400 | | * the AnalyzeWithStreamingParser() method has been used. |
401 | | */ |
402 | | std::unique_ptr<OGRFeature> |
403 | | ReadFeature(json_object *poObj, const char *pszRequestedLayer, bool bHasM, |
404 | | OGRJSONFGMemLayer **pOutMemLayer, |
405 | | OGRJSONFGStreamedLayer **pOutStreamedLayer); |
406 | | |
407 | | protected: |
408 | | friend class OGRJSONFGStreamingParser; |
409 | | |
410 | | bool GenerateLayerDefnFromFeature(json_object *poObj); |
411 | | |
412 | | private: |
413 | | GeometryElement eGeometryElement_ = GeometryElement::AUTO; |
414 | | |
415 | | OGRJSONFGDataset *poDS_ = nullptr; |
416 | | std::string osDefaultLayerName_{}; |
417 | | json_object *poObject_ = nullptr; |
418 | | |
419 | | bool bFlattenNestedAttributes_ = false; |
420 | | char chNestedAttributeSeparator_ = 0; |
421 | | bool bArrayAsString_ = false; |
422 | | bool bDateAsString_ = false; |
423 | | std::string osMeasureUnit_{}; |
424 | | std::string osMeasureDescription_{}; |
425 | | |
426 | | /** Layer building context, specific to one layer. */ |
427 | | struct LayerDefnBuildContext |
428 | | { |
429 | | //! Maps a field name to its index in apoFieldDefn[] |
430 | | std::map<std::string, int> oMapFieldNameToIdx{}; |
431 | | |
432 | | //! Vector of OGRFieldDefn |
433 | | std::vector<std::unique_ptr<OGRFieldDefn>> apoFieldDefn{}; |
434 | | |
435 | | //! Directed acyclic graph used to build the order of fields. |
436 | | gdal::DirectedAcyclicGraph<int, std::string> dag{}; |
437 | | |
438 | | /** Set of indices of apoFieldDefn[] for which no type information is |
439 | | * known yet. */ |
440 | | std::set<int> aoSetUndeterminedTypeFields{}; |
441 | | |
442 | | //! Whether at least one feature has a "coordRefSys" member. |
443 | | bool bHasCoordRefSysAtFeatureLevel = false; |
444 | | |
445 | | /** CRS object corresponding to "coordRefsys" member at feature level. |
446 | | * Only set if homogeneous among features. |
447 | | */ |
448 | | std::unique_ptr<OGRSpatialReference> poCRSAtFeatureLevel{}; |
449 | | |
450 | | /** Serialized JSON value of "coordRefsys" member at feature level. |
451 | | * Only set if homogeneous among features. |
452 | | */ |
453 | | std::string osCoordRefSysAtFeatureLevel{}; |
454 | | |
455 | | /** Whether to switch X/Y ordinates in geometries appearing in "place" |
456 | | * element. Only applies to CRS at layer level. |
457 | | */ |
458 | | bool bSwapPlacesXY = false; |
459 | | |
460 | | //! Whether the layer CRS is WGS 84. |
461 | | bool bLayerCRSIsWGS84 = false; |
462 | | |
463 | | //! Coordinate transformation from WGS 84 to layer CRS (might be null) |
464 | | std::unique_ptr<OGRCoordinateTransformation> poCTWGS84ToLayerCRS{}; |
465 | | |
466 | | /** Feature count */ |
467 | | GIntBig nFeatureCount = 0; |
468 | | |
469 | | //! Whether the Feature.id should be mapped to a OGR field. |
470 | | bool bFeatureLevelIdAsAttribute = false; |
471 | | |
472 | | //! Whether the Feature.id should be mapped to a OGR FID. |
473 | | bool bFeatureLevelIdAsFID = false; |
474 | | |
475 | | //! Whether 64-bit integers are needed for OGR FID. |
476 | | bool bNeedFID64 = false; |
477 | | |
478 | | //! Whether detection of layer geometry type is still needed. |
479 | | bool bDetectLayerGeomType = true; |
480 | | |
481 | | //! Whether no geometry has been analyzed yet. |
482 | | bool bFirstGeometry = true; |
483 | | |
484 | | //! Layer geometry type. |
485 | | OGRwkbGeometryType eLayerGeomType = wkbUnknown; |
486 | | |
487 | | //! Whether a Feature.time.date element has been found. |
488 | | bool bHasTimeDate = false; |
489 | | |
490 | | //! Whether a Feature.time.timestamp element has been found. |
491 | | bool bHasTimeTimestamp = false; |
492 | | |
493 | | /** Whether a Feature.time.interval[0] element of type timestamp has |
494 | | * been found */ |
495 | | bool bHasTimeIntervalStartTimestamp = false; |
496 | | |
497 | | /** Whether a Feature.time.interval[0] element of type date has |
498 | | * been found */ |
499 | | bool bHasTimeIntervalStartDate = false; |
500 | | |
501 | | /** Whether a Feature.time.interval[1] element of type timestamp has |
502 | | * been found */ |
503 | | bool bHasTimeIntervalEndTimestamp = false; |
504 | | |
505 | | /** Whether a Feature.time.interval[1] element of type date has |
506 | | * been found */ |
507 | | bool bHasTimeIntervalEndDate = false; |
508 | | |
509 | | //! Index of OGR field "time" / "jsonfg_time" |
510 | | int nIdxFieldTime = -1; |
511 | | |
512 | | //! Index of OGR field "time_start" / "jsonfg_time_start" |
513 | | int nIdxFieldTimeStart = -1; |
514 | | |
515 | | //! Index of OGR field "time_end" / "jsonfg_time_end" |
516 | | int nIdxFieldTimeEnd = -1; |
517 | | |
518 | | //! Corresponding OGRJSONFGMemLayer (only for Load() ingestion mode) |
519 | | OGRJSONFGMemLayer *poMemLayer = nullptr; |
520 | | |
521 | | /** Corresponding OGRJSONFGStreamedLayer(only for |
522 | | * AnalyzeWithStreamingParser() mode) */ |
523 | | OGRJSONFGStreamedLayer *poStreamedLayer = nullptr; |
524 | | |
525 | | bool bSameMeasureMetadata = true; |
526 | | |
527 | | //! Measure unit |
528 | | std::string osMeasureUnit{}; |
529 | | |
530 | | //! Measure description |
531 | | std::string osMeasureDescription{}; |
532 | | |
533 | 238 | LayerDefnBuildContext() = default; |
534 | 0 | LayerDefnBuildContext(LayerDefnBuildContext &&) = default; |
535 | 119 | LayerDefnBuildContext &operator=(LayerDefnBuildContext &&) = default; |
536 | | |
537 | | private: |
538 | | CPL_DISALLOW_COPY_ASSIGN(LayerDefnBuildContext) |
539 | | }; |
540 | | |
541 | | //! Maps a layer name to its build context |
542 | | std::map<std::string, LayerDefnBuildContext> oMapBuildContext_{}; |
543 | | |
544 | | // |
545 | | // Copy operations not supported. |
546 | | // |
547 | | CPL_DISALLOW_COPY_ASSIGN(OGRJSONFGReader) |
548 | | |
549 | | const char *GetLayerNameForFeature(json_object *poObj) const; |
550 | | bool GenerateLayerDefns(); |
551 | | bool FinalizeGenerateLayerDefns(bool bStreamedLayer); |
552 | | void FinalizeBuildContext(LayerDefnBuildContext &oBuildContext, |
553 | | const char *pszLayerName, bool bStreamedLayer, |
554 | | bool bInvalidCRS, bool bSwapPlacesXYTopLevel, |
555 | | OGRSpatialReference *poSRSTopLevel); |
556 | | }; |
557 | | |
558 | | /************************************************************************/ |
559 | | /* OGRJSONFGStreamingParser */ |
560 | | /************************************************************************/ |
561 | | |
562 | | /** FeatureCollection streaming parser. */ |
563 | | class OGRJSONFGStreamingParser final : public OGRJSONCollectionStreamingParser |
564 | | { |
565 | | OGRJSONFGReader &m_oReader; |
566 | | std::string m_osRequestedLayer{}; |
567 | | |
568 | | std::vector<std::pair<std::unique_ptr<OGRFeature>, OGRLayer *>> |
569 | | m_apoFeatures{}; |
570 | | size_t m_nCurFeatureIdx = 0; |
571 | | |
572 | | CPL_DISALLOW_COPY_ASSIGN(OGRJSONFGStreamingParser) |
573 | | |
574 | | protected: |
575 | | void GotFeature(json_object *poObj, bool bFirstPass, |
576 | | const std::string &osJson) override; |
577 | | void TooComplex() override; |
578 | | |
579 | | public: |
580 | | OGRJSONFGStreamingParser(OGRJSONFGReader &oReader, bool bFirstPass, |
581 | | bool bHasTopLevelMeasures); |
582 | | ~OGRJSONFGStreamingParser() override; |
583 | | |
584 | | void SetRequestedLayer(const char *pszRequestedLayer) |
585 | 12 | { |
586 | 12 | m_osRequestedLayer = pszRequestedLayer; |
587 | 12 | } |
588 | | |
589 | | std::unique_ptr<OGRJSONFGStreamingParser> Clone(); |
590 | | |
591 | | std::pair<std::unique_ptr<OGRFeature>, OGRLayer *> GetNextFeature(); |
592 | | }; |
593 | | |
594 | | bool OGRJSONFGMustSwapXY(const OGRSpatialReference *poSRS); |
595 | | |
596 | | #endif // OGR_JSONFG_H_INCLUDED |