Coverage Report

Created: 2025-06-13 06:29

/src/gdal/ogr/ogrsf_frmts/geojson/ogrgeojsondatasource.cpp
Line
Count
Source (jump to first uncovered line)
1
/******************************************************************************
2
 *
3
 * Project:  OpenGIS Simple Features Reference Implementation
4
 * Purpose:  Implementation of OGRGeoJSONDataSource class (OGR GeoJSON Driver).
5
 * Author:   Mateusz Loskot, mateusz@loskot.net
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 2007, Mateusz Loskot
9
 * Copyright (c) 2008-2013, Even Rouault <even dot rouault at spatialys.com>
10
 *
11
 * SPDX-License-Identifier: MIT
12
 ****************************************************************************/
13
14
#include "cpl_port.h"
15
#include "ogr_geojson.h"
16
17
#include <cmath>
18
#include <cstddef>
19
#include <cstdlib>
20
#include <cstring>
21
#include <string>
22
23
#include "cpl_conv.h"
24
#include "cpl_error.h"
25
#include "cpl_http.h"
26
#include "cpl_string.h"
27
#include "cpl_vsi.h"
28
#include "cpl_vsi_error.h"
29
#include "json.h"
30
// #include "json_object.h"
31
#include "gdal_utils.h"
32
#include "gdal.h"
33
#include "gdal_priv.h"
34
#include "ogr_core.h"
35
#include "ogr_feature.h"
36
#include "ogr_geometry.h"
37
#include "ogr_spatialref.h"
38
#include "ogrlibjsonutils.h"
39
#include "ogrgeojsonreader.h"
40
#include "ogrgeojsonutils.h"
41
#include "ogrgeojsonwriter.h"
42
#include "ogrsf_frmts.h"
43
#include "ogr_schema_override.h"
44
45
// #include "symbol_renames.h"
46
47
/************************************************************************/
48
/*                           OGRGeoJSONDataSource()                     */
49
/************************************************************************/
50
51
OGRGeoJSONDataSource::OGRGeoJSONDataSource()
52
0
    : pszName_(nullptr), pszGeoData_(nullptr), nGeoDataLen_(0),
53
0
      papoLayers_(nullptr), papoLayersWriter_(nullptr), nLayers_(0),
54
0
      fpOut_(nullptr), flTransGeom_(OGRGeoJSONDataSource::eGeometryPreserve),
55
0
      flTransAttrs_(OGRGeoJSONDataSource::eAttributesPreserve),
56
0
      bOtherPages_(false), bFpOutputIsSeekable_(false), nBBOXInsertLocation_(0),
57
0
      bUpdatable_(false)
58
0
{
59
0
}
60
61
/************************************************************************/
62
/*                           ~OGRGeoJSONDataSource()                    */
63
/************************************************************************/
64
65
OGRGeoJSONDataSource::~OGRGeoJSONDataSource()
66
0
{
67
0
    OGRGeoJSONDataSource::Close();
68
0
}
69
70
/************************************************************************/
71
/*                              Close()                                 */
72
/************************************************************************/
73
74
CPLErr OGRGeoJSONDataSource::Close()
75
0
{
76
0
    CPLErr eErr = CE_None;
77
0
    if (nOpenFlags != OPEN_FLAGS_CLOSED)
78
0
    {
79
0
        if (OGRGeoJSONDataSource::FlushCache(true) != CE_None)
80
0
            eErr = CE_Failure;
81
82
0
        if (!OGRGeoJSONDataSource::Clear())
83
0
            eErr = CE_Failure;
84
85
0
        if (GDALDataset::Close() != CE_None)
86
0
            eErr = CE_Failure;
87
0
    }
88
0
    return eErr;
89
0
}
90
91
/************************************************************************/
92
/*                 DealWithOgrSchemaOpenOption()                       */
93
/************************************************************************/
94
95
bool OGRGeoJSONDataSource::DealWithOgrSchemaOpenOption(
96
    const GDALOpenInfo *poOpenInfo)
97
0
{
98
99
0
    std::string osFieldsSchemaOverrideParam =
100
0
        CSLFetchNameValueDef(poOpenInfo->papszOpenOptions, "OGR_SCHEMA", "");
101
102
0
    if (!osFieldsSchemaOverrideParam.empty())
103
0
    {
104
105
0
        if (poOpenInfo->eAccess == GA_Update)
106
0
        {
107
0
            CPLError(CE_Failure, CPLE_NotSupported,
108
0
                     "OGR_SCHEMA open option is not supported in update mode.");
109
0
            return false;
110
0
        }
111
112
0
        OGRSchemaOverride osSchemaOverride;
113
0
        if (!osSchemaOverride.LoadFromJSON(osFieldsSchemaOverrideParam) ||
114
0
            !osSchemaOverride.IsValid())
115
0
        {
116
0
            return false;
117
0
        }
118
119
0
        const auto &oLayerOverrides = osSchemaOverride.GetLayerOverrides();
120
0
        for (const auto &oLayer : oLayerOverrides)
121
0
        {
122
0
            const auto &oLayerName = oLayer.first;
123
0
            const auto &oLayerFieldOverride = oLayer.second;
124
0
            const bool bIsFullOverride{oLayerFieldOverride.IsFullOverride()};
125
0
            auto oFieldOverrides = oLayerFieldOverride.GetFieldOverrides();
126
0
            std::vector<OGRFieldDefn *> aoFields;
127
128
0
            CPLDebug("GeoJSON", "Applying schema override for layer %s",
129
0
                     oLayerName.c_str());
130
131
            // Fail if the layer name does not exist
132
0
            auto poLayer = GetLayerByName(oLayerName.c_str());
133
0
            if (poLayer == nullptr)
134
0
            {
135
0
                CPLError(CE_Failure, CPLE_AppDefined,
136
0
                         "Layer %s not found in GeoJSON file",
137
0
                         oLayerName.c_str());
138
0
                return false;
139
0
            }
140
141
            // Patch field definitions
142
0
            auto poLayerDefn = poLayer->GetLayerDefn();
143
0
            for (int i = 0; i < poLayerDefn->GetFieldCount(); i++)
144
0
            {
145
0
                auto poFieldDefn = poLayerDefn->GetFieldDefn(i);
146
0
                auto oFieldOverride =
147
0
                    oFieldOverrides.find(poFieldDefn->GetNameRef());
148
0
                if (oFieldOverride != oFieldOverrides.cend())
149
0
                {
150
0
                    if (oFieldOverride->second.GetFieldType().has_value())
151
0
                        whileUnsealing(poFieldDefn)
152
0
                            ->SetType(
153
0
                                oFieldOverride->second.GetFieldType().value());
154
0
                    if (oFieldOverride->second.GetFieldWidth().has_value())
155
0
                        whileUnsealing(poFieldDefn)
156
0
                            ->SetWidth(
157
0
                                oFieldOverride->second.GetFieldWidth().value());
158
0
                    if (oFieldOverride->second.GetFieldPrecision().has_value())
159
0
                        whileUnsealing(poFieldDefn)
160
0
                            ->SetPrecision(
161
0
                                oFieldOverride->second.GetFieldPrecision()
162
0
                                    .value());
163
0
                    if (oFieldOverride->second.GetFieldSubType().has_value())
164
0
                        whileUnsealing(poFieldDefn)
165
0
                            ->SetSubType(
166
0
                                oFieldOverride->second.GetFieldSubType()
167
0
                                    .value());
168
0
                    if (oFieldOverride->second.GetFieldName().has_value())
169
0
                        whileUnsealing(poFieldDefn)
170
0
                            ->SetName(oFieldOverride->second.GetFieldName()
171
0
                                          .value()
172
0
                                          .c_str());
173
174
0
                    if (bIsFullOverride)
175
0
                    {
176
0
                        aoFields.push_back(poFieldDefn);
177
0
                    }
178
0
                    oFieldOverrides.erase(oFieldOverride);
179
0
                }
180
0
            }
181
182
            // Error if any field override is not found
183
0
            if (!oFieldOverrides.empty())
184
0
            {
185
0
                CPLError(CE_Failure, CPLE_AppDefined,
186
0
                         "Field %s not found in layer %s",
187
0
                         oFieldOverrides.cbegin()->first.c_str(),
188
0
                         oLayerName.c_str());
189
0
                return false;
190
0
            }
191
192
            // Remove fields not in the override
193
0
            if (bIsFullOverride)
194
0
            {
195
0
                for (int i = poLayerDefn->GetFieldCount() - 1; i >= 0; i--)
196
0
                {
197
0
                    auto poFieldDefn = poLayerDefn->GetFieldDefn(i);
198
0
                    if (std::find(aoFields.begin(), aoFields.end(),
199
0
                                  poFieldDefn) == aoFields.end())
200
0
                    {
201
0
                        whileUnsealing(poLayerDefn)->DeleteFieldDefn(i);
202
0
                    }
203
0
                }
204
0
            }
205
0
        }
206
0
    }
207
0
    return true;
208
0
}
209
210
/************************************************************************/
211
/*                           Open()                                     */
212
/************************************************************************/
213
214
int OGRGeoJSONDataSource::Open(GDALOpenInfo *poOpenInfo,
215
                               GeoJSONSourceType nSrcType,
216
                               const char *pszJSonFlavor)
