LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/geojson - ogrgeojsonreader.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 658 503 76.4 %
Date: 2013-03-30 Functions: 29 24 82.8 %

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

Generated by: LCOV version 1.7