LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/geojson - ogrgeojsonreader.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 655 500 76.3 %
Date: 2011-12-18 Functions: 29 24 82.8 %

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

Generated by: LCOV version 1.7