217
0
{
218
0
    osJSonFlavor_ = pszJSonFlavor;
219
220
0
    const char *pszUnprefixed = poOpenInfo->pszFilename;
221
0
    if (STARTS_WITH_CI(pszUnprefixed, pszJSonFlavor) &&
222
0
        pszUnprefixed[strlen(pszJSonFlavor)] == ':')
223
0
    {
224
0
        pszUnprefixed += strlen(pszJSonFlavor) + 1;
225
0
    }
226
227
0
    if (eGeoJSONSourceService == nSrcType)
228
0
    {
229
0
        if (!ReadFromService(poOpenInfo, pszUnprefixed))
230
0
            return FALSE;
231
0
        if (poOpenInfo->eAccess == GA_Update)
232
0
        {
233
0
            CPLError(CE_Failure, CPLE_NotSupported,
234
0
                     "Update from remote service not supported");
235
0
            return FALSE;
236
0
        }
237
0
    }
238
0
    else if (eGeoJSONSourceText == nSrcType)
239
0
    {
240
0
        if (poOpenInfo->eAccess == GA_Update)
241
0
        {
242
0
            CPLError(CE_Failure, CPLE_NotSupported,
243
0
                     "Update from inline definition not supported");
244
0
            return FALSE;
245
0
        }
246
0
        pszGeoData_ = CPLStrdup(pszUnprefixed);
247
0
    }
248
0
    else if (eGeoJSONSourceFile == nSrcType)
249
0
    {
250
0
        if (poOpenInfo->eAccess == GA_Update &&
251
0
            !EQUAL(pszJSonFlavor, "GeoJSON"))
252
0
        {
253
0
            CPLError(CE_Failure, CPLE_NotSupported,
254
0
                     "Update of %s not supported", pszJSonFlavor);
255
0
            return FALSE;
256
0
        }
257
0
        pszName_ = CPLStrdup(pszUnprefixed);
258
0
        bUpdatable_ = (poOpenInfo->eAccess == GA_Update);
259
260
0
        if (!EQUAL(pszUnprefixed, poOpenInfo->pszFilename))
261
0
        {
262
0
            GDALOpenInfo oOpenInfo(pszUnprefixed, GA_ReadOnly);
263
0
            if (oOpenInfo.fpL == nullptr || oOpenInfo.pabyHeader == nullptr)
264
0
                return FALSE;
265
0
            pszGeoData_ =
266
0
                CPLStrdup(reinterpret_cast<const char *>(oOpenInfo.pabyHeader));
267
0
        }
268
0
        else if (poOpenInfo->fpL == nullptr)
269
0
            return FALSE;
270
0
        else
271
0
        {
272
0
            pszGeoData_ = CPLStrdup(
273
0
                reinterpret_cast<const char *>(poOpenInfo->pabyHeader));
274
0
        }
275
0
    }
276
0
    else
277
0
    {
278
0
        Clear();
279
0
        return FALSE;
280
0
    }
281
282
    /* -------------------------------------------------------------------- */
283
    /*      Construct OGR layer and feature objects from                    */
284
    /*      GeoJSON text tree.                                              */
285
    /* -------------------------------------------------------------------- */
286
0
    if (nullptr == pszGeoData_ ||
287
0
        STARTS_WITH(pszGeoData_, "{\"couchdb\":\"Welcome\"") ||
288
0
        STARTS_WITH(pszGeoData_, "{\"db_name\":\"") ||
289
0
        STARTS_WITH(pszGeoData_, "{\"total_rows\":") ||
290
0
        STARTS_WITH(pszGeoData_, "{\"rows\":["))
291
0
    {
292
0
        Clear();
293
0
        return FALSE;
294
0
    }
295
296
0
    SetDescription(poOpenInfo->pszFilename);
297
0
    LoadLayers(poOpenInfo, nSrcType, pszUnprefixed, pszJSonFlavor);
298
299
0
    if (!DealWithOgrSchemaOpenOption(poOpenInfo))
300
0
    {
301
0
        Clear();
302
0
        return FALSE;
303
0
    }
304
305
0
    if (nLayers_ == 0)
306
0
    {
307
0
        bool bEmitError = true;
308
0
        if (eGeoJSONSourceService == nSrcType)
309
0
        {
310
0
            const CPLString osTmpFilename =
311
0
                VSIMemGenerateHiddenFilename(CPLSPrintf(
312
0
                    "geojson_%s", CPLGetFilename(poOpenInfo->pszFilename)));
313
0
            VSIFCloseL(VSIFileFromMemBuffer(osTmpFilename, (GByte *)pszGeoData_,
314
0
                                            nGeoDataLen_, TRUE));
315
0
            pszGeoData_ = nullptr;
316
0
            if (GDALIdentifyDriver(osTmpFilename, nullptr))
317
0
                bEmitError = false;
318
0
            VSIUnlink(osTmpFilename);
319
0
        }
320
0
        Clear();
321
322
0
        if (bEmitError)
323
0
        {
324
0
            CPLError(CE_Failure, CPLE_OpenFailed, "Failed to read %s data",
325
0
                     pszJSonFlavor);
326
0
        }
327
0
        return FALSE;
328
0
    }
329
330
0
    return TRUE;
331
0
}
332
333
/************************************************************************/
334
/*                           GetLayerCount()                            */
335
/************************************************************************/
336
337
int OGRGeoJSONDataSource::GetLayerCount()
338
0
{
339
0
    return nLayers_;
340
0
}
341
342
/************************************************************************/
343
/*                           GetLayer()                                 */
344
/************************************************************************/
345
346
OGRLayer *OGRGeoJSONDataSource::GetLayer(int nLayer)
347
0
{
348
0
    if (0 <= nLayer && nLayer < nLayers_)
349
0
    {
350
0
        if (papoLayers_)
351
0
            return papoLayers_[nLayer];
352
0
        else
353
0
            return papoLayersWriter_[nLayer];
354
0
    }
355
356
0
    return nullptr;
357
0
}
358
359
/************************************************************************/
360
/*                           ICreateLayer()                             */
361
/************************************************************************/
362
363
OGRLayer *
364
OGRGeoJSONDataSource::ICreateLayer(const char *pszNameIn,
365
                                   const OGRGeomFieldDefn *poSrcGeomFieldDefn,
366
                                   CSLConstList papszOptions)
