1 /******************************************************************************
2  *
3  * Project:  OpenGIS Simple Features Reference Implementation
4  * Purpose:  Implementation of OGRGeoJSONDriver class (OGR GeoJSON Driver).
5  * Author:   Mateusz Loskot, mateusz@loskot.net
6  *
7  ******************************************************************************
8  * Copyright (c) 2007, Mateusz Loskot
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 "ogr_geojson.h"
31 
32 #include <stdlib.h>
33 #include <string.h>
34 
35 #include "cpl_conv.h"
36 #include "cpl_error.h"
37 #include "cpl_http.h"
38 #include "cpl_multiproc.h"
39 #include "cpl_string.h"
40 #include "cpl_vsi.h"
41 // #include "json_object.h"
42 #include "gdal.h"
43 #include "gdal_priv.h"
44 #include "ogr_core.h"
45 #include "ogr_feature.h"
46 #include "ogrgeojsonutils.h"
47 #include "ogrsf_frmts.h"
48 
49 CPL_CVSID("$Id: ogrgeojsondriver.cpp 834742f5172f1c34b1ffdfd6a0197c88449ffd62 2021-09-02 22:36:02 +0200 Even Rouault $")
50 
51 static CPLMutex* ghMutex = nullptr;
52 static char* gpszSource = nullptr;
53 static char* gpszText = nullptr;
54 
55 class OGRESRIFeatureServiceDataset;
56 
57 /************************************************************************/
58 /*                      OGRESRIFeatureServiceLayer                      */
59 /************************************************************************/
60 
61 class OGRESRIFeatureServiceLayer final: public OGRLayer
62 {
63     OGRESRIFeatureServiceDataset* poDS;
64     OGRFeatureDefn* poFeatureDefn;
65     GIntBig         nFeaturesRead;
66     GIntBig         nFirstFID;
67     GIntBig         nLastFID;
68     bool            bOtherPage;
69     bool            bUseSequentialFID;
70 
71   public:
72     explicit OGRESRIFeatureServiceLayer( OGRESRIFeatureServiceDataset* poDS );
73     virtual ~OGRESRIFeatureServiceLayer();
74 
75     void ResetReading() override;
76     OGRFeature* GetNextFeature() override;
77     GIntBig GetFeatureCount( int bForce = TRUE ) override;
78     OGRErr              GetExtent(OGREnvelope *psExtent, int bForce = TRUE) override;
GetExtent(int iGeomField,OGREnvelope * psExtent,int bForce)79     virtual OGRErr      GetExtent( int iGeomField, OGREnvelope *psExtent,
80                                    int bForce) override
81             { return OGRLayer::GetExtent(iGeomField, psExtent, bForce); }
82     int TestCapability( const char* pszCap ) override;
GetLayerDefn()83     OGRFeatureDefn* GetLayerDefn() override { return poFeatureDefn; }
84 };
85 
86 /************************************************************************/
87 /*                       OGRESRIFeatureServiceDataset                   */
88 /************************************************************************/
89 
90 class OGRESRIFeatureServiceDataset final: public GDALDataset
91 {
92     CPLString              osURL;
93     GIntBig                nFirstOffset;
94     GIntBig                nLastOffset;
95     OGRGeoJSONDataSource  *poCurrent;
96     OGRESRIFeatureServiceLayer *poLayer;
97 
98     int                     LoadPage();
99 
100   public:
101     OGRESRIFeatureServiceDataset( const CPLString &osURL,
102                                   OGRGeoJSONDataSource* poFirst );
103     ~OGRESRIFeatureServiceDataset();
104 
GetLayerCount()105     int GetLayerCount() override { return 1; }
GetLayer(int nLayer)106     OGRLayer* GetLayer( int nLayer ) override
107         { return (nLayer == 0) ? poLayer : nullptr; }
108 
GetUnderlyingLayer()109     OGRLayer* GetUnderlyingLayer() { return poCurrent->GetLayer(0); }
110 
111     int MyResetReading();
112     int LoadNextPage();
113 
GetURL()114     const CPLString& GetURL() { return osURL; }
115 };
116 
117 /************************************************************************/
118 /*                       OGRESRIFeatureServiceLayer()                   */
119 /************************************************************************/
120 
OGRESRIFeatureServiceLayer(OGRESRIFeatureServiceDataset * poDSIn)121 OGRESRIFeatureServiceLayer::OGRESRIFeatureServiceLayer(
122     OGRESRIFeatureServiceDataset* poDSIn) :
123     poDS(poDSIn),
124     nFeaturesRead(0),
125     nFirstFID(0),
126     nLastFID(0),
127     bOtherPage(false),
128     bUseSequentialFID(false)
129 {
130     OGRFeatureDefn* poSrcFeatDefn = poDS->GetUnderlyingLayer()->GetLayerDefn();
131     poFeatureDefn = new OGRFeatureDefn(poSrcFeatDefn->GetName());
132     SetDescription(poFeatureDefn->GetName());
133     poFeatureDefn->Reference();
134     poFeatureDefn->SetGeomType(wkbNone);
135 
136     for( int i = 0; i < poSrcFeatDefn->GetFieldCount(); i++ )
137         poFeatureDefn->AddFieldDefn(poSrcFeatDefn->GetFieldDefn(i));
138 
139     for( int i = 0; i <poSrcFeatDefn->GetGeomFieldCount(); i++ )
140         poFeatureDefn->AddGeomFieldDefn(poSrcFeatDefn->GetGeomFieldDefn(i));
141 }
142 
143 /************************************************************************/
144 /*                      ~OGRESRIFeatureServiceLayer()                   */
145 /************************************************************************/
146 
~OGRESRIFeatureServiceLayer()147 OGRESRIFeatureServiceLayer::~OGRESRIFeatureServiceLayer()
148 {
149     poFeatureDefn->Release();
150 }
151 
152 /************************************************************************/
153 /*                            ResetReading()                            */
154 /************************************************************************/
155 
ResetReading()156 void OGRESRIFeatureServiceLayer::ResetReading()
157 {
158     poDS->MyResetReading();
159     nFeaturesRead = 0;
160     nLastFID = 0;
161     bOtherPage = false;
162     bUseSequentialFID = false;
163 }
164 
165 /************************************************************************/
166 /*                            GetNextFeature()                          */
167 /************************************************************************/
168 
GetNextFeature()169 OGRFeature* OGRESRIFeatureServiceLayer::GetNextFeature()
170 {
171     while( true )
172     {
173         const bool bWasInFirstPage = !bOtherPage;
174         OGRFeature* poSrcFeat = poDS->GetUnderlyingLayer()->GetNextFeature();
175         if( poSrcFeat == nullptr )
176         {
177             if( !poDS->LoadNextPage() )
178                 return nullptr;
179             poSrcFeat = poDS->GetUnderlyingLayer()->GetNextFeature();
180             if( poSrcFeat == nullptr )
181                 return nullptr;
182             bOtherPage = true;
183             if( bWasInFirstPage && poSrcFeat->GetFID() != 0 &&
184                 poSrcFeat->GetFID() == nFirstFID )
185             {
186                 // End-less looping
187                 CPLDebug("ESRIJSON", "Scrolling not working. Stopping");
188                 delete poSrcFeat;
189                 return nullptr;
190             }
191             if( bWasInFirstPage && poSrcFeat->GetFID() == 0 &&
192                 nLastFID == nFeaturesRead - 1 )
193             {
194                 bUseSequentialFID = true;
195             }
196         }
197         if( nFeaturesRead == 0 )
198             nFirstFID = poSrcFeat->GetFID();
199 
200         OGRFeature* poFeature = new OGRFeature(poFeatureDefn);
201         poFeature->SetFrom(poSrcFeat);
202         if( bUseSequentialFID )
203             poFeature->SetFID(nFeaturesRead);
204         else
205             poFeature->SetFID(poSrcFeat->GetFID());
206         nLastFID = poFeature->GetFID();
207         nFeaturesRead ++;
208         delete poSrcFeat;
209 
210         if( (m_poFilterGeom == nullptr
211              || FilterGeometry( poFeature->GetGeometryRef() ) )
212             && (m_poAttrQuery == nullptr
213                 || m_poAttrQuery->Evaluate( poFeature )) )
214         {
215             return poFeature;
216         }
217         delete poFeature;
218     }
219 }
220 
221 /************************************************************************/
222 /*                          TestCapability()                            */
223 /************************************************************************/
224 
TestCapability(const char * pszCap)225 int OGRESRIFeatureServiceLayer::TestCapability( const char* pszCap )
226 {
227     if( EQUAL(pszCap, OLCFastFeatureCount) )
228         return m_poAttrQuery == nullptr && m_poFilterGeom == nullptr;
229     if( EQUAL(pszCap, OLCFastGetExtent) )
230         return FALSE;
231     return poDS->GetUnderlyingLayer()->TestCapability(pszCap);
232 }
233 
234 /************************************************************************/
235 /*                          GetFeatureCount()                           */
236 /************************************************************************/
237 
GetFeatureCount(int bForce)238 GIntBig OGRESRIFeatureServiceLayer::GetFeatureCount( int bForce )
239 {
240     GIntBig nFeatureCount = -1;
241     if( m_poAttrQuery == nullptr && m_poFilterGeom == nullptr )
242     {
243         CPLString osNewURL =
244             CPLURLAddKVP(poDS->GetURL(), "returnCountOnly", "true");
245         osNewURL = CPLURLAddKVP(osNewURL, "resultRecordCount", nullptr);
246         CPLErrorReset();
247         CPLHTTPResult* pResult = CPLHTTPFetch( osNewURL, nullptr );
248         if( pResult != nullptr &&
249             pResult->nDataLen != 0 &&
250             CPLGetLastErrorNo() == 0 &&
251             pResult->nStatus == 0 )
252         {
253             const char* pszCount =
254                 strstr((const char*)pResult->pabyData, "\"count\"");
255             if( pszCount )
256             {
257                 pszCount = strchr(pszCount, ':');
258                 if( pszCount )
259                 {
260                     pszCount++;
261                     nFeatureCount = CPLAtoGIntBig(pszCount);
262                 }
263             }
264         }
265         CPLHTTPDestroyResult( pResult );
266     }
267     if( nFeatureCount < 0 )
268         nFeatureCount = OGRLayer::GetFeatureCount(bForce);
269     return nFeatureCount;
270 }
271 
272 /************************************************************************/
273 /*                               GetExtent()                            */
274 /************************************************************************/
275 
GetExtent(OGREnvelope * psExtent,int bForce)276 OGRErr OGRESRIFeatureServiceLayer::GetExtent( OGREnvelope *psExtent,
277                                               int bForce )
278 {
279     OGRErr eErr = OGRERR_FAILURE;
280     CPLString osNewURL =
281         CPLURLAddKVP(poDS->GetURL(), "returnExtentOnly", "true");
282     osNewURL = CPLURLAddKVP(osNewURL, "resultRecordCount", nullptr);
283     osNewURL = CPLURLAddKVP(osNewURL, "f", "geojson");
284     CPLErrorReset();
285     CPLHTTPResult* pResult = CPLHTTPFetch( osNewURL, nullptr );
286     if( pResult != nullptr && pResult->nDataLen != 0 && CPLGetLastErrorNo() == 0 &&
287         pResult->nStatus == 0 )
288     {
289         const char* pszBBox =
290             strstr((const char*)pResult->pabyData, "\"bbox\"");
291         if( pszBBox )
292         {
293             pszBBox = strstr(pszBBox, ":[");
294             if( pszBBox )
295             {
296                 pszBBox += 2;
297                 char** papszTokens = CSLTokenizeString2(pszBBox, ",", 0);
298                 if( CSLCount(papszTokens) >= 4 )
299                 {
300                     psExtent->MinX = CPLAtof(papszTokens[0]);
301                     psExtent->MinY = CPLAtof(papszTokens[1]);
302                     psExtent->MaxX = CPLAtof(papszTokens[2]);
303                     psExtent->MaxY = CPLAtof(papszTokens[3]);
304                     eErr = OGRERR_NONE;
305                 }
306                 CSLDestroy(papszTokens);
307             }
308         }
309     }
310     CPLHTTPDestroyResult( pResult );
311     if( eErr == OGRERR_FAILURE )
312         eErr = OGRLayer::GetExtent(psExtent, bForce);
313     return eErr;
314 }
315 
316 /************************************************************************/
317 /*                      OGRESRIFeatureServiceDataset()                  */
318 /************************************************************************/
319 
OGRESRIFeatureServiceDataset(const CPLString & osURLIn,OGRGeoJSONDataSource * poFirst)320 OGRESRIFeatureServiceDataset::OGRESRIFeatureServiceDataset(
321     const CPLString &osURLIn,
322     OGRGeoJSONDataSource* poFirst) :
323     poCurrent(poFirst)
324 {
325     poLayer = new OGRESRIFeatureServiceLayer(this);
326     osURL = osURLIn;
327     if( CPLURLGetValue(osURL, "resultRecordCount").empty() )
328     {
329         // We assume that if the server sets the exceededTransferLimit, the
330         // and resultRecordCount is not set, the number of features returned
331         // in our first request is the maximum allowed by the server
332         // So set it for following requests.
333         osURL =
334             CPLURLAddKVP(
335                 this->osURL, "resultRecordCount",
336                 CPLSPrintf(
337                     "%d",
338                     static_cast<int>(poFirst->GetLayer(0)->GetFeatureCount())));
339     }
340     else
341     {
342         const int nUserSetRecordCount =
343             atoi(CPLURLGetValue(osURL, "resultRecordCount"));
344         if( nUserSetRecordCount > poFirst->GetLayer(0)->GetFeatureCount() )
345         {
346             CPLError(CE_Warning, CPLE_AppDefined,
347                      "Specified resultRecordCount=%d is greater than "
348                      "the maximum %d supported by the server",
349                      nUserSetRecordCount,
350                      static_cast<int>(poFirst->GetLayer(0)->GetFeatureCount()));
351         }
352     }
353     nFirstOffset = CPLAtoGIntBig(CPLURLGetValue(osURL, "resultOffset"));
354     nLastOffset = nFirstOffset;
355 }
356 
357 /************************************************************************/
358 /*                      ~OGRESRIFeatureServiceDataset()                 */
359 /************************************************************************/
360 
~OGRESRIFeatureServiceDataset()361 OGRESRIFeatureServiceDataset::~OGRESRIFeatureServiceDataset()
362 {
363     delete poCurrent;
364     delete poLayer;
365 }
366 
367 /************************************************************************/
368 /*                           MyResetReading()                           */
369 /************************************************************************/
370 
MyResetReading()371 int OGRESRIFeatureServiceDataset::MyResetReading()
372 {
373     if( nLastOffset > nFirstOffset )
374     {
375         nLastOffset = nFirstOffset;
376         return LoadPage();
377     }
378 
379     poCurrent->GetLayer(0)->ResetReading();
380     return TRUE;
381 }
382 
383 /************************************************************************/
384 /*                             LoadNextPage()                           */
385 /************************************************************************/
386 
LoadNextPage()387 int OGRESRIFeatureServiceDataset::LoadNextPage()
388 {
389     if( !poCurrent->HasOtherPages() )
390         return FALSE;
391     nLastOffset += poCurrent->GetLayer(0)->GetFeatureCount();
392     return LoadPage();
393 }
394 
395 /************************************************************************/
396 /*                                 LoadPage()                           */
397 /************************************************************************/
398 
LoadPage()399 int OGRESRIFeatureServiceDataset::LoadPage()
400 {
401     CPLString osNewURL = CPLURLAddKVP(osURL, "resultOffset",
402                                       CPLSPrintf(CPL_FRMT_GIB, nLastOffset));
403     OGRGeoJSONDataSource* poDS = new OGRGeoJSONDataSource();
404     GDALOpenInfo oOpenInfo(osNewURL, GA_ReadOnly);
405     GeoJSONSourceType nSrcType;
406     if( EQUAL(poCurrent->GetJSonFlavor(), "GeoJSON") )
407         nSrcType = GeoJSONGetSourceType( &oOpenInfo );
408     else
409         nSrcType = ESRIJSONDriverGetSourceType( &oOpenInfo );
410     if( !poDS->Open( &oOpenInfo, nSrcType,
411                      poCurrent->GetJSonFlavor() ) ||
412         poDS->GetLayerCount() == 0 )
413     {
414         delete poDS;
415         poDS = nullptr;
416         return FALSE;
417     }
418     delete poCurrent;
419     poCurrent = poDS;
420     return TRUE;
421 }
422 
423 /************************************************************************/
424 /*                        OGRGeoJSONDriverIdentify()                    */
425 /************************************************************************/
426 
OGRGeoJSONDriverIdentifyInternal(GDALOpenInfo * poOpenInfo,GeoJSONSourceType & nSrcType)427 static int OGRGeoJSONDriverIdentifyInternal( GDALOpenInfo* poOpenInfo,
428                                              GeoJSONSourceType& nSrcType )
429 {
430 /* -------------------------------------------------------------------- */
431 /*      Determine type of data source: text file (.geojson, .json),     */
432 /*      Web Service or text passed directly and load data.              */
433 /* -------------------------------------------------------------------- */
434 
435     nSrcType = GeoJSONGetSourceType( poOpenInfo );
436     if( nSrcType == eGeoJSONSourceUnknown )
437         return FALSE;
438     if( nSrcType == eGeoJSONSourceService &&
439         !STARTS_WITH_CI(poOpenInfo->pszFilename, "GeoJSON:") )
440     {
441         return -1;
442     }
443 
444     // If this looks like a file that can be handled by the STACTA driver,
445     // and that one is available, then don't identify the file.
446     const char* pszHeader = reinterpret_cast<const char*>(poOpenInfo->pabyHeader);
447     if( pszHeader != nullptr &&
448         strstr(pszHeader, "\"stac_extensions\"") != nullptr &&
449         strstr(pszHeader, "\"tiled-assets\"") != nullptr &&
450         GDALGetDriverByName("STACTA") != nullptr )
451     {
452         return FALSE;
453     }
454 
455     return TRUE;
456 }
457 
458 /************************************************************************/
459 /*                        OGRGeoJSONDriverIdentify()                    */
460 /************************************************************************/
461 
OGRGeoJSONDriverIdentify(GDALOpenInfo * poOpenInfo)462 static int OGRGeoJSONDriverIdentify( GDALOpenInfo* poOpenInfo )
463 {
464     GeoJSONSourceType nSrcType;
465     return OGRGeoJSONDriverIdentifyInternal(poOpenInfo, nSrcType);
466 }
467 
468 /************************************************************************/
469 /*                           Open()                                     */
470 /************************************************************************/
471 
OGRGeoJSONDriverOpen(GDALOpenInfo * poOpenInfo)472 static GDALDataset* OGRGeoJSONDriverOpen( GDALOpenInfo* poOpenInfo )
473 {
474     GeoJSONSourceType nSrcType;
475     if( OGRGeoJSONDriverIdentifyInternal(poOpenInfo, nSrcType) == FALSE )
476     {
477         return nullptr;
478     }
479     return OGRGeoJSONDriverOpenInternal(poOpenInfo, nSrcType, "GeoJSON");
480 }
481 
482 /************************************************************************/
483 /*                     OGRGeoJSONDriverOpenInternal()                   */
484 /************************************************************************/
485 
OGRGeoJSONDriverOpenInternal(GDALOpenInfo * poOpenInfo,GeoJSONSourceType nSrcType,const char * pszJSonFlavor)486 GDALDataset* OGRGeoJSONDriverOpenInternal( GDALOpenInfo* poOpenInfo,
487                                            GeoJSONSourceType nSrcType,
488                                            const char* pszJSonFlavor )
489 {
490     OGRGeoJSONDataSource* poDS = new OGRGeoJSONDataSource();
491 
492 /* -------------------------------------------------------------------- */
493 /*      Processing configuration options.                               */
494 /* -------------------------------------------------------------------- */
495 
496     // TODO: Currently, options are based on environment variables.
497     //       This is workaround for not yet implemented Andrey's concept
498     //       described in document 'RFC 10: OGR Open Parameters'.
499 
500     poDS->SetGeometryTranslation( OGRGeoJSONDataSource::eGeometryPreserve );
501     const char* pszOpt = CPLGetConfigOption("GEOMETRY_AS_COLLECTION", nullptr);
502     if( nullptr != pszOpt && STARTS_WITH_CI(pszOpt, "YES") )
503     {
504         poDS->SetGeometryTranslation(
505             OGRGeoJSONDataSource::eGeometryAsCollection );
506     }
507 
508     poDS->SetAttributesTranslation( OGRGeoJSONDataSource::eAttributesPreserve );
509     pszOpt = CPLGetConfigOption("ATTRIBUTES_SKIP", nullptr);
510     if( nullptr != pszOpt && STARTS_WITH_CI(pszOpt, "YES") )
511     {
512         poDS->SetAttributesTranslation(
513             OGRGeoJSONDataSource::eAttributesSkip );
514     }
515 
516 /* -------------------------------------------------------------------- */
517 /*      Open and start processing GeoJSON datasource to OGR objects.    */
518 /* -------------------------------------------------------------------- */
519     if( !poDS->Open( poOpenInfo, nSrcType, pszJSonFlavor ) )
520     {
521         delete poDS;
522         poDS = nullptr;
523     }
524 
525     if( poDS != nullptr && poDS->HasOtherPages() )
526     {
527         const char* pszFilename = poOpenInfo->pszFilename;
528         if( STARTS_WITH_CI(pszFilename, "ESRIJSON:") )
529             pszFilename += strlen("ESRIJSON:");
530         if( STARTS_WITH(pszFilename, "http") ||
531             STARTS_WITH(pszFilename, "/vsimem/") )
532         {
533             const char* pszFSP = CSLFetchNameValue(poOpenInfo->papszOpenOptions,
534                                                    "FEATURE_SERVER_PAGING");
535             const bool bHasResultOffset =
536               !CPLURLGetValue(pszFilename, "resultOffset").empty();
537             if( (!bHasResultOffset && (pszFSP == nullptr || CPLTestBool(pszFSP))) ||
538                 (bHasResultOffset && pszFSP != nullptr && CPLTestBool(pszFSP)) )
539             {
540                 return new OGRESRIFeatureServiceDataset(pszFilename,
541                                                         poDS);
542             }
543         }
544     }
545 
546     return poDS;
547 }
548 
549 /************************************************************************/
550 /*                               Create()                               */
551 /************************************************************************/
552 
OGRGeoJSONDriverCreate(const char * pszName,int,int,int,GDALDataType,char ** papszOptions)553 static GDALDataset *OGRGeoJSONDriverCreate( const char * pszName,
554                                             int /* nBands */,
555                                             int /* nXSize */,
556                                             int /* nYSize */,
557                                             GDALDataType /* eDT */,
558                                             char **papszOptions )
559 {
560     OGRGeoJSONDataSource* poDS = new OGRGeoJSONDataSource();
561 
562     if( !poDS->Create( pszName, papszOptions ) )
563     {
564         delete poDS;
565         poDS = nullptr;
566     }
567 
568     return poDS;
569 }
570 
571 /************************************************************************/
572 /*                               Delete()                               */
573 /************************************************************************/
574 
OGRGeoJSONDriverDelete(const char * pszFilename)575 static CPLErr OGRGeoJSONDriverDelete( const char *pszFilename )
576 {
577     if( VSIUnlink( pszFilename ) == 0 )
578     {
579         return CE_None;
580     }
581 
582     CPLDebug( "GeoJSON", "Failed to delete \'%s\'", pszFilename);
583 
584     return CE_Failure;
585 }
586 
587 /************************************************************************/
588 /*                      OGRGeoJSONDriverStoreContent()                  */
589 /************************************************************************/
590 
OGRGeoJSONDriverStoreContent(const char * pszSource,char * pszText)591 void OGRGeoJSONDriverStoreContent( const char* pszSource, char* pszText )
592 {
593     CPLMutexHolderD(&ghMutex);
594     CPLAssert( pszSource );
595     CPLAssert( pszText );
596 
597     CPLFree(gpszSource);
598     CPLFree(gpszText);
599     gpszSource = CPLStrdup(pszSource);
600     gpszText = pszText;
601 }
602 
603 /************************************************************************/
604 /*                    OGRGeoJSONDriverStealStoredContent()              */
605 /************************************************************************/
606 
OGRGeoJSONDriverStealStoredContent(const char * pszSource)607 char* OGRGeoJSONDriverStealStoredContent( const char* pszSource )
608 {
609     CPLMutexHolderD(&ghMutex);
610     if( gpszSource && EQUAL(pszSource, gpszSource) )
611     {
612         char* pszRet = gpszText;
613         CPLFree(gpszSource);
614         gpszSource = nullptr;
615         gpszText = nullptr;
616         return pszRet;
617     }
618     return nullptr;
619 }
620 
621 /************************************************************************/
622 /*                        OGRGeoJSONDriverUnload()                      */
623 /************************************************************************/
624 
OGRGeoJSONDriverUnload(GDALDriver *)625 static void OGRGeoJSONDriverUnload( GDALDriver* )
626 {
627     if( ghMutex )
628         CPLDestroyMutex(ghMutex);
629     ghMutex = nullptr;
630     CPLFree(gpszSource);
631     CPLFree(gpszText);
632     gpszSource = nullptr;
633     gpszText = nullptr;
634 }
635 
636 /************************************************************************/
637 /*                           RegisterOGRGeoJSON()                       */
638 /************************************************************************/
639 
RegisterOGRGeoJSON()640 void RegisterOGRGeoJSON()
641 {
642     if( !GDAL_CHECK_VERSION("OGR/GeoJSON driver") )
643         return;
644 
645     if( GDALGetDriverByName( "GeoJSON" ) != nullptr )
646         return;
647 
648     GDALDriver *poDriver = new GDALDriver();
649 
650     poDriver->SetDescription( "GeoJSON" );
651     poDriver->SetMetadataItem( GDAL_DCAP_VECTOR, "YES" );
652     poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, "GeoJSON" );
653     poDriver->SetMetadataItem( GDAL_DMD_EXTENSIONS, "json geojson" );
654     poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, "drivers/vector/geojson.html" );
655 
656     poDriver->SetMetadataItem( GDAL_DMD_OPENOPTIONLIST,
657 "<OpenOptionList>"
658 "  <Option name='FLATTEN_NESTED_ATTRIBUTES' type='boolean' description='Whether to recursively explore nested objects and produce flatten OGR attributes' default='NO'/>"
659 "  <Option name='NESTED_ATTRIBUTE_SEPARATOR' type='string' description='Separator between components of nested attributes' default='_'/>"
660 "  <Option name='FEATURE_SERVER_PAGING' type='boolean' description='Whether to automatically scroll through results with a ArcGIS Feature Service endpoint'/>"
661 "  <Option name='NATIVE_DATA' type='boolean' description='Whether to store the native JSon representation at FeatureCollection and Feature level' default='NO'/>"
662 "  <Option name='ARRAY_AS_STRING' type='boolean' description='Whether to expose JSon arrays of strings, integers or reals as a OGR String' default='NO'/>"
663 "  <Option name='DATE_AS_STRING' type='boolean' description='Whether to expose date/time/date-time content using dedicated OGR date/time/date-time types or as a OGR String' default='NO'/>"
664 "</OpenOptionList>");
665 
666     poDriver->SetMetadataItem( GDAL_DMD_CREATIONOPTIONLIST,
667                                "<CreationOptionList/>");
668 
669     poDriver->SetMetadataItem( GDAL_DS_LAYER_CREATIONOPTIONLIST,
670 "<LayerCreationOptionList>"
671 "  <Option name='WRITE_BBOX' type='boolean' description='whether to write a bbox property with the bounding box of the geometries at the feature and feature collection level' default='NO'/>"
672 "  <Option name='COORDINATE_PRECISION' type='int' description='Number of decimal for coordinates. Default is 15 for GJ2008 and 7 for RFC7946'/>"
673 "  <Option name='SIGNIFICANT_FIGURES' type='int' description='Number of significant figures for floating-point values' default='17'/>"
674 "  <Option name='NATIVE_DATA' type='string' description='FeatureCollection level elements.'/>"
675 "  <Option name='NATIVE_MEDIA_TYPE' type='string' description='Format of NATIVE_DATA. Must be \"application/vnd.geo+json\", otherwise NATIVE_DATA will be ignored.'/>"
676 "  <Option name='RFC7946' type='boolean' description='Whether to use RFC 7946 standard. Otherwise GeoJSON 2008 initial version will be used' default='NO'/>"
677 "  <Option name='WRITE_NAME' type='boolean' description='Whether to write a &quot;name&quot; property at feature collection level with layer name' default='YES'/>"
678 "  <Option name='DESCRIPTION' type='string' description='(Long) description to write in a &quot;description&quot; property at feature collection level'/>"
679 "  <Option name='ID_FIELD' type='string' description='Name of the source field that must be used as the id member of Feature features'/>"
680 "  <Option name='ID_TYPE' type='string-select' description='Type of the id member of Feature features'>"
681 "    <Value>AUTO</Value>"
682 "    <Value>String</Value>"
683 "    <Value>Integer</Value>"
684 "  </Option>"
685 "  <Option name='ID_GENERATE' type='boolean' description='Auto-generate feature ids' />"
686 "  <Option name='WRITE_NON_FINITE_VALUES' type='boolean' description='Whether to write NaN / Infinity values' default='NO'/>"
687 "</LayerCreationOptionList>");
688 
689     poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
690     poDriver->SetMetadataItem( GDAL_DMD_CREATIONFIELDDATATYPES,
691                                "Integer Integer64 Real String IntegerList "
692                                "Integer64List RealList StringList Date DateTime" );
693     poDriver->SetMetadataItem( GDAL_DMD_CREATIONFIELDDATASUBTYPES, "Boolean" );
694 
695     poDriver->pfnOpen = OGRGeoJSONDriverOpen;
696     poDriver->pfnIdentify = OGRGeoJSONDriverIdentify;
697     poDriver->pfnCreate = OGRGeoJSONDriverCreate;
698     poDriver->pfnDelete = OGRGeoJSONDriverDelete;
699     poDriver->pfnUnloadDriver = OGRGeoJSONDriverUnload;
700 
701     GetGDALDriverManager()->RegisterDriver( poDriver );
702 }
703