1 /******************************************************************************
2  * $Id: ogrgeojsonreader.cpp 29156 2015-05-05 10:19:17Z rouault $
3  *
4  * Project:  OpenGIS Simple Features Reference Implementation
5  * Purpose:  Implementation of OGRGeoJSONReader class (OGR GeoJSON Driver).
6  * Author:   Mateusz Loskot, mateusz@loskot.net
7  *
8  ******************************************************************************
9  * Copyright (c) 2007, Mateusz Loskot
10  * Copyright (c) 2008-2013, Even Rouault <even dot rouault at mines-paris dot org>
11  *
12  * Permission is hereby granted, free of charge, to any person obtaining a
13  * copy of this software and associated documentation files (the "Software"),
14  * to deal in the Software without restriction, including without limitation
15  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16  * and/or sell copies of the Software, and to permit persons to whom the
17  * Software is furnished to do so, subject to the following conditions:
18  *
19  * The above copyright notice and this permission notice shall be included
20  * in all copies or substantial portions of the Software.
21  *
22  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28  * DEALINGS IN THE SOFTWARE.
29  ****************************************************************************/
30 #include "ogrgeojsonreader.h"
31 #include "ogrgeojsonutils.h"
32 #include "ogr_geojson.h"
33 #include <json.h> // JSON-C
34 #include <ogr_api.h>
35 
36 /************************************************************************/
37 /*                           OGRGeoJSONReader                           */
38 /************************************************************************/
39 
OGRGeoJSONReader()40 OGRGeoJSONReader::OGRGeoJSONReader()
41     : poGJObject_( NULL ),
42         bGeometryPreserve_( true ),
43         bAttributesSkip_( false ),
44         bFlattenNestedAttributes_ (false),
45         chNestedAttributeSeparator_ (0),
46         bFlattenGeocouchSpatiallistFormat (-1), bFoundId (false), bFoundRev(false), bFoundTypeFeature(false), bIsGeocouchSpatiallistFormat(false)
47 {
48     // Take a deep breath and get to work.
49 }
50 
51 /************************************************************************/
52 /*                          ~OGRGeoJSONReader                           */
53 /************************************************************************/
54 
~OGRGeoJSONReader()55 OGRGeoJSONReader::~OGRGeoJSONReader()
56 {
57     if( NULL != poGJObject_ )
58     {
59         json_object_put(poGJObject_);
60     }
61 
62     poGJObject_ = NULL;
63 }
64 
65 /************************************************************************/
66 /*                           Parse                                      */
67 /************************************************************************/
68 
Parse(const char * pszText)69 OGRErr OGRGeoJSONReader::Parse( const char* pszText )
70 {
71     if( NULL != pszText )
72     {
73         json_tokener* jstok = NULL;
74         json_object* jsobj = NULL;
75 
76         /* Skip UTF-8 BOM (#5630) */
77         const GByte* pabyData = (const GByte*)pszText;
78         if( pabyData[0] == 0xEF && pabyData[1] == 0xBB && pabyData[2] == 0xBF )
79         {
80             CPLDebug("GeoJSON", "Skip UTF-8 BOM");
81             pszText += 3;
82         }
83 
84         jstok = json_tokener_new();
85         jsobj = json_tokener_parse_ex(jstok, pszText, -1);
86         if( jstok->err != json_tokener_success)
87         {
88             CPLError( CE_Failure, CPLE_AppDefined,
89                       "GeoJSON parsing error: %s (at offset %d)",
90             	      json_tokener_error_desc(jstok->err), jstok->char_offset);
91 
92             json_tokener_free(jstok);
93             return OGRERR_CORRUPT_DATA;
94         }
95         json_tokener_free(jstok);
96 
97         /* JSON tree is shared for while lifetime of the reader object
98          * and will be released in the destructor.
99          */
100         poGJObject_ = jsobj;
101     }
102 
103     return OGRERR_NONE;
104 }
105 
106 /************************************************************************/
107 /*                           ReadLayers                                 */
108 /************************************************************************/
109 
ReadLayers(OGRGeoJSONDataSource * poDS)110 void OGRGeoJSONReader::ReadLayers( OGRGeoJSONDataSource* poDS )
111 {
112     if( NULL == poGJObject_ )
113     {
114         CPLDebug( "GeoJSON",
115                   "Missing parset GeoJSON data. Forgot to call Parse()?" );
116         return;
117     }
118 
119     ReadLayer(poDS, OGRGeoJSONLayer::DefaultName, poGJObject_);
120 }
121 
122 /************************************************************************/
123 /*                           ReadLayer                                  */
124 /************************************************************************/
125 
ReadLayer(OGRGeoJSONDataSource * poDS,const char * pszName,json_object * poObj)126 void OGRGeoJSONReader::ReadLayer( OGRGeoJSONDataSource* poDS,
127                                   const char* pszName,
128                                   json_object* poObj )
129 {
130     GeoJSONObject::Type objType = OGRGeoJSONGetType( poObj );
131     if( objType == GeoJSONObject::eUnknown )
132     {
133         /* Check if the object contains key:value pairs where value */
134         /* is a standard GeoJSON object. In which case, use key as the layer */
135         /* name */
136         if( json_type_object == json_object_get_type( poObj ) )
137         {
138             json_object_iter it;
139             it.key = NULL;
140             it.val = NULL;
141             it.entry = NULL;
142             json_object_object_foreachC( poObj, it )
143             {
144                 objType = OGRGeoJSONGetType( it.val );
145                 if( objType != GeoJSONObject::eUnknown )
146                     ReadLayer(poDS, it.key, it.val);
147             }
148         }
149 
150         /*CPLError( CE_Failure, CPLE_AppDefined,
151             "Unrecognized GeoJSON structure." );*/
152 
153         return;
154     }
155 
156     OGRSpatialReference* poSRS = NULL;
157     poSRS = OGRGeoJSONReadSpatialReference( poObj );
158     if (poSRS == NULL ) {
159         // If there is none defined, we use 4326
160         poSRS = new OGRSpatialReference();
161         if( OGRERR_NONE != poSRS->importFromEPSG( 4326 ) )
162         {
163             delete poSRS;
164             poSRS = NULL;
165         }
166     }
167 
168     OGRGeoJSONLayer* poLayer = new OGRGeoJSONLayer( pszName, poSRS,
169                                     OGRGeoJSONLayer::DefaultGeometryType,
170                                     poDS );
171     if( poSRS != NULL )
172         poSRS->Release();
173 
174     if( !GenerateLayerDefn(poLayer, poObj) )
175     {
176         CPLError( CE_Failure, CPLE_AppDefined,
177             "Layer schema generation failed." );
178 
179         delete poLayer;
180         return;
181     }
182 
183 /* -------------------------------------------------------------------- */
184 /*      Translate single geometry-only Feature object.                  */
185 /* -------------------------------------------------------------------- */
186 
187     if( GeoJSONObject::ePoint == objType
188         || GeoJSONObject::eMultiPoint == objType
189         || GeoJSONObject::eLineString == objType
190         || GeoJSONObject::eMultiLineString == objType
191         || GeoJSONObject::ePolygon == objType
192         || GeoJSONObject::eMultiPolygon == objType
193         || GeoJSONObject::eGeometryCollection == objType )
194     {
195         OGRGeometry* poGeometry = NULL;
196         poGeometry = ReadGeometry( poObj );
197         if( !AddFeature( poLayer, poGeometry ) )
198         {
199             CPLDebug( "GeoJSON",
200                       "Translation of single geometry failed." );
201             delete poLayer;
202             return;
203         }
204     }
205 /* -------------------------------------------------------------------- */
206 /*      Translate single but complete Feature object.                   */
207 /* -------------------------------------------------------------------- */
208     else if( GeoJSONObject::eFeature == objType )
209     {
210         OGRFeature* poFeature = NULL;
211         poFeature = ReadFeature( poLayer, poObj );
212         if( !AddFeature( poLayer, poFeature ) )
213         {
214             CPLDebug( "GeoJSON",
215                       "Translation of single feature failed." );
216 
217             delete poLayer;
218             return;
219         }
220     }
221 /* -------------------------------------------------------------------- */
222 /*      Translate multi-feature FeatureCollection object.               */
223 /* -------------------------------------------------------------------- */
224     else if( GeoJSONObject::eFeatureCollection == objType )
225     {
226         ReadFeatureCollection( poLayer, poObj );
227     }
228 
229     CPLErrorReset();
230 
231     poDS->AddLayer(poLayer);
232 }
233 
234 /************************************************************************/
235 /*                    OGRGeoJSONReadSpatialReference                    */
236 /************************************************************************/
237 
OGRGeoJSONReadSpatialReference(json_object * poObj)238 OGRSpatialReference* OGRGeoJSONReadSpatialReference( json_object* poObj) {
239 
240 /* -------------------------------------------------------------------- */
241 /*      Read spatial reference definition.                              */
242 /* -------------------------------------------------------------------- */
243     OGRSpatialReference* poSRS = NULL;
244 
245     json_object* poObjSrs = OGRGeoJSONFindMemberByName( poObj, "crs" );
246     if( NULL != poObjSrs )
247     {
248         json_object* poObjSrsType = OGRGeoJSONFindMemberByName( poObjSrs, "type" );
249         if (poObjSrsType == NULL)
250             return NULL;
251 
252         const char* pszSrsType = json_object_get_string( poObjSrsType );
253 
254         // TODO: Add URL and URN types support
255         if( EQUALN( pszSrsType, "NAME", 4 ) )
256         {
257             json_object* poObjSrsProps = OGRGeoJSONFindMemberByName( poObjSrs, "properties" );
258             if (poObjSrsProps == NULL)
259                 return NULL;
260 
261             json_object* poNameURL = OGRGeoJSONFindMemberByName( poObjSrsProps, "name" );
262             if (poNameURL == NULL)
263                 return NULL;
264 
265             const char* pszName = json_object_get_string( poNameURL );
266 
267             poSRS = new OGRSpatialReference();
268             if( OGRERR_NONE != poSRS->SetFromUserInput( pszName ) )
269             {
270                 delete poSRS;
271                 poSRS = NULL;
272             }
273         }
274 
275         if( EQUALN( pszSrsType, "EPSG", 4 ) )
276         {
277             json_object* poObjSrsProps = OGRGeoJSONFindMemberByName( poObjSrs, "properties" );
278             if (poObjSrsProps == NULL)
279                 return NULL;
280 
281             json_object* poObjCode = OGRGeoJSONFindMemberByName( poObjSrsProps, "code" );
282             if (poObjCode == NULL)
283                 return NULL;
284 
285             int nEPSG = json_object_get_int( poObjCode );
286 
287             poSRS = new OGRSpatialReference();
288             if( OGRERR_NONE != poSRS->importFromEPSG( nEPSG ) )
289             {
290                 delete poSRS;
291                 poSRS = NULL;
292             }
293         }
294 
295         if( EQUALN( pszSrsType, "URL", 3 ) || EQUALN( pszSrsType, "LINK", 4 )  )
296         {
297             json_object* poObjSrsProps = OGRGeoJSONFindMemberByName( poObjSrs, "properties" );
298             if (poObjSrsProps == NULL)
299                 return NULL;
300 
301             json_object* poObjURL = OGRGeoJSONFindMemberByName( poObjSrsProps, "url" );
302 
303             if (NULL == poObjURL) {
304                 poObjURL = OGRGeoJSONFindMemberByName( poObjSrsProps, "href" );
305             }
306             if (poObjURL == NULL)
307                 return NULL;
308 
309             const char* pszURL = json_object_get_string( poObjURL );
310 
311             poSRS = new OGRSpatialReference();
312             if( OGRERR_NONE != poSRS->importFromUrl( pszURL ) )
313             {
314                 delete poSRS;
315                 poSRS = NULL;
316 
317             }
318         }
319 
320 
321         if( EQUAL( pszSrsType, "OGC" ) )
322         {
323             json_object* poObjSrsProps = OGRGeoJSONFindMemberByName( poObjSrs, "properties" );
324             if (poObjSrsProps == NULL)
325                 return NULL;
326 
327             json_object* poObjURN = OGRGeoJSONFindMemberByName( poObjSrsProps, "urn" );
328             if (poObjURN == NULL)
329                 return NULL;
330 
331             poSRS = new OGRSpatialReference();
332             if( OGRERR_NONE != poSRS->importFromURN( json_object_get_string(poObjURN) ) )
333             {
334                 delete poSRS;
335                 poSRS = NULL;
336             }
337         }
338     }
339 
340     /* Strip AXIS, since geojson has (easting, northing) / (longitude, latitude) order. */
341     /* According to http://www.geojson.org/geojson-spec.html#id2 : "Point coordinates are in x, y order */
342     /* (easting, northing for projected coordinates, longitude, latitude for geographic coordinates)" */
343     if( poSRS != NULL )
344     {
345         OGR_SRSNode *poGEOGCS = poSRS->GetAttrNode( "GEOGCS" );
346         if( poGEOGCS != NULL )
347             poGEOGCS->StripNodes( "AXIS" );
348     }
349 
350     return poSRS;
351 }
352 /************************************************************************/
353 /*                           SetPreserveGeometryType                    */
354 /************************************************************************/
355 
SetPreserveGeometryType(bool bPreserve)356 void OGRGeoJSONReader::SetPreserveGeometryType( bool bPreserve )
357 {
358     bGeometryPreserve_ = bPreserve;
359 }
360 
361 /************************************************************************/
362 /*                           SetSkipAttributes                          */
363 /************************************************************************/
364 
SetSkipAttributes(bool bSkip)365 void OGRGeoJSONReader::SetSkipAttributes( bool bSkip )
366 {
367     bAttributesSkip_ = bSkip;
368 }
369 
370 /************************************************************************/
371 /*                           SetSkipAttributes                          */
372 /************************************************************************/
373 
SetFlattenNestedAttributes(bool bFlatten,char chSeparator)374 void OGRGeoJSONReader::SetFlattenNestedAttributes( bool bFlatten, char chSeparator )
375 {
376     bFlattenNestedAttributes_ = bFlatten;
377     chNestedAttributeSeparator_ = chSeparator;
378 }
379 
380 /************************************************************************/
381 /*                         GenerateLayerDefn()                          */
382 /************************************************************************/
383 
GenerateLayerDefn(OGRGeoJSONLayer * poLayer,json_object * poGJObject)384 bool OGRGeoJSONReader::GenerateLayerDefn( OGRGeoJSONLayer* poLayer, json_object* poGJObject )
385 {
386     CPLAssert( NULL != poGJObject );
387     CPLAssert( NULL != poLayer->GetLayerDefn() );
388     CPLAssert( 0 == poLayer->GetLayerDefn()->GetFieldCount() );
389 
390     bool bSuccess = true;
391 
392     if( bAttributesSkip_ )
393         return true;
394 
395 /* -------------------------------------------------------------------- */
396 /*      Scan all features and generate layer definition.                */
397 /* -------------------------------------------------------------------- */
398     GeoJSONObject::Type objType = OGRGeoJSONGetType( poGJObject );
399     if( GeoJSONObject::eFeature == objType )
400     {
401         bSuccess = GenerateFeatureDefn( poLayer, poGJObject );
402     }
403     else if( GeoJSONObject::eFeatureCollection == objType )
404     {
405         json_object* poObjFeatures = NULL;
406         poObjFeatures = OGRGeoJSONFindMemberByName( poGJObject, "features" );
407         if( NULL != poObjFeatures
408             && json_type_array == json_object_get_type( poObjFeatures ) )
409         {
410             json_object* poObjFeature = NULL;
411             const int nFeatures = json_object_array_length( poObjFeatures );
412             for( int i = 0; i < nFeatures; ++i )
413             {
414                 poObjFeature = json_object_array_get_idx( poObjFeatures, i );
415                 if( !GenerateFeatureDefn( poLayer, poObjFeature ) )
416                 {
417                     CPLDebug( "GeoJSON", "Create feature schema failure." );
418                     bSuccess = false;
419                 }
420             }
421         }
422         else
423         {
424             CPLError( CE_Failure, CPLE_AppDefined,
425                       "Invalid FeatureCollection object. "
426                       "Missing \'features\' member." );
427             bSuccess = false;
428         }
429     }
430 
431 /* -------------------------------------------------------------------- */
432 /*      Validate and add FID column if necessary.                       */
433 /* -------------------------------------------------------------------- */
434     OGRFeatureDefn* poLayerDefn = poLayer->GetLayerDefn();
435     CPLAssert( NULL != poLayerDefn );
436 
437     /* bool bHasFID = false; */
438 
439     for( int i = 0; i < poLayerDefn->GetFieldCount(); ++i )
440     {
441         OGRFieldDefn* poDefn = poLayerDefn->GetFieldDefn(i);
442         if( EQUAL( poDefn->GetNameRef(), OGRGeoJSONLayer::DefaultFIDColumn )
443             && (OFTInteger == poDefn->GetType() || OFTInteger64 == poDefn->GetType()) )
444         {
445             poLayer->SetFIDColumn( poDefn->GetNameRef() );
446             /* bHasFID = true; */
447             break;
448         }
449     }
450 
451     // TODO - mloskot: This is wrong! We want to add only FID field if
452     // found in source layer (by default name or by FID_PROPERTY= specifier,
453     // the latter has to be implemented).
454     /*
455       if( !bHasFID )
456       {
457       OGRFieldDefn fldDefn( OGRGeoJSONLayer::DefaultFIDColumn, OFTInteger );
458       poLayerDefn->AddFieldDefn( &fldDefn );
459       poLayer_->SetFIDColumn( fldDefn.GetNameRef() );
460       }
461     */
462 
463     return bSuccess;
464 }
465 
466 /************************************************************************/
467 /*                     OGRGeoJSONReaderAddNewField()                    */
468 /************************************************************************/
469 
OGRGeoJSONReaderAddOrUpdateField(OGRFeatureDefn * poDefn,const char * pszKey,json_object * poVal,bool bFlattenNestedAttributes,char chNestedAttributeSeparator)470 void OGRGeoJSONReaderAddOrUpdateField(OGRFeatureDefn* poDefn,
471                                       const char* pszKey,
472                                       json_object* poVal,
473                                       bool bFlattenNestedAttributes,
474                                       char chNestedAttributeSeparator)
475 {
476     if( bFlattenNestedAttributes &&
477         poVal != NULL && json_object_get_type(poVal) == json_type_object )
478     {
479         json_object_iter it;
480         it.key = NULL;
481         it.val = NULL;
482         it.entry = NULL;
483         json_object_object_foreachC( poVal, it )
484         {
485             char szSeparator[2];
486             szSeparator[0] = chNestedAttributeSeparator;
487             szSeparator[1] = 0;
488             CPLString osAttrName(CPLSPrintf("%s%s%s", pszKey, szSeparator,
489                                             it.key));
490             if( it.val != NULL && json_object_get_type(it.val) == json_type_object )
491             {
492                 OGRGeoJSONReaderAddOrUpdateField(poDefn, osAttrName, it.val,
493                                                  TRUE, chNestedAttributeSeparator);
494             }
495             else
496             {
497                 OGRGeoJSONReaderAddOrUpdateField(poDefn, osAttrName, it.val, FALSE, 0);
498             }
499         }
500         return;
501     }
502 
503     int nIndex = poDefn->GetFieldIndex(pszKey);
504     if( nIndex < 0 )
505     {
506         OGRFieldSubType eSubType;
507         OGRFieldDefn fldDefn( pszKey,
508                                 GeoJSONPropertyToFieldType( poVal, eSubType ) );
509         fldDefn.SetSubType(eSubType);
510         if( eSubType == OFSTBoolean )
511             fldDefn.SetWidth(1);
512         if( fldDefn.GetType() == OFTString )
513         {
514             fldDefn.SetType(GeoJSONStringPropertyToFieldType( poVal ));
515         }
516         poDefn->AddFieldDefn( &fldDefn );
517     }
518     else
519     {
520         OGRFieldDefn* poFDefn = poDefn->GetFieldDefn(nIndex);
521         OGRFieldType eType = poFDefn->GetType();
522         if( eType == OFTInteger )
523         {
524             OGRFieldSubType eSubType;
525             OGRFieldType eNewType = GeoJSONPropertyToFieldType( poVal, eSubType );
526             if( eNewType == OFTInteger &&
527                 poFDefn->GetSubType() == OFSTBoolean && eSubType != OFSTBoolean )
528             {
529                 poFDefn->SetSubType(OFSTNone);
530             }
531             else if( eNewType == OFTInteger64 || eNewType == OFTReal || eNewType == OFTString )
532             {
533                 poFDefn->SetType(eNewType);
534                 poFDefn->SetSubType(OFSTNone);
535             }
536         }
537         else if( eType == OFTInteger64 )
538         {
539             OGRFieldSubType eSubType;
540             OGRFieldType eNewType = GeoJSONPropertyToFieldType( poVal, eSubType );
541             if( eNewType == OFTReal || eNewType == OFTString )
542             {
543                 poFDefn->SetType(eNewType);
544                 poFDefn->SetSubType(OFSTNone);
545             }
546         }
547         else if( eType == OFTIntegerList || eType == OFTInteger64List )
548         {
549             OGRFieldSubType eSubType;
550             OGRFieldType eNewType = GeoJSONPropertyToFieldType( poVal, eSubType );
551             if( eNewType == OFTInteger64List || eNewType == OFTRealList || eNewType == OFTStringList )
552                 poFDefn->SetType(eNewType);
553         }
554         else if( eType == OFTRealList )
555         {
556             OGRFieldSubType eSubType;
557             OGRFieldType eNewType = GeoJSONPropertyToFieldType( poVal, eSubType );
558             if( eNewType == OFTStringList )
559                 poFDefn->SetType(eNewType);
560         }
561         else if( eType == OFTDate || eType == OFTTime || eType == OFTDateTime )
562         {
563             OGRFieldSubType eSubType;
564             OGRFieldType eNewType = GeoJSONPropertyToFieldType( poVal, eSubType );
565             if( eNewType == OFTString )
566                 eNewType = GeoJSONStringPropertyToFieldType( poVal );
567             if( eType != eNewType )
568             {
569                 if( eType == OFTDate && eNewType == OFTDateTime )
570                 {
571                     poFDefn->SetType(OFTDateTime);
572                 }
573                 else if( !(eType == OFTDateTime && eNewType == OFTDate) )
574                 {
575                     poFDefn->SetType(OFTString);
576                 }
577             }
578         }
579     }
580 }
581 
582 /************************************************************************/
583 /*                        GenerateFeatureDefn()                         */
584 /************************************************************************/
GenerateFeatureDefn(OGRGeoJSONLayer * poLayer,json_object * poObj)585 bool OGRGeoJSONReader::GenerateFeatureDefn( OGRGeoJSONLayer* poLayer, json_object* poObj )
586 {
587     OGRFeatureDefn* poDefn = poLayer->GetLayerDefn();
588     CPLAssert( NULL != poDefn );
589 
590     bool bSuccess = false;
591 
592 /* -------------------------------------------------------------------- */
593 /*      Read collection of properties.                                  */
594 /* -------------------------------------------------------------------- */
595     json_object* poObjProps = NULL;
596     poObjProps = OGRGeoJSONFindMemberByName( poObj, "properties" );
597 
598     // If there's a top-level id of type string, and no properties.id, then
599     // declare a id field
600     if( poDefn->GetFieldIndex( "id" ) < 0 )
601     {
602         json_object* poObjId = OGRGeoJSONFindMemberByName( poObj, "id" );
603         if( poObjId && json_object_get_type(poObjId) == json_type_string )
604         {
605             int bHasRegularIdProp = FALSE;
606             if( NULL != poObjProps &&
607                 json_object_get_type(poObjProps) == json_type_object )
608             {
609                 bHasRegularIdProp = (json_object_object_get(poObjProps, "id") != NULL);
610             }
611             if( !bHasRegularIdProp )
612             {
613                 OGRFieldDefn fldDefn( "id", OFTString );
614                 poDefn->AddFieldDefn(&fldDefn);
615             }
616         }
617     }
618 
619     if( NULL != poObjProps &&
620         json_object_get_type(poObjProps) == json_type_object )
621     {
622         if (bIsGeocouchSpatiallistFormat)
623         {
624             poObjProps = json_object_object_get(poObjProps, "properties");
625             if( NULL == poObjProps ||
626                 json_object_get_type(poObjProps) != json_type_object )
627             {
628                 return true;
629             }
630         }
631 
632         json_object_iter it;
633         it.key = NULL;
634         it.val = NULL;
635         it.entry = NULL;
636         json_object_object_foreachC( poObjProps, it )
637         {
638             int nFldIndex = poDefn->GetFieldIndex( it.key );
639             if( -1 == nFldIndex )
640             {
641                 /* Detect the special kind of GeoJSON output by a spatiallist of GeoCouch */
642                 /* such as http://gd.iriscouch.com/cphosm/_design/geo/_rewrite/data?bbox=12.53%2C55.73%2C12.54%2C55.73 */
643                 if (strcmp(it.key, "_id") == 0)
644                     bFoundId = true;
645                 else if (bFoundId && strcmp(it.key, "_rev") == 0)
646                     bFoundRev = true;
647                 else if (bFoundRev && strcmp(it.key, "type") == 0 &&
648                          it.val != NULL && json_object_get_type(it.val) == json_type_string &&
649                          strcmp(json_object_get_string(it.val), "Feature") == 0)
650                     bFoundTypeFeature = true;
651                 else if (bFoundTypeFeature && strcmp(it.key, "properties") == 0 &&
652                          it.val != NULL && json_object_get_type(it.val) == json_type_object)
653                 {
654                     if (bFlattenGeocouchSpatiallistFormat < 0)
655                         bFlattenGeocouchSpatiallistFormat = CSLTestBoolean(
656                             CPLGetConfigOption("GEOJSON_FLATTEN_GEOCOUCH", "TRUE"));
657                     if (bFlattenGeocouchSpatiallistFormat)
658                     {
659                         poDefn->DeleteFieldDefn(poDefn->GetFieldIndex("type"));
660                         bIsGeocouchSpatiallistFormat = true;
661                         return GenerateFeatureDefn(poLayer, poObj);
662                     }
663                 }
664 
665             }
666             OGRGeoJSONReaderAddOrUpdateField(poDefn, it.key, it.val,
667                                              bFlattenNestedAttributes_,
668                                              chNestedAttributeSeparator_);
669         }
670 
671         bSuccess = true; // SUCCESS
672     }
673     else
674     {
675         json_object_iter it;
676         it.key = NULL;
677         it.val = NULL;
678         it.entry = NULL;
679         json_object_object_foreachC( poObj, it )
680         {
681             if( strcmp(it.key, "type") != 0 &&
682                 strcmp(it.key, "geometry") != 0 &&
683                 strcmp(it.key, "centroid") != 0 &&
684                 strcmp(it.key, "bbox") != 0 &&
685                 strcmp(it.key, "center") != 0 )
686             {
687                 int nFldIndex = poDefn->GetFieldIndex( it.key );
688                 if( -1 == nFldIndex )
689                 {
690                     OGRFieldDefn fldDefn( it.key, OFTString );
691                     poDefn->AddFieldDefn( &fldDefn );
692                 }
693             }
694         }
695 
696         bSuccess = true; // SUCCESS
697         /*CPLError( CE_Failure, CPLE_AppDefined,
698                   "Invalid Feature object. "
699                   "Missing \'properties\' member." );*/
700     }
701 
702     return bSuccess;
703 }
704 
705 /************************************************************************/
706 /*                           AddFeature                                 */
707 /************************************************************************/
708 
AddFeature(OGRGeoJSONLayer * poLayer,OGRGeometry * poGeometry)709 bool OGRGeoJSONReader::AddFeature( OGRGeoJSONLayer* poLayer, OGRGeometry* poGeometry )
710 {
711     bool bAdded = false;
712 
713     // TODO: Should we check if geometry is of type of
714     //       wkbGeometryCollection ?
715 
716     if( NULL != poGeometry )
717     {
718         OGRFeature* poFeature = NULL;
719         poFeature = new OGRFeature( poLayer->GetLayerDefn() );
720         poFeature->SetGeometryDirectly( poGeometry );
721 
722         bAdded = AddFeature( poLayer, poFeature );
723     }
724 
725     return bAdded;
726 }
727 
728 /************************************************************************/
729 /*                           AddFeature                                 */
730 /************************************************************************/
731 
AddFeature(OGRGeoJSONLayer * poLayer,OGRFeature * poFeature)732 bool OGRGeoJSONReader::AddFeature( OGRGeoJSONLayer* poLayer, OGRFeature* poFeature )
733 {
734     bool bAdded = false;
735 
736     if( NULL != poFeature )
737     {
738         poLayer->AddFeature( poFeature );
739         bAdded = true;
740         delete poFeature;
741     }
742 
743     return bAdded;
744 }
745 
746 /************************************************************************/
747 /*                           ReadGeometry                               */
748 /************************************************************************/
749 
ReadGeometry(json_object * poObj)750 OGRGeometry* OGRGeoJSONReader::ReadGeometry( json_object* poObj )
751 {
752     OGRGeometry* poGeometry = NULL;
753 
754     poGeometry = OGRGeoJSONReadGeometry( poObj );
755 
756 /* -------------------------------------------------------------------- */
757 /*      Wrap geometry with GeometryCollection as a common denominator.  */
758 /*      Sometimes a GeoJSON text may consist of objects of different    */
759 /*      geometry types. Users may request wrapping all geometries with  */
760 /*      OGRGeometryCollection type by using option                      */
761 /*      GEOMETRY_AS_COLLECTION=NO|YES (NO is default).                 */
762 /* -------------------------------------------------------------------- */
763     if( NULL != poGeometry )
764     {
765         if( !bGeometryPreserve_
766             && wkbGeometryCollection != poGeometry->getGeometryType() )
767         {
768             OGRGeometryCollection* poMetaGeometry = NULL;
769             poMetaGeometry = new OGRGeometryCollection();
770             poMetaGeometry->addGeometryDirectly( poGeometry );
771             return poMetaGeometry;
772         }
773     }
774 
775     return poGeometry;
776 }
777 
778 /************************************************************************/
779 /*                OGRGeoJSONReaderSetFieldNestedAttribute()             */
780 /************************************************************************/
781 
OGRGeoJSONReaderSetFieldNestedAttribute(OGRLayer * poLayer,OGRFeature * poFeature,const char * pszAttrPrefix,char chSeparator,json_object * poVal)782 static void OGRGeoJSONReaderSetFieldNestedAttribute(OGRLayer* poLayer,
783                                                     OGRFeature* poFeature,
784                                                     const char* pszAttrPrefix,
785                                                     char chSeparator,
786                                                     json_object* poVal)
787 {
788     json_object_iter it;
789     it.key = NULL;
790     it.val = NULL;
791     it.entry = NULL;
792     json_object_object_foreachC( poVal, it )
793     {
794         char szSeparator[2];
795         szSeparator[0] = chSeparator;
796         szSeparator[1] = 0;
797         CPLString osAttrName(CPLSPrintf("%s%s%s", pszAttrPrefix, szSeparator,
798                                         it.key));
799         if( it.val != NULL && json_object_get_type(it.val) == json_type_object )
800         {
801             OGRGeoJSONReaderSetFieldNestedAttribute(poLayer, poFeature,
802                                                     osAttrName, chSeparator,
803                                                     it.val);
804         }
805         else
806         {
807             int nField = poFeature->GetFieldIndex(osAttrName);
808             OGRGeoJSONReaderSetField(poLayer, poFeature, nField,
809                                      osAttrName, it.val, FALSE, 0);
810         }
811     }
812 }
813 
814 /************************************************************************/
815 /*                   OGRGeoJSONReaderSetField()                         */
816 /************************************************************************/
817 
OGRGeoJSONReaderSetField(OGRLayer * poLayer,OGRFeature * poFeature,int nField,const char * pszAttrPrefix,json_object * poVal,bool bFlattenNestedAttributes,char chNestedAttributeSeparator)818 void OGRGeoJSONReaderSetField(OGRLayer* poLayer,
819                               OGRFeature* poFeature,
820                               int nField,
821                               const char* pszAttrPrefix,
822                               json_object* poVal,
823                               bool bFlattenNestedAttributes,
824                               char chNestedAttributeSeparator)
825 {
826     if( bFlattenNestedAttributes &&
827         poVal != NULL && json_object_get_type(poVal) == json_type_object )
828     {
829         OGRGeoJSONReaderSetFieldNestedAttribute(poLayer,
830                                                 poFeature,
831                                                 pszAttrPrefix,
832                                                 chNestedAttributeSeparator,
833                                                 poVal);
834         return ;
835     }
836 
837     OGRFieldDefn* poFieldDefn = poFeature->GetFieldDefnRef(nField);
838     CPLAssert( NULL != poFieldDefn );
839     OGRFieldType eType = poFieldDefn->GetType();
840 
841     if( poVal == NULL)
842     {
843         /* nothing to do */
844     }
845     else if( OFTInteger == eType )
846     {
847         poFeature->SetField( nField, json_object_get_int(poVal) );
848 
849         /* Check if FID available and set correct value. */
850         if( EQUAL( poFieldDefn->GetNameRef(), poLayer->GetFIDColumn() ) )
851             poFeature->SetFID( json_object_get_int(poVal) );
852     }
853     else if( OFTInteger64 == eType )
854     {
855         poFeature->SetField( nField, (GIntBig)json_object_get_int64(poVal) );
856 
857         /* Check if FID available and set correct value. */
858         if( EQUAL( poFieldDefn->GetNameRef(), poLayer->GetFIDColumn() ) )
859             poFeature->SetFID( (GIntBig)json_object_get_int64(poVal) );
860     }
861     else if( OFTReal == eType )
862     {
863         poFeature->SetField( nField, json_object_get_double(poVal) );
864     }
865     else if( OFTIntegerList == eType )
866     {
867         if ( json_object_get_type(poVal) == json_type_array )
868         {
869             int nLength = json_object_array_length(poVal);
870             int* panVal = (int*)CPLMalloc(sizeof(int) * nLength);
871             for(int i=0;i<nLength;i++)
872             {
873                 json_object* poRow = json_object_array_get_idx(poVal, i);
874                 panVal[i] = json_object_get_int(poRow);
875             }
876             poFeature->SetField( nField, nLength, panVal );
877             CPLFree(panVal);
878         }
879     }
880     else if( OFTInteger64List == eType )
881     {
882         if ( json_object_get_type(poVal) == json_type_array )
883         {
884             int nLength = json_object_array_length(poVal);
885             GIntBig* panVal = (GIntBig*)CPLMalloc(sizeof(GIntBig) * nLength);
886             for(int i=0;i<nLength;i++)
887             {
888                 json_object* poRow = json_object_array_get_idx(poVal, i);
889                 panVal[i] = (GIntBig)json_object_get_int64(poRow);
890             }
891             poFeature->SetField( nField, nLength, panVal );
892             CPLFree(panVal);
893         }
894     }
895     else if( OFTRealList == eType )
896     {
897         if ( json_object_get_type(poVal) == json_type_array )
898         {
899             int nLength = json_object_array_length(poVal);
900             double* padfVal = (double*)CPLMalloc(sizeof(double) * nLength);
901             for(int i=0;i<nLength;i++)
902             {
903                 json_object* poRow = json_object_array_get_idx(poVal, i);
904                 padfVal[i] = json_object_get_double(poRow);
905             }
906             poFeature->SetField( nField, nLength, padfVal );
907             CPLFree(padfVal);
908         }
909     }
910     else if( OFTStringList == eType )
911     {
912         if ( json_object_get_type(poVal) == json_type_array )
913         {
914             int nLength = json_object_array_length(poVal);
915             char** papszVal = (char**)CPLMalloc(sizeof(char*) * (nLength+1));
916             int i;
917             for(i=0;i<nLength;i++)
918             {
919                 json_object* poRow = json_object_array_get_idx(poVal, i);
920                 const char* pszVal = json_object_get_string(poRow);
921                 if (pszVal == NULL)
922                     break;
923                 papszVal[i] = CPLStrdup(pszVal);
924             }
925             papszVal[i] = NULL;
926             poFeature->SetField( nField, papszVal );
927             CSLDestroy(papszVal);
928         }
929     }
930     else
931     {
932         poFeature->SetField( nField, json_object_get_string(poVal) );
933     }
934 }
935 
936 /************************************************************************/
937 /*                           ReadFeature()                              */
938 /************************************************************************/
939 
ReadFeature(OGRGeoJSONLayer * poLayer,json_object * poObj)940 OGRFeature* OGRGeoJSONReader::ReadFeature( OGRGeoJSONLayer* poLayer, json_object* poObj )
941 {
942     CPLAssert( NULL != poObj );
943 
944     OGRFeature* poFeature = NULL;
945     poFeature = new OGRFeature( poLayer->GetLayerDefn() );
946 
947 /* -------------------------------------------------------------------- */
948 /*      Translate GeoJSON "properties" object to feature attributes.    */
949 /* -------------------------------------------------------------------- */
950     CPLAssert( NULL != poFeature );
951 
952     json_object* poObjProps = NULL;
953     poObjProps = OGRGeoJSONFindMemberByName( poObj, "properties" );
954     if( !bAttributesSkip_ && NULL != poObjProps &&
955         json_object_get_type(poObjProps) == json_type_object )
956     {
957         if (bIsGeocouchSpatiallistFormat)
958         {
959             json_object* poId = json_object_object_get(poObjProps, "_id");
960             if (poId != NULL && json_object_get_type(poId) == json_type_string)
961                 poFeature->SetField( "_id", json_object_get_string(poId) );
962 
963             json_object* poRev = json_object_object_get(poObjProps, "_rev");
964             if (poRev != NULL && json_object_get_type(poRev) == json_type_string)
965                 poFeature->SetField( "_rev", json_object_get_string(poRev) );
966 
967             poObjProps = json_object_object_get(poObjProps, "properties");
968             if( NULL == poObjProps ||
969                 json_object_get_type(poObjProps) != json_type_object )
970             {
971                 return poFeature;
972             }
973         }
974 
975         int nField = -1;
976         json_object_iter it;
977         it.key = NULL;
978         it.val = NULL;
979         it.entry = NULL;
980         json_object_object_foreachC( poObjProps, it )
981         {
982             nField = poFeature->GetFieldIndex(it.key);
983             OGRGeoJSONReaderSetField(poLayer, poFeature, nField, it.key, it.val,
984                                      bFlattenNestedAttributes_,
985                                      chNestedAttributeSeparator_);
986         }
987     }
988 
989     if( !bAttributesSkip_ && NULL == poObjProps )
990     {
991         json_object_iter it;
992         it.key = NULL;
993         it.val = NULL;
994         it.entry = NULL;
995         json_object_object_foreachC( poObj, it )
996         {
997             int nFldIndex = poFeature->GetFieldIndex(it.key);
998             if( nFldIndex >= 0 )
999             {
1000                 poFeature->SetField(nFldIndex, json_object_get_string(it.val) );
1001             }
1002         }
1003     }
1004 
1005 /* -------------------------------------------------------------------- */
1006 /*      If FID not set, try to use feature-level ID if available        */
1007 /*      and of integral type. Otherwise, leave unset (-1) then index    */
1008 /*      in features sequence will be used as FID.                       */
1009 /* -------------------------------------------------------------------- */
1010     if( -1 == poFeature->GetFID() )
1011     {
1012         json_object* poObjId = NULL;
1013         OGRFieldSubType eSubType;
1014         poObjId = OGRGeoJSONFindMemberByName( poObj, OGRGeoJSONLayer::DefaultFIDColumn );
1015         if( NULL != poObjId
1016             && EQUAL( OGRGeoJSONLayer::DefaultFIDColumn, poLayer->GetFIDColumn() )
1017             && (OFTInteger == GeoJSONPropertyToFieldType( poObjId, eSubType ) ||
1018                 OFTInteger64 == GeoJSONPropertyToFieldType( poObjId, eSubType )) )
1019         {
1020             poFeature->SetFID( (GIntBig)json_object_get_int64( poObjId ) );
1021             int nField = poFeature->GetFieldIndex( poLayer->GetFIDColumn() );
1022             if( -1 != nField )
1023                 poFeature->SetField( nField, poFeature->GetFID() );
1024         }
1025     }
1026 
1027     if( -1 == poFeature->GetFID() )
1028     {
1029         json_object* poObjId = OGRGeoJSONFindMemberByName( poObj, "id" );
1030         if (poObjId != NULL && json_object_get_type(poObjId) == json_type_int)
1031             poFeature->SetFID( (GIntBig)json_object_get_int64( poObjId ) );
1032         else if (poObjId != NULL && json_object_get_type(poObjId) == json_type_string &&
1033                  !poFeature->IsFieldSet(poFeature->GetFieldIndex("id")))
1034             poFeature->SetField( "id", json_object_get_string(poObjId) );
1035     }
1036 
1037 /* -------------------------------------------------------------------- */
1038 /*      Translate geometry sub-object of GeoJSON Feature.               */
1039 /* -------------------------------------------------------------------- */
1040     json_object* poObjGeom = NULL;
1041 
1042     json_object* poTmp = poObj;
1043 
1044     json_object_iter it;
1045     it.key = NULL;
1046     it.val = NULL;
1047     it.entry = NULL;
1048     json_object_object_foreachC(poTmp, it)
1049     {
1050         if( EQUAL( it.key, "geometry" ) ) {
1051             if (it.val != NULL)
1052                 poObjGeom = it.val;
1053             // we're done.  They had 'geometry':null
1054             else
1055                 return poFeature;
1056         }
1057     }
1058 
1059     if( NULL != poObjGeom )
1060     {
1061         // NOTE: If geometry can not be parsed or read correctly
1062         //       then NULL geometry is assigned to a feature and
1063         //       geometry type for layer is classified as wkbUnknown.
1064         OGRGeometry* poGeometry = ReadGeometry( poObjGeom );
1065         if( NULL != poGeometry )
1066         {
1067             poFeature->SetGeometryDirectly( poGeometry );
1068         }
1069     }
1070     else
1071     {
1072         static int bWarned = FALSE;
1073         if( !bWarned )
1074         {
1075             bWarned = TRUE;
1076             CPLDebug("GeoJSON", "Non conformant Feature object. Missing \'geometry\' member." );
1077         }
1078     }
1079 
1080     return poFeature;
1081 }
1082 
1083 /************************************************************************/
1084 /*                           ReadFeatureCollection()                    */
1085 /************************************************************************/
1086 
1087 void
ReadFeatureCollection(OGRGeoJSONLayer * poLayer,json_object * poObj)1088 OGRGeoJSONReader::ReadFeatureCollection( OGRGeoJSONLayer* poLayer, json_object* poObj )
1089 {
1090     json_object* poObjFeatures = NULL;
1091     poObjFeatures = OGRGeoJSONFindMemberByName( poObj, "features" );
1092     if( NULL == poObjFeatures )
1093     {
1094         CPLError( CE_Failure, CPLE_AppDefined,
1095                   "Invalid FeatureCollection object. "
1096                   "Missing \'features\' member." );
1097         return;
1098     }
1099 
1100     if( json_type_array == json_object_get_type( poObjFeatures ) )
1101     {
1102         /* bool bAdded = false; */
1103         OGRFeature* poFeature = NULL;
1104         json_object* poObjFeature = NULL;
1105 
1106         const int nFeatures = json_object_array_length( poObjFeatures );
1107         for( int i = 0; i < nFeatures; ++i )
1108         {
1109             poObjFeature = json_object_array_get_idx( poObjFeatures, i );
1110             poFeature = ReadFeature( poLayer, poObjFeature );
1111             /* bAdded = */ AddFeature( poLayer, poFeature );
1112             //CPLAssert( bAdded );
1113         }
1114         //CPLAssert( nFeatures == poLayer_->GetFeatureCount() );
1115     }
1116 }
1117 
1118 /************************************************************************/
1119 /*                           OGRGeoJSONFindMemberByName                 */
1120 /************************************************************************/
1121 
OGRGeoJSONFindMemberByName(json_object * poObj,const char * pszName)1122 json_object* OGRGeoJSONFindMemberByName( json_object* poObj,
1123                                          const char* pszName )
1124 {
1125     if( NULL == pszName || NULL == poObj)
1126         return NULL;
1127 
1128     json_object* poTmp = poObj;
1129 
1130     json_object_iter it;
1131     it.key = NULL;
1132     it.val = NULL;
1133     it.entry = NULL;
1134     if( NULL != json_object_get_object(poTmp) &&
1135         NULL != json_object_get_object(poTmp)->head )
1136     {
1137         for( it.entry = json_object_get_object(poTmp)->head;
1138              ( it.entry ?
1139                ( it.key = (char*)it.entry->k,
1140                  it.val = (json_object*)it.entry->v, it.entry) : 0);
1141              it.entry = it.entry->next)
1142         {
1143             if( EQUAL( it.key, pszName ) )
1144                 return it.val;
1145         }
1146     }
1147 
1148     return NULL;
1149 }
1150 
1151 /************************************************************************/
1152 /*                           OGRGeoJSONGetType                          */
1153 /************************************************************************/
1154 
OGRGeoJSONGetType(json_object * poObj)1155 GeoJSONObject::Type OGRGeoJSONGetType( json_object* poObj )
1156 {
1157     if( NULL == poObj )
1158         return GeoJSONObject::eUnknown;
1159 
1160     json_object* poObjType = NULL;
1161     poObjType = OGRGeoJSONFindMemberByName( poObj, "type" );
1162     if( NULL == poObjType )
1163         return GeoJSONObject::eUnknown;
1164 
1165     const char* name = json_object_get_string( poObjType );
1166     if( EQUAL( name, "Point" ) )
1167         return GeoJSONObject::ePoint;
1168     else if( EQUAL( name, "LineString" ) )
1169         return GeoJSONObject::eLineString;
1170     else if( EQUAL( name, "Polygon" ) )
1171         return GeoJSONObject::ePolygon;
1172     else if( EQUAL( name, "MultiPoint" ) )
1173         return GeoJSONObject::eMultiPoint;
1174     else if( EQUAL( name, "MultiLineString" ) )
1175         return GeoJSONObject::eMultiLineString;
1176     else if( EQUAL( name, "MultiPolygon" ) )
1177         return GeoJSONObject::eMultiPolygon;
1178     else if( EQUAL( name, "GeometryCollection" ) )
1179         return GeoJSONObject::eGeometryCollection;
1180     else if( EQUAL( name, "Feature" ) )
1181         return GeoJSONObject::eFeature;
1182     else if( EQUAL( name, "FeatureCollection" ) )
1183         return GeoJSONObject::eFeatureCollection;
1184     else
1185         return GeoJSONObject::eUnknown;
1186 }
1187 
1188 /************************************************************************/
1189 /*                           OGRGeoJSONReadGeometry                     */
1190 /************************************************************************/
1191 
OGRGeoJSONReadGeometry(json_object * poObj)1192 OGRGeometry* OGRGeoJSONReadGeometry( json_object* poObj )
1193 {
1194     OGRGeometry* poGeometry = NULL;
1195 
1196     GeoJSONObject::Type objType = OGRGeoJSONGetType( poObj );
1197     if( GeoJSONObject::ePoint == objType )
1198         poGeometry = OGRGeoJSONReadPoint( poObj );
1199     else if( GeoJSONObject::eMultiPoint == objType )
1200         poGeometry = OGRGeoJSONReadMultiPoint( poObj );
1201     else if( GeoJSONObject::eLineString == objType )
1202         poGeometry = OGRGeoJSONReadLineString( poObj );
1203     else if( GeoJSONObject::eMultiLineString == objType )
1204         poGeometry = OGRGeoJSONReadMultiLineString( poObj );
1205     else if( GeoJSONObject::ePolygon == objType )
1206         poGeometry = OGRGeoJSONReadPolygon( poObj );
1207     else if( GeoJSONObject::eMultiPolygon == objType )
1208         poGeometry = OGRGeoJSONReadMultiPolygon( poObj );
1209     else if( GeoJSONObject::eGeometryCollection == objType )
1210         poGeometry = OGRGeoJSONReadGeometryCollection( poObj );
1211     else
1212     {
1213         CPLDebug( "GeoJSON",
1214                   "Unsupported geometry type detected. "
1215                   "Feature gets NULL geometry assigned." );
1216     }
1217     // If we have a crs object in the current object, let's try and
1218     // set it too.
1219 
1220     json_object* poObjSrs = OGRGeoJSONFindMemberByName( poObj, "crs" );
1221     if (poGeometry != NULL && poObjSrs != NULL) {
1222         OGRSpatialReference* poSRS = OGRGeoJSONReadSpatialReference(poObj);
1223         if (poSRS != NULL) {
1224             poGeometry->assignSpatialReference(poSRS);
1225             poSRS->Release();
1226         }
1227     }
1228     return poGeometry;
1229 }
1230 
1231 /************************************************************************/
1232 /*                           OGRGeoJSONReadRawPoint                     */
1233 /************************************************************************/
1234 
OGRGeoJSONReadRawPoint(json_object * poObj,OGRPoint & point)1235 bool OGRGeoJSONReadRawPoint( json_object* poObj, OGRPoint& point )
1236 {
1237     CPLAssert( NULL != poObj );
1238 
1239     if( json_type_array == json_object_get_type( poObj ) )
1240     {
1241         const int nSize = json_object_array_length( poObj );
1242         int iType = 0;
1243 
1244         if( nSize != GeoJSONObject::eMinCoordinateDimension
1245             && nSize != GeoJSONObject::eMaxCoordinateDimension )
1246         {
1247             CPLDebug( "GeoJSON",
1248                       "Invalid coord dimension. Only 2D and 3D supported." );
1249             return false;
1250         }
1251 
1252         json_object* poObjCoord = NULL;
1253 
1254         // Read X coordinate
1255         poObjCoord = json_object_array_get_idx( poObj, 0 );
1256         if (poObjCoord == NULL)
1257         {
1258             CPLDebug( "GeoJSON", "Point: got null object." );
1259             return false;
1260         }
1261 
1262         iType = json_object_get_type(poObjCoord);
1263         if ( (json_type_double != iType) && (json_type_int != iType) )
1264         {
1265             CPLError( CE_Failure, CPLE_AppDefined,
1266                       "Invalid X coordinate. Type is not double or integer for \'%s\'.",
1267                       json_object_to_json_string(poObj) );
1268             return false;
1269         }
1270 
1271         if (iType == json_type_double)
1272             point.setX(json_object_get_double( poObjCoord ));
1273         else
1274             point.setX(json_object_get_int( poObjCoord ));
1275 
1276         // Read Y coordiante
1277         poObjCoord = json_object_array_get_idx( poObj, 1 );
1278         if (poObjCoord == NULL)
1279         {
1280             CPLDebug( "GeoJSON", "Point: got null object." );
1281             return false;
1282         }
1283 
1284         iType = json_object_get_type(poObjCoord);
1285         if ( (json_type_double != iType) && (json_type_int != iType) )
1286         {
1287             CPLError( CE_Failure, CPLE_AppDefined,
1288                       "Invalid Y coordinate. Type is not double or integer for \'%s\'.",
1289                       json_object_to_json_string(poObj) );
1290             return false;
1291         }
1292 
1293         if (iType == json_type_double)
1294             point.setY(json_object_get_double( poObjCoord ));
1295         else
1296             point.setY(json_object_get_int( poObjCoord ));
1297 
1298         // Read Z coordinate
1299         if( nSize == GeoJSONObject::eMaxCoordinateDimension )
1300         {
1301             // Don't *expect* mixed-dimension geometries, although the
1302             // spec doesn't explicitly forbid this.
1303             poObjCoord = json_object_array_get_idx( poObj, 2 );
1304             if (poObjCoord == NULL)
1305             {
1306                 CPLDebug( "GeoJSON", "Point: got null object." );
1307                 return false;
1308             }
1309 
1310             iType = json_object_get_type(poObjCoord);
1311             if ( (json_type_double != iType) && (json_type_int != iType) )
1312             {
1313                 CPLError( CE_Failure, CPLE_AppDefined,
1314                           "Invalid Z coordinate. Type is not double or integer for \'%s\'.",
1315                           json_object_to_json_string(poObj) );
1316                 return false;
1317             }
1318 
1319             if (iType == json_type_double)
1320                 point.setZ(json_object_get_double( poObjCoord ));
1321             else
1322                 point.setZ(json_object_get_int( poObjCoord ));
1323         }
1324         else
1325         {
1326             point.flattenTo2D();
1327         }
1328         return true;
1329     }
1330 
1331     return false;
1332 }
1333 
1334 /************************************************************************/
1335 /*                           OGRGeoJSONReadPoint                        */
1336 /************************************************************************/
1337 
OGRGeoJSONReadPoint(json_object * poObj)1338 OGRPoint* OGRGeoJSONReadPoint( json_object* poObj )
1339 {
1340     CPLAssert( NULL != poObj );
1341 
1342     json_object* poObjCoords = NULL;
1343     poObjCoords = OGRGeoJSONFindMemberByName( poObj, "coordinates" );
1344     if( NULL == poObjCoords )
1345     {
1346         CPLError( CE_Failure, CPLE_AppDefined,
1347                   "Invalid Point object. Missing \'coordinates\' member." );
1348         return NULL;
1349     }
1350 
1351     OGRPoint* poPoint = new OGRPoint();
1352     if( !OGRGeoJSONReadRawPoint( poObjCoords, *poPoint ) )
1353     {
1354         CPLDebug( "GeoJSON", "Point: raw point parsing failure." );
1355         delete poPoint;
1356         return NULL;
1357     }
1358 
1359     return poPoint;
1360 }
1361 
1362 /************************************************************************/
1363 /*                           OGRGeoJSONReadMultiPoint                   */
1364 /************************************************************************/
1365 
OGRGeoJSONReadMultiPoint(json_object * poObj)1366 OGRMultiPoint* OGRGeoJSONReadMultiPoint( json_object* poObj )
1367 {
1368     CPLAssert( NULL != poObj );
1369 
1370     OGRMultiPoint* poMultiPoint = NULL;
1371 
1372     json_object* poObjPoints = NULL;
1373     poObjPoints = OGRGeoJSONFindMemberByName( poObj, "coordinates" );
1374     if( NULL == poObjPoints )
1375     {
1376         CPLError( CE_Failure, CPLE_AppDefined,
1377                   "Invalid MultiPoint object. "
1378                   "Missing \'coordinates\' member." );
1379         return NULL;
1380     }
1381 
1382     if( json_type_array == json_object_get_type( poObjPoints ) )
1383     {
1384         const int nPoints = json_object_array_length( poObjPoints );
1385 
1386         poMultiPoint = new OGRMultiPoint();
1387 
1388         for( int i = 0; i < nPoints; ++i)
1389         {
1390             json_object* poObjCoords = NULL;
1391             poObjCoords = json_object_array_get_idx( poObjPoints, i );
1392 
1393             OGRPoint pt;
1394             if( poObjCoords != NULL && !OGRGeoJSONReadRawPoint( poObjCoords, pt ) )
1395             {
1396                 delete poMultiPoint;
1397                 CPLDebug( "GeoJSON",
1398                           "LineString: raw point parsing failure." );
1399                 return NULL;
1400             }
1401             poMultiPoint->addGeometry( &pt );
1402         }
1403     }
1404 
1405     return poMultiPoint;
1406 }
1407 
1408 /************************************************************************/
1409 /*                           OGRGeoJSONReadLineString                   */
1410 /************************************************************************/
1411 
OGRGeoJSONReadLineString(json_object * poObj,bool bRaw)1412 OGRLineString* OGRGeoJSONReadLineString( json_object* poObj , bool bRaw)
1413 {
1414     CPLAssert( NULL != poObj );
1415 
1416     OGRLineString* poLine = NULL;
1417     json_object* poObjPoints = NULL;
1418 
1419     if( !bRaw )
1420     {
1421         poObjPoints = OGRGeoJSONFindMemberByName( poObj, "coordinates" );
1422         if( NULL == poObjPoints )
1423         {
1424             CPLError( CE_Failure, CPLE_AppDefined,
1425                     "Invalid LineString object. "
1426                     "Missing \'coordinates\' member." );
1427                 return NULL;
1428         }
1429     }
1430     else
1431     {
1432         poObjPoints = poObj;
1433     }
1434 
1435     if( json_type_array == json_object_get_type( poObjPoints ) )
1436     {
1437         const int nPoints = json_object_array_length( poObjPoints );
1438 
1439         poLine = new OGRLineString();
1440         poLine->setNumPoints( nPoints );
1441 
1442         for( int i = 0; i < nPoints; ++i)
1443         {
1444             json_object* poObjCoords = NULL;
1445             poObjCoords = json_object_array_get_idx( poObjPoints, i );
1446             if (poObjCoords == NULL)
1447             {
1448                 delete poLine;
1449                 CPLDebug( "GeoJSON",
1450                           "LineString: got null object." );
1451                 return NULL;
1452             }
1453 
1454             OGRPoint pt;
1455             if( !OGRGeoJSONReadRawPoint( poObjCoords, pt ) )
1456             {
1457                 delete poLine;
1458                 CPLDebug( "GeoJSON",
1459                           "LineString: raw point parsing failure." );
1460                 return NULL;
1461             }
1462             if (pt.getCoordinateDimension() == 2) {
1463                 poLine->setPoint( i, pt.getX(), pt.getY());
1464             } else {
1465                 poLine->setPoint( i, pt.getX(), pt.getY(), pt.getZ() );
1466             }
1467 
1468         }
1469     }
1470 
1471     return poLine;
1472 }
1473 
1474 /************************************************************************/
1475 /*                           OGRGeoJSONReadMultiLineString              */
1476 /************************************************************************/
1477 
OGRGeoJSONReadMultiLineString(json_object * poObj)1478 OGRMultiLineString* OGRGeoJSONReadMultiLineString( json_object* poObj )
1479 {
1480     CPLAssert( NULL != poObj );
1481 
1482     OGRMultiLineString* poMultiLine = NULL;
1483 
1484     json_object* poObjLines = NULL;
1485     poObjLines = OGRGeoJSONFindMemberByName( poObj, "coordinates" );
1486     if( NULL == poObjLines )
1487     {
1488         CPLError( CE_Failure, CPLE_AppDefined,
1489                   "Invalid MultiLineString object. "
1490                   "Missing \'coordinates\' member." );
1491         return NULL;
1492     }
1493 
1494     if( json_type_array == json_object_get_type( poObjLines ) )
1495     {
1496         const int nLines = json_object_array_length( poObjLines );
1497 
1498         poMultiLine = new OGRMultiLineString();
1499 
1500         for( int i = 0; i < nLines; ++i)
1501         {
1502             json_object* poObjLine = NULL;
1503             poObjLine = json_object_array_get_idx( poObjLines, i );
1504 
1505             OGRLineString* poLine;
1506             if (poObjLine != NULL)
1507                 poLine = OGRGeoJSONReadLineString( poObjLine , true );
1508             else
1509                 poLine = new OGRLineString();
1510 
1511             if( NULL != poLine )
1512             {
1513                 poMultiLine->addGeometryDirectly( poLine );
1514             }
1515         }
1516     }
1517 
1518     return poMultiLine;
1519 }
1520 
1521 /************************************************************************/
1522 /*                           OGRGeoJSONReadLinearRing                   */
1523 /************************************************************************/
1524 
OGRGeoJSONReadLinearRing(json_object * poObj)1525 OGRLinearRing* OGRGeoJSONReadLinearRing( json_object* poObj )
1526 {
1527     CPLAssert( NULL != poObj );
1528 
1529     OGRLinearRing* poRing = NULL;
1530 
1531     if( json_type_array == json_object_get_type( poObj ) )
1532     {
1533         const int nPoints = json_object_array_length( poObj );
1534 
1535         poRing= new OGRLinearRing();
1536         poRing->setNumPoints( nPoints );
1537 
1538         for( int i = 0; i < nPoints; ++i)
1539         {
1540             json_object* poObjCoords = NULL;
1541             poObjCoords = json_object_array_get_idx( poObj, i );
1542             if (poObjCoords == NULL)
1543             {
1544                 delete poRing;
1545                 CPLDebug( "GeoJSON",
1546                           "LinearRing: got null object." );
1547                 return NULL;
1548             }
1549 
1550             OGRPoint pt;
1551             if( !OGRGeoJSONReadRawPoint( poObjCoords, pt ) )
1552             {
1553                 delete poRing;
1554                 CPLDebug( "GeoJSON",
1555                           "LinearRing: raw point parsing failure." );
1556                 return NULL;
1557             }
1558 
1559             if( 2 == pt.getCoordinateDimension() )
1560                 poRing->setPoint( i, pt.getX(), pt.getY());
1561             else
1562                 poRing->setPoint( i, pt.getX(), pt.getY(), pt.getZ() );
1563         }
1564     }
1565 
1566     return poRing;
1567 }
1568 
1569 /************************************************************************/
1570 /*                           OGRGeoJSONReadPolygon                      */
1571 /************************************************************************/
1572 
OGRGeoJSONReadPolygon(json_object * poObj,bool bRaw)1573 OGRPolygon* OGRGeoJSONReadPolygon( json_object* poObj , bool bRaw )
1574 {
1575     CPLAssert( NULL != poObj );
1576 
1577     OGRPolygon* poPolygon = NULL;
1578 
1579     json_object* poObjRings = NULL;
1580 
1581     if( !bRaw )
1582     {
1583         poObjRings = OGRGeoJSONFindMemberByName( poObj, "coordinates" );
1584         if( NULL == poObjRings )
1585         {
1586             CPLError( CE_Failure, CPLE_AppDefined,
1587                       "Invalid Polygon object. "
1588                       "Missing \'coordinates\' member." );
1589             return NULL;
1590         }
1591     }
1592     else
1593     {
1594         poObjRings = poObj;
1595     }
1596 
1597     if( json_type_array == json_object_get_type( poObjRings ) )
1598     {
1599         const int nRings = json_object_array_length( poObjRings );
1600         if( nRings > 0 )
1601         {
1602             json_object* poObjPoints = NULL;
1603             poObjPoints = json_object_array_get_idx( poObjRings, 0 );
1604             if (poObjPoints == NULL)
1605             {
1606                 poPolygon = new OGRPolygon();
1607                 poPolygon->addRingDirectly( new OGRLinearRing() );
1608             }
1609             else
1610             {
1611                 OGRLinearRing* poRing = OGRGeoJSONReadLinearRing( poObjPoints );
1612                 if( NULL != poRing )
1613                 {
1614                     poPolygon = new OGRPolygon();
1615                     poPolygon->addRingDirectly( poRing );
1616                 }
1617             }
1618 
1619             for( int i = 1; i < nRings && NULL != poPolygon; ++i )
1620             {
1621                 poObjPoints = json_object_array_get_idx( poObjRings, i );
1622                 if (poObjPoints == NULL)
1623                 {
1624                     poPolygon->addRingDirectly( new OGRLinearRing() );
1625                 }
1626                 else
1627                 {
1628                     OGRLinearRing* poRing = OGRGeoJSONReadLinearRing( poObjPoints );
1629                     if( NULL != poRing )
1630                     {
1631                         poPolygon->addRingDirectly( poRing );
1632                     }
1633                 }
1634             }
1635         }
1636     }
1637 
1638     return poPolygon;
1639 }
1640 
1641 /************************************************************************/
1642 /*                           OGRGeoJSONReadMultiPolygon                 */
1643 /************************************************************************/
1644 
OGRGeoJSONReadMultiPolygon(json_object * poObj)1645 OGRMultiPolygon* OGRGeoJSONReadMultiPolygon( json_object* poObj )
1646 {
1647     CPLAssert( NULL != poObj );
1648 
1649     OGRMultiPolygon* poMultiPoly = NULL;
1650 
1651     json_object* poObjPolys = NULL;
1652     poObjPolys = OGRGeoJSONFindMemberByName( poObj, "coordinates" );
1653     if( NULL == poObjPolys )
1654     {
1655         CPLError( CE_Failure, CPLE_AppDefined,
1656                   "Invalid MultiPolygon object. "
1657                   "Missing \'coordinates\' member." );
1658         return NULL;
1659     }
1660 
1661     if( json_type_array == json_object_get_type( poObjPolys ) )
1662     {
1663         const int nPolys = json_object_array_length( poObjPolys );
1664 
1665         poMultiPoly = new OGRMultiPolygon();
1666 
1667         for( int i = 0; i < nPolys; ++i)
1668         {
1669 
1670             json_object* poObjPoly = NULL;
1671             poObjPoly = json_object_array_get_idx( poObjPolys, i );
1672             if (poObjPoly == NULL)
1673             {
1674                 poMultiPoly->addGeometryDirectly( new OGRPolygon() );
1675             }
1676             else
1677             {
1678                 OGRPolygon* poPoly = OGRGeoJSONReadPolygon( poObjPoly , true );
1679                 if( NULL != poPoly )
1680                 {
1681                     poMultiPoly->addGeometryDirectly( poPoly );
1682                 }
1683             }
1684         }
1685     }
1686 
1687     return poMultiPoly;
1688 }
1689 /************************************************************************/
1690 /*                           OGRGeoJSONReadGeometryCollection           */
1691 /************************************************************************/
1692 
OGRGeoJSONReadGeometryCollection(json_object * poObj)1693 OGRGeometryCollection* OGRGeoJSONReadGeometryCollection( json_object* poObj )
1694 {
1695     CPLAssert( NULL != poObj );
1696 
1697     OGRGeometry* poGeometry = NULL;
1698     OGRGeometryCollection* poCollection = NULL;
1699 
1700     json_object* poObjGeoms = NULL;
1701     poObjGeoms = OGRGeoJSONFindMemberByName( poObj, "geometries" );
1702     if( NULL == poObjGeoms )
1703     {
1704         CPLError( CE_Failure, CPLE_AppDefined,
1705                   "Invalid GeometryCollection object. "
1706                   "Missing \'geometries\' member." );
1707         return NULL;
1708     }
1709 
1710     if( json_type_array == json_object_get_type( poObjGeoms ) )
1711     {
1712         const int nGeoms = json_object_array_length( poObjGeoms );
1713         if( nGeoms > 0 )
1714         {
1715             poCollection = new OGRGeometryCollection();
1716         }
1717 
1718         json_object* poObjGeom = NULL;
1719         for( int i = 0; i < nGeoms; ++i )
1720         {
1721             poObjGeom = json_object_array_get_idx( poObjGeoms, i );
1722             if (poObjGeom == NULL)
1723             {
1724                 CPLDebug( "GeoJSON", "Skipping null sub-geometry");
1725                 continue;
1726             }
1727 
1728             poGeometry = OGRGeoJSONReadGeometry( poObjGeom );
1729             if( NULL != poGeometry )
1730             {
1731                 poCollection->addGeometryDirectly( poGeometry );
1732             }
1733         }
1734     }
1735 
1736     return poCollection;
1737 }
1738 
1739 /************************************************************************/
1740 /*                           OGR_G_ExportToJson                         */
1741 /************************************************************************/
1742 
OGR_G_CreateGeometryFromJson(const char * pszJson)1743 OGRGeometryH OGR_G_CreateGeometryFromJson( const char* pszJson )
1744 {
1745     VALIDATE_POINTER1( pszJson, "OGR_G_CreateGeometryFromJson", NULL );
1746 
1747     if( NULL != pszJson )
1748     {
1749         json_tokener* jstok = NULL;
1750         json_object* poObj = NULL;
1751 
1752         jstok = json_tokener_new();
1753         poObj = json_tokener_parse_ex(jstok, pszJson, -1);
1754         if( jstok->err != json_tokener_success)
1755         {
1756             CPLError( CE_Failure, CPLE_AppDefined,
1757                       "GeoJSON parsing error: %s (at offset %d)",
1758                       json_tokener_error_desc(jstok->err), jstok->char_offset);
1759             json_tokener_free(jstok);
1760             return NULL;
1761         }
1762         json_tokener_free(jstok);
1763 
1764         OGRGeometry* poGeometry = NULL;
1765         poGeometry = OGRGeoJSONReadGeometry( poObj );
1766 
1767         /* Assign WGS84 if no CRS defined on geometry */
1768         if( poGeometry && poGeometry->getSpatialReference() == NULL )
1769         {
1770             poGeometry->assignSpatialReference(OGRSpatialReference::GetWGS84SRS());
1771         }
1772 
1773         /* Release JSON tree. */
1774         json_object_put( poObj );
1775 
1776         return (OGRGeometryH)poGeometry;
1777     }
1778 
1779     /* Translation failed */
1780     return NULL;
1781 }
1782