367
0
{
368
0
    if (nullptr == fpOut_)
369
0
    {
370
0
        CPLError(CE_Failure, CPLE_NotSupported,
371
0
                 "GeoJSON driver doesn't support creating a layer "
372
0
                 "on a read-only datasource");
373
0
        return nullptr;
374
0
    }
375
376
0
    if (nLayers_ != 0)
377
0
    {
378
0
        CPLError(CE_Failure, CPLE_NotSupported,
379
0
                 "GeoJSON driver doesn't support creating more than one layer");
380
0
        return nullptr;
381
0
    }
382
383
0
    const auto eGType =
384
0
        poSrcGeomFieldDefn ? poSrcGeomFieldDefn->GetType() : wkbNone;
385
0
    const auto poSRS =
386
0
        poSrcGeomFieldDefn ? poSrcGeomFieldDefn->GetSpatialRef() : nullptr;
387
388
0
    const char *pszForeignMembersCollection =
389
0
        CSLFetchNameValue(papszOptions, "FOREIGN_MEMBERS_COLLECTION");
390
0
    if (pszForeignMembersCollection)
391
0
    {
392
0
        if (pszForeignMembersCollection[0] != '{' ||
393
0
            pszForeignMembersCollection[strlen(pszForeignMembersCollection) -
394
0
                                        1] != '}')
395
0
        {
396
0
            CPLError(CE_Failure, CPLE_AppDefined,
397
0
                     "Value of FOREIGN_MEMBERS_COLLECTION should start with { "
398
0
                     "and end with }");
399
0
            return nullptr;
400
0
        }
401
0
        json_object *poTmp = nullptr;
402
0
        if (!OGRJSonParse(pszForeignMembersCollection, &poTmp, false))
403
0
        {
404
0
            pszForeignMembersCollection = nullptr;
405
0
        }
406
0
        json_object_put(poTmp);
407
0
        if (!pszForeignMembersCollection)
408
0
        {
409
0
            CPLError(CE_Failure, CPLE_AppDefined,
410
0
                     "Value of FOREIGN_MEMBERS_COLLECTION is invalid JSON");
411
0
            return nullptr;
412
0
        }
413
0
    }
414
415
0
    std::string osForeignMembersFeature =
416
0
        CSLFetchNameValueDef(papszOptions, "FOREIGN_MEMBERS_FEATURE", "");
417
0
    if (!osForeignMembersFeature.empty())
418
0
    {
419
0
        if (osForeignMembersFeature.front() != '{' ||
420
0
            osForeignMembersFeature.back() != '}')
421
0
        {
422
0
            CPLError(CE_Failure, CPLE_AppDefined,
423
0
                     "Value of FOREIGN_MEMBERS_FEATURE should start with { and "
424
0
                     "end with }");
425
0
            return nullptr;
426
0
        }
427
0
        json_object *poTmp = nullptr;
428
0
        if (!OGRJSonParse(osForeignMembersFeature.c_str(), &poTmp, false))
429
0
        {
430
0
            osForeignMembersFeature.clear();
431
0
        }
432
0
        json_object_put(poTmp);
433
0
        if (osForeignMembersFeature.empty())
434
0
        {
435
0
            CPLError(CE_Failure, CPLE_AppDefined,
436
0
                     "Value of FOREIGN_MEMBERS_FEATURE is invalid JSON");
437
0
            return nullptr;
438
0
        }
439
0
    }
440
441
0
    VSIFPrintfL(fpOut_, "{\n\"type\": \"FeatureCollection\",\n");
442
443
0
    if (pszForeignMembersCollection)
444
0
    {
445
0
        VSIFWriteL(pszForeignMembersCollection + 1, 1,
446
0
                   strlen(pszForeignMembersCollection) - 2, fpOut_);
447
0
        VSIFWriteL(",\n", 2, 1, fpOut_);
448
0
    }
449
450
0
    bool bWriteFC_BBOX =
451
0
        CPLTestBool(CSLFetchNameValueDef(papszOptions, "WRITE_BBOX", "FALSE"));
452
453
0
    const bool bRFC7946 =
454
0
        CPLTestBool(CSLFetchNameValueDef(papszOptions, "RFC7946", "FALSE"));
455
456
0
    const char *pszNativeData = CSLFetchNameValue(papszOptions, "NATIVE_DATA");
457
0
    const char *pszNativeMediaType =
458
0
        CSLFetchNameValue(papszOptions, "NATIVE_MEDIA_TYPE");
459
0
    bool bWriteCRSIfWGS84 = true;
460
0
    bool bFoundNameInNativeData = false;
461
0
    if (pszNativeData && pszNativeMediaType &&
462
0
        EQUAL(pszNativeMediaType, "application/vnd.geo+json"))
463
0
    {
464
0
        json_object *poObj = nullptr;
465
0
        if (OGRJSonParse(pszNativeData, &poObj) &&
466
0
            json_object_get_type(poObj) == json_type_object)
467
0
        {
468
0
            json_object_iter it;
469
0
            it.key = nullptr;
470
0
            it.val = nullptr;
471
0
            it.entry = nullptr;
472
0
            CPLString osNativeData;
473
0
            bWriteCRSIfWGS84 = false;
474
0
            json_object_object_foreachC(poObj, it)
475
0
            {
476
0
                if (strcmp(it.key, "type") == 0 ||
477
0
                    strcmp(it.key, "features") == 0)
478
0
                {
479
0
                    continue;
480
0
                }
481
0
                if (strcmp(it.key, "bbox") == 0)
482
0
                {
483
0
                    if (CSLFetchNameValue(papszOptions, "WRITE_BBOX") ==
484
0
                        nullptr)
485
0
                        bWriteFC_BBOX = true;
486
0
                    continue;
487
0
                }
488
0
                if (strcmp(it.key, "crs") == 0)
489
0
                {
490
0
                    if (!bRFC7946)
491
0
                        bWriteCRSIfWGS84 = true;
492
0
                    continue;
493
0
                }
494
                // See https://tools.ietf.org/html/rfc7946#section-7.1
495
0
                if (bRFC7946 && (strcmp(it.key, "coordinates") == 0 ||
496
0
                                 strcmp(it.key, "geometries") == 0 ||
497
0
                                 strcmp(it.key, "geometry") == 0 ||
498
0
                                 strcmp(it.key, "properties") == 0))
499
0
                {
500
0
                    continue;
501
0
                }
502
503
0
                if (strcmp(it.key, "name") == 0)
504
0
                {
505
0
                    bFoundNameInNativeData = true;
506
0
                    if (!CPLFetchBool(papszOptions, "WRITE_NAME", true) ||
507
0
                        CSLFetchNameValue(papszOptions, "@NAME") != nullptr)
508
0
                    {
509
0
                        continue;
510
0
                    }
511
0
                }
512
513
                // If a native description exists, ignore it if an explicit
514
                // DESCRIPTION option has been provided.
515
0
                if (strcmp(it.key, "description") == 0 &&
516
0
                    CSLFetchNameValue(papszOptions, "DESCRIPTION"))
517
0
                {
518
0
                    continue;
519
0
                }
520
521
0
                if (strcmp(it.key, "xy_coordinate_resolution") == 0 ||
522
0
                    strcmp(it.key, "z_coordinate_resolution") == 0)
523
0
                {
524
0
                    continue;
525
0
                }
526
527
0
                json_object *poKey = json_object_new_string(it.key);
528
0
                VSIFPrintfL(fpOut_, "%s: ", json_object_to_json_string(poKey));
529
0
                json_object_put(poKey);
530
0
                VSIFPrintfL(fpOut_, "%s,\n",
531
0
                            json_object_to_json_string(it.val));
532
0
            }
533
0
            json_object_put(poObj);
534
0
        }
535
0
    }
536
537
    // Used by ogr2ogr in -nln mode
538
0
    const char *pszAtName = CSLFetchNameValue(papszOptions, "@NAME");
539
0
    if (pszAtName && CPLFetchBool(papszOptions, "WRITE_NAME", true))
540
0
    {
541
0
        json_object *poName = json_object_new_string(pszAtName);
542
0
        VSIFPrintfL(fpOut_, "\"name\": %s,\n",
543
0
                    json_object_to_json_string(poName));
544
0
        json_object_put(poName);
545
0
    }
546
0
    else if (!bFoundNameInNativeData &&
547
0
             CPLFetchBool(papszOptions, "WRITE_NAME", true) &&
548
0
             !EQUAL(pszNameIn, OGRGeoJSONLayer::DefaultName) &&
549
0
             !EQUAL(pszNameIn, ""))
550
0
    {
551
0
        json_object *poName = json_object_new_string(pszNameIn);
552
0
        VSIFPrintfL(fpOut_, "\"name\": %s,\n",
553
0
                    json_object_to_json_string(poName));
554
0
        json_object_put(poName);
555
0
    }
556
557
0
    const char *pszDescription = CSLFetchNameValue(papszOptions, "DESCRIPTION");
558
0
    if (pszDescription)
559
0
    {
560
0
        json_object *poDesc = json_object_new_string(pszDescription);
561
0
        VSIFPrintfL(fpOut_, "\"description\": %s,\n",
562
0
                    json_object_to_json_string(poDesc));
563
0
        json_object_put(poDesc);
564
0
    }
565
566
0
    OGRCoordinateTransformation *poCT = nullptr;
567
0
    if (bRFC7946)
568
0
    {
569
0
        if (poSRS == nullptr)
570
0
        {
571
0
            CPLError(CE_Warning, CPLE_AppDefined,
572
0
                     "No SRS set on layer. Assuming it is long/lat on WGS84 "
573
0
                     "ellipsoid");
574
0
        }
575
0
        else if (poSRS->GetAxesCount() == 3)
576
0
        {
577
0
            OGRSpatialReference oSRS_EPSG_4979;
578
0
            oSRS_EPSG_4979.importFromEPSG(4979);
579
0
            oSRS_EPSG_4979.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
580
0
            if (!poSRS->IsSame(&oSRS_EPSG_4979))
581
0
            {
582
0
                poCT =
583
0
                    OGRCreateCoordinateTransformation(poSRS, &oSRS_EPSG_4979);
584
0
                if (poCT == nullptr)
585
0
                {
586
0
                    CPLError(CE_Warning, CPLE_AppDefined,
587
0
                             "Failed to create coordinate transformation "
588
0
                             "between the "
589
0
                             "input coordinate system and WGS84.");
590
591
0
                    return nullptr;
592
0
                }
593
0
            }
594
0
        }
595
0
        else
596
0
        {
597
0
            OGRSpatialReference oSRSWGS84;
598
0
            oSRSWGS84.SetWellKnownGeogCS("WGS84");
599
0
            oSRSWGS84.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
600
0
            if (!poSRS->IsSame(&oSRSWGS84))
601
0
            {
602
0
                poCT = OGRCreateCoordinateTransformation(poSRS, &oSRSWGS84);
603
0
                if (poCT == nullptr)
604
0
                {
605
0
                    CPLError(CE_Warning, CPLE_AppDefined,
606
0
                             "Failed to create coordinate transformation "
607
0
                             "between the "
608
0
                             "input coordinate system and WGS84.");
609
610
0
                    return nullptr;
611
0
                }
612
0
            }
613
0
        }
614
0
    }
615
0
    else if (poSRS)
616
0
    {
617
0
        char *pszOGCURN = poSRS->GetOGCURN();
618
0
        if (pszOGCURN != nullptr &&
619
0
            (bWriteCRSIfWGS84 ||
620
0
             !EQUAL(pszOGCURN, "urn:ogc:def:crs:EPSG::4326")))
621
0
        {
622
0
            json_object *poObjCRS = json_object_new_object();
623
0
            json_object_object_add(poObjCRS, "type",
624
0
                                   json_object_new_string("name"));
625
0
            json_object *poObjProperties = json_object_new_object();
626
0
            json_object_object_add(poObjCRS, "properties", poObjProperties);
627
628
0
            if (EQUAL(pszOGCURN, "urn:ogc:def:crs:EPSG::4326"))
629
0
            {
630
0
                json_object_object_add(
631
0
                    poObjProperties, "name",
632
0
                    json_object_new_string("urn:ogc:def:crs:OGC:1.3:CRS84"));
633
0
            }
634
0
            else
635
0
            {
636
0
                json_object_object_add(poObjProperties, "name",
637
0
                                       json_object_new_string(pszOGCURN));
638
0
            }
639
640
0
            const char *pszCRS = json_object_to_json_string(poObjCRS);
641
0
            VSIFPrintfL(fpOut_, "\"crs\": %s,\n", pszCRS);
642
643
0
            json_object_put(poObjCRS);
644
0
        }
645
0
        CPLFree(pszOGCURN);
646
0
    }
647
648
0
    CPLStringList aosOptions(papszOptions);
649
650
0
    double dfXYResolution = OGRGeomCoordinatePrecision::UNKNOWN;
651
0
    double dfZResolution = OGRGeomCoordinatePrecision::UNKNOWN;
652
653
0
    if (const char *pszCoordPrecision =
654
0
            CSLFetchNameValue(papszOptions, "COORDINATE_PRECISION"))
655
0
    {
656
0
        dfXYResolution = std::pow(10.0, -CPLAtof(pszCoordPrecision));
657
0
        dfZResolution = dfXYResolution;
658
0
        VSIFPrintfL(fpOut_, "\"xy_coordinate_resolution\": %g,\n",
659
0
                    dfXYResolution);
660
0
        if (poSRS && poSRS->GetAxesCount() == 3)
661
0
        {
662
0
            VSIFPrintfL(fpOut_, "\"z_coordinate_resolution\": %g,\n",
663
0
                        dfZResolution);
664
0
        }
665
0
    }
666
0
    else if (poSrcGeomFieldDefn)
667
0
    {
668
0
        const auto &oCoordPrec = poSrcGeomFieldDefn->GetCoordinatePrecision();
669
0
        OGRSpatialReference oSRSWGS84;
670
0
        oSRSWGS84.SetWellKnownGeogCS("WGS84");
671
0
        const auto oCoordPrecWGS84 =
672
0
            oCoordPrec.ConvertToOtherSRS(poSRS, &oSRSWGS84);
673
674
0
        if (oCoordPrec.dfXYResolution != OGRGeomCoordinatePrecision::UNKNOWN)
675
0
        {
676
0
            dfXYResolution = poSRS && bRFC7946 ? oCoordPrecWGS84.dfXYResolution
677
0
                                               : oCoordPrec.dfXYResolution;
678
679
0
            aosOptions.SetNameValue(
680
0
                "XY_COORD_PRECISION",
681
0
                CPLSPrintf("%d",
682
0
                           OGRGeomCoordinatePrecision::ResolutionToPrecision(
683
0
                               dfXYResolution)));
684
0
            VSIFPrintfL(fpOut_, "\"xy_coordinate_resolution\": %g,\n",
685
0
                        dfXYResolution);
686
0
        }
687
0
        if (oCoordPrec.dfZResolution != OGRGeomCoordinatePrecision::UNKNOWN)
688
0
        {
689
0
            dfZResolution = poSRS && bRFC7946 ? oCoordPrecWGS84.dfZResolution
690
0
                                              : oCoordPrec.dfZResolution;
691
692
0
            aosOptions.SetNameValue(
693
0
                "Z_COORD_PRECISION",
694
0
                CPLSPrintf("%d",
695
0
                           OGRGeomCoordinatePrecision::ResolutionToPrecision(
696
0
                               dfZResolution)));
697
0
            VSIFPrintfL(fpOut_, "\"z_coordinate_resolution\": %g,\n",
698
0
                        dfZResolution);
699
0
        }
700
0
    }
701
702
0
    if (bFpOutputIsSeekable_ && bWriteFC_BBOX)
703
0
    {
704
0
        nBBOXInsertLocation_ = static_cast<int>(VSIFTellL(fpOut_));
705
706
0
        const std::string osSpaceForBBOX(SPACE_FOR_BBOX + 1, ' ');
707
0
        VSIFPrintfL(fpOut_, "%s\n", osSpaceForBBOX.c_str());
708
0
    }
709
710
0
    VSIFPrintfL(fpOut_, "\"features\": [\n");
711
712
0
    OGRGeoJSONWriteLayer *poLayer = new OGRGeoJSONWriteLayer(
713
0
        pszNameIn, eGType, aosOptions.List(), bWriteFC_BBOX, poCT, this);
714
715
0
    if (eGType != wkbNone &&
716
0
        dfXYResolution != OGRGeomCoordinatePrecision::UNKNOWN)
717
0
    {
718
0
        auto poGeomFieldDefn = poLayer->GetLayerDefn()->GetGeomFieldDefn(0);
719
0
        OGRGeomCoordinatePrecision oCoordPrec(
720
0
            poGeomFieldDefn->GetCoordinatePrecision());
721
0
        oCoordPrec.dfXYResolution = dfXYResolution;
722
0
        poGeomFieldDefn->SetCoordinatePrecision(oCoordPrec);
723
0
    }
724
725
0
    if (eGType != wkbNone &&
726
0
        dfZResolution != OGRGeomCoordinatePrecision::UNKNOWN)
727
0
    {
728
0
        auto poGeomFieldDefn = poLayer->GetLayerDefn()->GetGeomFieldDefn(0);
729
0
        OGRGeomCoordinatePrecision oCoordPrec(
730
0
            poGeomFieldDefn->GetCoordinatePrecision());
731
0
        oCoordPrec.dfZResolution = dfZResolution;
732
0
        poGeomFieldDefn->SetCoordinatePrecision(oCoordPrec);
733
0
    }
734
735
    /* -------------------------------------------------------------------- */
736
    /*      Add layer to data source layer list.                            */
737
    /* -------------------------------------------------------------------- */
738
0
    CPLAssert(papoLayers_ == nullptr);
739
0
    papoLayersWriter_ = static_cast<OGRGeoJSONWriteLayer **>(CPLRealloc(
740
0
        papoLayers_, sizeof(OGRGeoJSONWriteLayer *) * (nLayers_ + 1)));
741
742
0
    papoLayersWriter_[nLayers_++] = poLayer;
743
744
0
    return poLayer;
745
0
}
746
747
/************************************************************************/
748
/*                           TestCapability()                           */
749
/************************************************************************/
750
751
int OGRGeoJSONDataSource::TestCapability(const char *pszCap)
752
0
{
753
0
    if (EQUAL(pszCap, ODsCCreateLayer))
754
0
        return fpOut_ != nullptr && nLayers_ == 0;
755
0
    else if (EQUAL(pszCap, ODsCMeasuredGeometries))
756
0
        return m_bSupportsMGeometries;
757
0
    else if (EQUAL(pszCap, ODsCZGeometries))
758
0
        return m_bSupportsZGeometries;
759
760
0
    return FALSE;
761
0
}
762
763
/************************************************************************/
764
/*                              Create()                                */
765
/************************************************************************/
766
767
int OGRGeoJSONDataSource::Create(const char *pszName,
768
                                 char ** /* papszOptions */)
769
0
{
770
0
    CPLAssert(nullptr == fpOut_);
771
772
0
    if (strcmp(pszName, "/dev/stdout") == 0)
773
0
        pszName = "/vsistdout/";
774
775
0
    bFpOutputIsSeekable_ = !(strcmp(pszName, "/vsistdout/") == 0 ||
776
0
                             STARTS_WITH(pszName, "/vsigzip/") ||
777
0
                             STARTS_WITH(pszName, "/vsizip/"));
778
779
    /* -------------------------------------------------------------------- */
780
    /*     File overwrite not supported.                                    */
781
    /* -------------------------------------------------------------------- */
782
0
    VSIStatBufL sStatBuf;
783
0
    if (0 == VSIStatL(pszName, &sStatBuf))
784
0
    {
785
0
        CPLError(CE_Failure, CPLE_NotSupported,
786
0
                 "The GeoJSON driver does not overwrite existing files.");
787
0
        return FALSE;
788
0
    }
789
790
    /* -------------------------------------------------------------------- */
791
    /*      Create the output file.                                         */
792
    /* -------------------------------------------------------------------- */
793
0
    fpOut_ = VSIFOpenExL(pszName, "w", true);
794
0
    if (nullptr == fpOut_)
795
0
    {
796
0
        CPLError(CE_Failure, CPLE_OpenFailed,
797
0
                 "Failed to create GeoJSON datasource: %s: %s", pszName,
798
0
                 VSIGetLastErrorMsg());
799
0
        return FALSE;
800
0
    }
801
802
0
    pszName_ = CPLStrdup(pszName);
803
804
0
    return TRUE;
805
0
}
806
807
/************************************************************************/
808
/*                           SetGeometryTranslation()                   */
809
/************************************************************************/
810
811
void OGRGeoJSONDataSource::SetGeometryTranslation(GeometryTranslation type)
812
0
{
813
0
    flTransGeom_ = type;
814
0
}
815
816
/************************************************************************/
817
/*                           SetAttributesTranslation()                 */
818
/************************************************************************/
819
820
void OGRGeoJSONDataSource::SetAttributesTranslation(AttributesTranslation type)
821
0
{
822
0
    flTransAttrs_ = type;
823
0
}
824
825
/************************************************************************/
826
/*                  PRIVATE FUNCTIONS IMPLEMENTATION                    */
827
/************************************************************************/
828
829
bool OGRGeoJSONDataSource::Clear()
830
0
{
831
0
    for (int i = 0; i < nLayers_; i++)
832
0
    {
833
0
        if (papoLayers_ != nullptr)
834
0
            delete papoLayers_[i];
835
0
        else
836
0
            delete papoLayersWriter_[i];
837
0
    }
838
839
0
    CPLFree(papoLayers_);
840
0
    papoLayers_ = nullptr;
841
0
    CPLFree(papoLayersWriter_);
842
0
    papoLayersWriter_ = nullptr;
843
0
    nLayers_ = 0;
844
845
0
    CPLFree(pszName_);
846
0
    pszName_ = nullptr;
847
848
0
    CPLFree(pszGeoData_);
849
0
    pszGeoData_ = nullptr;
850
0
    nGeoDataLen_ = 0;
851
852
0
    bool bRet = true;
853
0
    if (fpOut_)
854
0
    {
855
0
        if (VSIFCloseL(fpOut_) != 0)
856
0
            bRet = false;
857
0
        fpOut_ = nullptr;
858
0
    }
859
0
    return bRet;
860
0
}
861
862
/************************************************************************/
863
/*                           ReadFromFile()                             */
864
/************************************************************************/
865
866
int OGRGeoJSONDataSource::ReadFromFile(GDALOpenInfo *poOpenInfo,
867
                                       const char *pszUnprefixed)
868
0
{
869
0
    GByte *pabyOut = nullptr;
870
0
    if (!EQUAL(poOpenInfo->pszFilename, pszUnprefixed))
871
0
    {
872
0
        GDALOpenInfo oOpenInfo(pszUnprefixed, GA_ReadOnly);
873
0
        if (oOpenInfo.fpL == nullptr || oOpenInfo.pabyHeader == nullptr)
874
0
            return FALSE;
875
0
        VSIFSeekL(oOpenInfo.fpL, 0, SEEK_SET);
876
0
        if (!VSIIngestFile(oOpenInfo.fpL, pszUnprefixed, &pabyOut, nullptr, -1))
877
0
        {
878
0
            return FALSE;
879
0
        }
880
0
    }
881
0
    else
882
0
    {
883
0
        if (poOpenInfo->fpL == nullptr)
884
0
            return FALSE;
885
0
        VSIFSeekL(poOpenInfo->fpL, 0, SEEK_SET);
886
0
        if (!VSIIngestFile(poOpenInfo->fpL, poOpenInfo->pszFilename, &pabyOut,
887
0
                           nullptr, -1))
888
0
        {
889
0
            return FALSE;
890
0
        }
891
892
0
        VSIFCloseL(poOpenInfo->fpL);
893
0
        poOpenInfo->fpL = nullptr;
894
0
    }
895
896
0
    CPLFree(pszGeoData_);
897
0
    pszGeoData_ = reinterpret_cast<char *>(pabyOut);
898
899
0
    CPLAssert(nullptr != pszGeoData_);
900
901
0
    return TRUE;
902
0
}
903
904
/************************************************************************/
905
/*                           ReadFromService()                          */
906
/************************************************************************/
907
908
int OGRGeoJSONDataSource::ReadFromService(GDALOpenInfo *poOpenInfo,
909
                                          const char *pszSource)
910
0
{
911
0
    CPLAssert(nullptr == pszGeoData_);
912
0
    CPLAssert(nullptr != pszSource);
913
914
0
    CPLErrorReset();
915
916
    /* -------------------------------------------------------------------- */
917
    /*      Look if we already cached the content.                          */
918
    /* -------------------------------------------------------------------- */
919
0
    char *pszStoredContent = OGRGeoJSONDriverStealStoredContent(pszSource);
920
0
    if (pszStoredContent != nullptr)
921
0
    {
922
0
        if (!EQUAL(pszStoredContent, INVALID_CONTENT_FOR_JSON_LIKE) &&
923
0
            ((osJSonFlavor_ == "ESRIJSON" &&
924
0
              ESRIJSONIsObject(pszStoredContent, poOpenInfo)) ||
925
0
             (osJSonFlavor_ == "TopoJSON" &&
926
0
              TopoJSONIsObject(pszStoredContent, poOpenInfo))))
927
0
        {
928
0
            pszGeoData_ = pszStoredContent;
929
0
            nGeoDataLen_ = strlen(pszGeoData_);
930
931
0
            pszName_ = CPLStrdup(pszSource);
932
0
            return true;
933
0
        }
934
935
0
        OGRGeoJSONDriverStoreContent(pszSource, pszStoredContent);
936
0
        return false;
937
0
    }
938
939
    /* -------------------------------------------------------------------- */
940
    /*      Fetch the GeoJSON result.                                        */
941
    /* -------------------------------------------------------------------- */
942
0
    CPLHTTPResult *pResult = GeoJSONHTTPFetchWithContentTypeHeader(pszSource);
943
0
    if (!pResult)
944
0
    {
945
0
        return FALSE;
946
0
    }
947
948
    /* -------------------------------------------------------------------- */
949
    /*      Copy returned GeoJSON data to text buffer.                      */
950
    /* -------------------------------------------------------------------- */
951
0
    char *pszData = reinterpret_cast<char *>(pResult->pabyData);
952
953
    // Directly assign CPLHTTPResult::pabyData to pszGeoData_.
954
0
    pszGeoData_ = pszData;
955
0
    nGeoDataLen_ = pResult->nDataLen;
956
0
    pResult->pabyData = nullptr;
957
0
    pResult->nDataLen = 0;
958
959
0
    pszName_ = CPLStrdup(pszSource);
960
961
    /* -------------------------------------------------------------------- */
962
    /*      Cleanup HTTP resources.                                         */
963
    /* -------------------------------------------------------------------- */
964
0
    CPLHTTPDestroyResult(pResult);
965
966
0
    CPLAssert(nullptr != pszGeoData_);
967
968
    /* -------------------------------------------------------------------- */
969
    /*      Cache the content if it is not handled by this driver, but      */
970
    /*      another related one.                                            */
971
    /* -------------------------------------------------------------------- */
972
0
    if (EQUAL(pszSource, poOpenInfo->pszFilename) && osJSonFlavor_ == "GeoJSON")
973
0
    {
974
0
        if (!GeoJSONIsObject(pszGeoData_, poOpenInfo))
975
0
        {
976
0
            if (ESRIJSONIsObject(pszGeoData_, poOpenInfo) ||
977
0
                TopoJSONIsObject(pszGeoData_, poOpenInfo) ||
978
0
                GeoJSONSeqIsObject(pszGeoData_, poOpenInfo) ||
979
0
                JSONFGIsObject(pszGeoData_, poOpenInfo))
980
0
            {
981
0
                OGRGeoJSONDriverStoreContent(pszSource, pszGeoData_);
982
0
                pszGeoData_ = nullptr;
983
0
                nGeoDataLen_ = 0;
984
0
            }
985
0
            else
986
0
            {
987
0
                OGRGeoJSONDriverStoreContent(
988
0
                    pszSource, CPLStrdup(INVALID_CONTENT_FOR_JSON_LIKE));
989
0
            }
990
0
            return false;
991
0
        }
992
0
    }
993
994
0
    return TRUE;
995
0
}
996
997
/************************************************************************/
998
/*                       RemoveJSonPStuff()                             */
999
/************************************************************************/
1000
1001
void OGRGeoJSONDataSource::RemoveJSonPStuff()
1002
0
{
1003
0
    const char *const apszPrefix[] = {"loadGeoJSON(", "jsonp("};
1004
0
    for (size_t iP = 0; iP < CPL_ARRAYSIZE(apszPrefix); iP++)
1005
0
    {
1006
0
        if (strncmp(pszGeoData_, apszPrefix[iP], strlen(apszPrefix[iP])) == 0)
1007
0
        {
1008
0
            const size_t nDataLen = strlen(pszGeoData_);
1009
0
            memmove(pszGeoData_, pszGeoData_ + strlen(apszPrefix[iP]),
1010
0
                    nDataLen - strlen(apszPrefix[iP]));
1011
0
            size_t i = nDataLen - strlen(apszPrefix[iP]);
1012
0
            pszGeoData_[i] = '\0';
1013
0
            while (i > 0 && pszGeoData_[i] != ')')
1014
0
            {
1015
0
                i--;
1016
0
            }
1017
0
            pszGeoData_[i] = '\0';
1018
0
        }
1019
0
    }
1020
0
}
1021
1022
/************************************************************************/
1023
/*                           LoadLayers()                               */
1024
/************************************************************************/
1025
1026
void OGRGeoJSONDataSource::LoadLayers(GDALOpenInfo *poOpenInfo,
1027
                                      GeoJSONSourceType nSrcType,
1028
                                      const char *pszUnprefixed,
1029
                                      const char *pszJSonFlavor)
1030
0
{
1031
0
    if (nullptr == pszGeoData_)
1032
0
    {
1033
0
        CPLError(CE_Failure, CPLE_ObjectNull, "%s data buffer empty",
1034
0
                 pszJSonFlavor);
1035
0
        return;
1036
0
    }
1037
1038
0
    if (nSrcType != eGeoJSONSourceFile)
1039
0
    {
1040
0
        RemoveJSonPStuff();
1041
0
    }
1042
1043
    /* -------------------------------------------------------------------- */
1044
    /*      Is it ESRI Feature Service data ?                               */
1045
    /* -------------------------------------------------------------------- */
1046
0
    if (EQUAL(pszJSonFlavor, "ESRIJSON"))
1047
0
    {
1048
0
        OGRESRIJSONReader reader;
1049
0
        if (nSrcType == eGeoJSONSourceFile)
1050
0
        {
1051
0
            if (!ReadFromFile(poOpenInfo, pszUnprefixed))
1052
0
                return;
1053
0
        }
1054
0
        OGRErr err = reader.Parse(pszGeoData_);
1055
0
        if (OGRERR_NONE == err)
1056
0
        {
1057
0
            json_object *poObj = reader.GetJSonObject();
1058
0
            CheckExceededTransferLimit(poObj);
1059
0
            reader.ReadLayers(this, nSrcType);
1060
0
        }
1061
0
        return;
1062
0
    }
1063
1064
    /* -------------------------------------------------------------------- */
1065
    /*      Is it TopoJSON data ?                                           */
1066
    /* -------------------------------------------------------------------- */
1067
0
    if (EQUAL(pszJSonFlavor, "TOPOJSON"))
1068
0
    {
1069
0
        OGRTopoJSONReader reader;
1070
0
        if (nSrcType == eGeoJSONSourceFile)
1071
0
        {
1072
0
            if (!ReadFromFile(poOpenInfo, pszUnprefixed))
1073
0
                return;
1074
0
        }
1075
0
        OGRErr err = reader.Parse(
1076
0
            pszGeoData_,
1077
0
            nSrcType == eGeoJSONSourceService &&
1078
0
                !STARTS_WITH_CI(poOpenInfo->pszFilename, "TopoJSON:"));
1079
0
        if (OGRERR_NONE == err)
1080
0
        {
1081
0
            reader.ReadLayers(this);
1082
0
        }
1083
0
        return;
1084
0
    }
1085
1086
0
    VSILFILE *fp = nullptr;
1087
0
    if (nSrcType == eGeoJSONSourceFile &&
1088
0
        !EQUAL(poOpenInfo->pszFilename, pszUnprefixed))
1089
0
    {
1090
0
        GDALOpenInfo oOpenInfo(pszUnprefixed, GA_ReadOnly);
1091
0
        if (oOpenInfo.fpL == nullptr || oOpenInfo.pabyHeader == nullptr)
1092
0
            return;
1093
0
        CPL_IGNORE_RET_VAL(oOpenInfo.TryToIngest(6000));
1094
0
        CPLFree(pszGeoData_);
1095
0
        pszGeoData_ =
1096
0
            CPLStrdup(reinterpret_cast<const char *>(oOpenInfo.pabyHeader));
1097
0
        fp = oOpenInfo.fpL;
1098
0
        oOpenInfo.fpL = nullptr;
1099
0
    }
1100
1101
0
    if (!GeoJSONIsObject(pszGeoData_, poOpenInfo))
1102
0
    {
1103
0
        CPLDebug(pszJSonFlavor, "No valid %s data found in source '%s'",
1104
0
                 pszJSonFlavor, pszName_);
1105
0
        if (fp)
1106
0
            VSIFCloseL(fp);
1107
0
        return;
1108
0
    }
1109
1110
    /* -------------------------------------------------------------------- */
1111
    /*      Configure GeoJSON format translator.                            */
1112
    /* -------------------------------------------------------------------- */
1113
0
    OGRGeoJSONReader *poReader = new OGRGeoJSONReader();
1114
0
    SetOptionsOnReader(poOpenInfo, poReader);
1115
1116
    /* -------------------------------------------------------------------- */
1117
    /*      Parse GeoJSON and build valid OGRLayer instance.                */
1118
    /* -------------------------------------------------------------------- */
1119
0
    bool bUseStreamingInterface = false;
1120
0
    const GIntBig nMaxBytesFirstPass = CPLAtoGIntBig(
1121
0
        CPLGetConfigOption("OGR_GEOJSON_MAX_BYTES_FIRST_PASS", "0"));
1122
0
    if ((fp != nullptr || poOpenInfo->fpL != nullptr) &&
1123
0
        (!STARTS_WITH(pszUnprefixed, "/vsistdin/") ||
1124
0
         (nMaxBytesFirstPass > 0 && nMaxBytesFirstPass <= 1000000)))
1125
0
    {
1126
0
        const char *pszStr = strstr(pszGeoData_, "\"features\"");
1127
0
        if (pszStr)
1128
0
        {
1129
0
            pszStr += strlen("\"features\"");
1130
0
            while (*pszStr && isspace(static_cast<unsigned char>(*pszStr)))
1131
0
                pszStr++;
1132
0
            if (*pszStr == ':')
1133
0
            {
1134
0
                pszStr++;
1135
0
                while (*pszStr && isspace(static_cast<unsigned char>(*pszStr)))
1136
0
                    pszStr++;
1137
0
                if (*pszStr == '[')
1138
0
                {
1139
0
                    bUseStreamingInterface = true;
1140
0
                }
1141
0
            }
1142
0
        }
1143
0
    }
1144
1145
0
    if (bUseStreamingInterface)
1146
0
    {
1147
0
        bool bTryStandardReading = false;
1148
0
        if (poReader->FirstPassReadLayer(this, fp ? fp : poOpenInfo->fpL,
1149
0
                                         bTryStandardReading))
1150
0
        {
1151
0
            if (fp)
1152
0
                fp = nullptr;
1153
0
            else
1154
0
                poOpenInfo->fpL = nullptr;
1155
0
            CheckExceededTransferLimit(poReader->GetJSonObject());
1156
0
        }
1157
0
        else
1158
0
        {
1159
0
            delete poReader;
1160
0
        }
1161
0
        if (!bTryStandardReading)
1162
0
        {
1163
0
            if (fp)
1164
0
                VSIFCloseL(fp);
1165
0
            return;
1166
0
        }
1167
1168
0
        poReader = new OGRGeoJSONReader();
1169
0
        SetOptionsOnReader(poOpenInfo, poReader);
1170
0
    }
1171
1172
0
    if (fp)
1173
0
        VSIFCloseL(fp);
1174
0
    if (nSrcType == eGeoJSONSourceFile)
1175
0
    {
1176
0
        if (!ReadFromFile(poOpenInfo, pszUnprefixed))
1177
0
        {
1178
0
            delete poReader;
1179
0
            return;
1180
0
        }
1181
0
        RemoveJSonPStuff();
1182
0
    }
1183
0
    const OGRErr err = poReader->Parse(pszGeoData_);
1184
0
    if (OGRERR_NONE == err)
1185
0
    {
1186
0
        CheckExceededTransferLimit(poReader->GetJSonObject());
1187
0
    }
1188
1189
0
    poReader->ReadLayers(this);
1190
0
    delete poReader;
1191
0
}
1192
1193
/************************************************************************/
1194
/*                          SetOptionsOnReader()                        */
1195
/************************************************************************/
1196
1197
void OGRGeoJSONDataSource::SetOptionsOnReader(GDALOpenInfo *poOpenInfo,
1198
                                              OGRGeoJSONReader *poReader)
1199
0
{
1200
0
    if (eGeometryAsCollection == flTransGeom_)
1201
0
    {
1202
0
        poReader->SetPreserveGeometryType(false);
1203
0
        CPLDebug("GeoJSON", "Geometry as OGRGeometryCollection type.");
1204
0
    }
1205
1206
0
    if (eAttributesSkip == flTransAttrs_)
1207
0
    {
1208
0
        poReader->SetSkipAttributes(true);
1209
0
        CPLDebug("GeoJSON", "Skip all attributes.");
1210
0
    }
1211
1212
0
    poReader->SetFlattenNestedAttributes(
1213
0
        CPLFetchBool(poOpenInfo->papszOpenOptions, "FLATTEN_NESTED_ATTRIBUTES",
1214
0
                     false),
1215
0
        CSLFetchNameValueDef(poOpenInfo->papszOpenOptions,
1216
0
                             "NESTED_ATTRIBUTE_SEPARATOR", "_")[0]);
1217
1218
0
    const bool bDefaultNativeData = bUpdatable_;
1219
0
    poReader->SetStoreNativeData(CPLFetchBool(
1220
0
        poOpenInfo->papszOpenOptions, "NATIVE_DATA", bDefaultNativeData));
1221
1222
0
    poReader->SetArrayAsString(CPLTestBool(CSLFetchNameValueDef(
1223
0
        poOpenInfo->papszOpenOptions, "ARRAY_AS_STRING",
1224
0
        CPLGetConfigOption("OGR_GEOJSON_ARRAY_AS_STRING", "NO"))));
1225
1226
0
    poReader->SetDateAsString(CPLTestBool(CSLFetchNameValueDef(
1227
0
        poOpenInfo->papszOpenOptions, "DATE_AS_STRING",
1228
0
        CPLGetConfigOption("OGR_GEOJSON_DATE_AS_STRING", "NO"))));
1229
1230
0
    const char *pszForeignMembers = CSLFetchNameValueDef(
1231
0
        poOpenInfo->papszOpenOptions, "FOREIGN_MEMBERS", "AUTO");
1232
0
    if (EQUAL(pszForeignMembers, "AUTO"))
1233
0
    {
1234
0
        poReader->SetForeignMemberProcessing(
1235
0
            OGRGeoJSONBaseReader::ForeignMemberProcessing::AUTO);
1236
0
    }
1237
0
    else if (EQUAL(pszForeignMembers, "ALL"))
1238
0
    {
1239
0
        poReader->SetForeignMemberProcessing(
1240
0
            OGRGeoJSONBaseReader::ForeignMemberProcessing::ALL);
1241
0
    }
1242
0
    else if (EQUAL(pszForeignMembers, "NONE"))
1243
0
    {
1244
0
        poReader->SetForeignMemberProcessing(
1245
0
            OGRGeoJSONBaseReader::ForeignMemberProcessing::NONE);
1246
0
    }
1247
0
    else if (EQUAL(pszForeignMembers, "STAC"))
1248
0
    {
1249
0
        poReader->SetForeignMemberProcessing(
1250
0
            OGRGeoJSONBaseReader::ForeignMemberProcessing::STAC);
1251
0
    }
1252
0
}
1253
1254
/************************************************************************/
1255
/*                     CheckExceededTransferLimit()                     */
1256
/************************************************************************/
1257
1258
void OGRGeoJSONDataSource::CheckExceededTransferLimit(json_object *poObj)
1259
0
{
1260
0
    for (int i = 0; i < 2; i++)
1261
0
    {
1262
0
        if (i == 1)
1263
0
        {
1264
0
            if (poObj && json_object_get_type(poObj) == json_type_object)
1265
0
            {
1266
0
                poObj = CPL_json_object_object_get(poObj, "properties");
1267
0
            }
1268
0
        }
1269
0
        if (poObj && json_object_get_type(poObj) == json_type_object)
1270
0
        {
1271
0
            json_object *poExceededTransferLimit =
1272
0
                CPL_json_object_object_get(poObj, "exceededTransferLimit");
1273
0
            if (poExceededTransferLimit &&
1274
0
                json_object_get_type(poExceededTransferLimit) ==
1275
0
                    json_type_boolean)
1276
0
            {
1277
0
                bOtherPages_ = CPL_TO_BOOL(
1278
0
                    json_object_get_boolean(poExceededTransferLimit));
1279
0
                return;
1280
0
            }
1281
0
        }
1282
0
    }
1283
0
}
1284
1285
/************************************************************************/
1286
/*                            AddLayer()                                */
1287
/************************************************************************/
1288
1289
void OGRGeoJSONDataSource::AddLayer(OGRGeoJSONLayer *poLayer)
1290
0
{
1291
0
    CPLAssert(papoLayersWriter_ == nullptr);
1292
1293
    // Return layer in readable state.
1294
0
    poLayer->ResetReading();
1295
1296
0
    papoLayers_ = static_cast<OGRGeoJSONLayer **>(
1297
0
        CPLRealloc(papoLayers_, sizeof(OGRGeoJSONLayer *) * (nLayers_ + 1)));
1298
0
    papoLayers_[nLayers_] = poLayer;
1299
0
    nLayers_++;
1300
0
}
1301
1302
/************************************************************************/
1303
/*                            FlushCache()                              */
1304
/************************************************************************/
1305
1306
CPLErr OGRGeoJSONDataSource::FlushCache(bool /*bAtClosing*/)
1307
0
{
1308
0
    if (papoLayersWriter_ != nullptr)
1309
0
    {
1310
0
        return papoLayersWriter_[0]->SyncToDisk() == OGRERR_NONE ? CE_None
1311
0
                                                                 : CE_Failure;
1312
0
    }
1313
1314
0
    CPLErr eErr = CE_None;
1315
0
    for (int i = 0; i < nLayers_; i++)
1316
0
    {
1317
0
        if (papoLayers_[i]->HasBeenUpdated())
1318
0
        {
1319
0
            papoLayers_[i]->SetUpdated(false);
1320
1321
0
            bool bOK = false;
1322
1323
            // Disable all filters.
1324
0
            OGRFeatureQuery *poAttrQueryBak = papoLayers_[i]->m_poAttrQuery;
1325
0
            papoLayers_[i]->m_poAttrQuery = nullptr;
1326
0
            OGRGeometry *poFilterGeomBak = papoLayers_[i]->m_poFilterGeom;
1327
0
            papoLayers_[i]->m_poFilterGeom = nullptr;
1328
1329
            // If the source data only contained one single feature and
1330
            // that's still the case, then do not use a FeatureCollection
1331
            // on writing.
1332
0
            bool bAlreadyDone = false;
1333
0
            if (papoLayers_[i]->GetFeatureCount(TRUE) == 1 &&
1334
0
                papoLayers_[i]->GetMetadata("NATIVE_DATA") == nullptr)
1335
0
            {
1336
0
                papoLayers_[i]->ResetReading();
1337
0
                OGRFeature *poFeature = papoLayers_[i]->GetNextFeature();
1338
0
                if (poFeature != nullptr)
1339
0
                {
1340
0
                    if (poFeature->GetNativeData() != nullptr)
1341
0
                    {
1342
0
                        bAlreadyDone = true;
1343
0
                        OGRGeoJSONWriteOptions oOptions;
1344
0
                        json_object *poObj =
1345
0
                            OGRGeoJSONWriteFeature(poFeature, oOptions);
1346
0
                        VSILFILE *fp = VSIFOpenL(pszName_, "wb");
1347
0
                        if (fp != nullptr)
1348
0
                        {
1349
0
                            bOK = VSIFPrintfL(
1350
0
                                      fp, "%s",
1351
0
                                      json_object_to_json_string(poObj)) > 0;
1352
0
                            VSIFCloseL(fp);
1353
0
                        }
1354
0
                        json_object_put(poObj);
1355
0
                    }
1356
0
                    delete poFeature;
1357
0
                }
1358
0
            }
1359
1360
            // Otherwise do layer translation.
1361
0
            if (!bAlreadyDone)
1362
0
            {
1363
0
                char **papszOptions = CSLAddString(nullptr, "-f");
1364
0
                papszOptions = CSLAddString(papszOptions, "GeoJSON");
1365
0
                GDALVectorTranslateOptions *psOptions =
1366
0
                    GDALVectorTranslateOptionsNew(papszOptions, nullptr);
1367
0
                CSLDestroy(papszOptions);
1368
0
                GDALDatasetH hSrcDS = this;
1369
0
                CPLString osNewFilename(pszName_);
1370
0
                osNewFilename += ".tmp";
1371
0
                GDALDatasetH hOutDS = GDALVectorTranslate(
1372
0
                    osNewFilename, nullptr, 1, &hSrcDS, psOptions, nullptr);
1373
0
                GDALVectorTranslateOptionsFree(psOptions);
1374
1375
0
                if (hOutDS != nullptr)
1376
0
                {
1377
0
                    CPLErrorReset();
1378
0
                    GDALClose(hOutDS);
1379
0
                    bOK = (CPLGetLastErrorType() == CE_None);
1380
0
                }
1381
0
                if (bOK)
1382
0
                {
1383
0
                    const bool bOverwrite = CPLTestBool(
1384
0
                        CPLGetConfigOption("OGR_GEOJSON_REWRITE_IN_PLACE",
1385
#ifdef _WIN32
1386
                                           "YES"
1387
#else
1388
0
                                           "NO"
1389
0
#endif
1390
0
                                           ));
1391
0
                    if (bOverwrite)
1392
0
                    {
1393
0
                        VSILFILE *fpTarget = nullptr;
1394
0
                        for (int attempt = 0; attempt < 10; attempt++)
1395
0
                        {
1396
0
                            fpTarget = VSIFOpenL(pszName_, "rb+");
1397
0
                            if (fpTarget)
1398
0
                                break;
1399
0
                            CPLSleep(0.1);
1400
0
                        }
1401
0
                        if (!fpTarget)
1402
0
                        {
1403
0
                            CPLError(CE_Failure, CPLE_AppDefined,
1404
0
                                     "Cannot rewrite %s", pszName_);
1405
0
                        }
1406
0
                        else
1407
0
                        {
1408
0
                            bool bCopyOK = CPL_TO_BOOL(
1409
0
                                VSIOverwriteFile(fpTarget, osNewFilename));
1410
0
                            if (VSIFCloseL(fpTarget) != 0)
1411
0
                                bCopyOK = false;
1412
0
                            if (bCopyOK)
1413
0
                            {
1414
0
                                VSIUnlink(osNewFilename);
1415
0
                            }
1416
0
                            else
1417
0
                            {
1418
0
                                CPLError(CE_Failure, CPLE_AppDefined,
1419
0
                                         "Cannot rewrite %s with content of %s",
1420
0
                                         pszName_, osNewFilename.c_str());
1421
0
                            }
1422
0
                        }
1423
0
                    }
1424
0
                    else
1425
0
                    {
1426
0
                        CPLString osBackup(pszName_);
1427
0
                        osBackup += ".bak";
1428
0
                        if (VSIRename(pszName_, osBackup) < 0)
1429
0
                        {
1430
0
                            CPLError(CE_Failure, CPLE_AppDefined,
1431
0
                                     "Cannot create backup copy");
1432
0
                        }
1433
0
                        else if (VSIRename(osNewFilename, pszName_) < 0)
1434
0
                        {
1435
0
                            CPLError(CE_Failure, CPLE_AppDefined,
1436
0
                                     "Cannot rename %s to %s",
1437
0
                                     osNewFilename.c_str(), pszName_);
1438
0
                        }
1439
0
                        else
1440
0
                        {
1441
0
                            VSIUnlink(osBackup);
1442
0
                        }
1443
0
                    }
1444
0
                }
1445
0
            }
1446
0
            if (!bOK)
1447
0
                eErr = CE_Failure;
1448
1449
            // Restore filters.
1450
0
            papoLayers_[i]->m_poAttrQuery = poAttrQueryBak;
1451
0
            papoLayers_[i]->m_poFilterGeom = poFilterGeomBak;
1452
0
        }
1453
0
    }
1454
0
    return eErr;
1455
0
}