LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/geojson - ogrgeojsonreader.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 654 483 73.9 %
Date: 2012-04-28 Functions: 29 24 82.8 %

       1                 : /******************************************************************************
       2                 :  * $Id: ogrgeojsonreader.cpp 23662 2011-12-30 11:16:59Z 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              66 : OGRGeoJSONReader::OGRGeoJSONReader()
      41                 :     : poGJObject_( NULL ), poLayer_( NULL ),
      42                 :         bGeometryPreserve_( true ),
      43                 :         bAttributesSkip_( false ),
      44              66 :         bFlattenGeocouchSpatiallistFormat (-1), bFoundId (false), bFoundRev(false), bFoundTypeFeature(false), bIsGeocouchSpatiallistFormat(false)
      45                 : {
      46                 :     // Take a deep breath and get to work.
      47              66 : }
      48                 : 
      49                 : /************************************************************************/
      50                 : /*                          ~OGRGeoJSONReader                           */
      51                 : /************************************************************************/
      52                 : 
      53              66 : OGRGeoJSONReader::~OGRGeoJSONReader()
      54                 : {
      55              66 :     if( NULL != poGJObject_ )
      56                 :     {
      57              66 :         json_object_put(poGJObject_);
      58                 :     }
      59                 : 
      60              66 :     poGJObject_ = NULL;
      61              66 :     poLayer_ = NULL;
      62              66 : }
      63                 : 
      64                 : /************************************************************************/
      65                 : /*                           Parse                                      */
      66                 : /************************************************************************/
      67                 : 
      68              66 : OGRErr OGRGeoJSONReader::Parse( const char* pszText )
      69                 : {
      70              66 :     if( NULL != pszText )
      71                 :     {
      72              66 :         json_tokener* jstok = NULL;
      73              66 :         json_object* jsobj = NULL;
      74                 : 
      75              66 :         jstok = json_tokener_new();
      76              66 :         jsobj = json_tokener_parse_ex(jstok, pszText, -1);
      77              66 :         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              66 :         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              66 :         poGJObject_ = jsobj;
      92                 :     }
      93                 : 
      94              66 :     return OGRERR_NONE;
      95                 : }
      96                 : 
      97                 : /************************************************************************/
      98                 : /*                           ReadLayer                                  */
      99                 : /************************************************************************/
     100                 : 
     101              66 : OGRGeoJSONLayer* OGRGeoJSONReader::ReadLayer( const char* pszName,
     102                 :                                               OGRGeoJSONDataSource* poDS )
     103                 : {
     104              66 :     CPLAssert( NULL == poLayer_ );
     105                 : 
     106              66 :     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              66 :                                     poDS );
     116                 : 
     117              66 :     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              66 :     GeoJSONObject::Type objType = OGRGeoJSONGetType( poGJObject_ );
     130                 : 
     131             100 :     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              34 :         OGRGeometry* poGeometry = NULL;
     140              34 :         poGeometry = ReadGeometry( poGJObject_ );
     141              34 :         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              32 :     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              32 :     else if( GeoJSONObject::eFeatureCollection == objType )
     169                 :     {
     170              32 :         OGRGeoJSONLayer* poThisLayer = NULL;
     171              32 :         poThisLayer = ReadFeatureCollection( poGJObject_ );
     172              32 :         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              66 :     OGRSpatialReference* poSRS = NULL;
     184              66 :     poSRS = OGRGeoJSONReadSpatialReference( poGJObject_ );
     185              66 :     if (poSRS == NULL ) {
     186                 :         // If there is none defined, we use 4326
     187              62 :         poSRS = new OGRSpatialReference();
     188              62 :         if( OGRERR_NONE != poSRS->importFromEPSG( 4326 ) )
     189                 :         {
     190               0 :             delete poSRS;
     191               0 :             poSRS = NULL;
     192                 :         }
     193              62 :         poLayer_->SetSpatialRef( poSRS );
     194              62 :         delete poSRS;
     195                 :     }
     196                 :     else {
     197               4 :         poLayer_->SetSpatialRef( poSRS );
     198               4 :         delete poSRS;
     199                 :     }
     200                 : 
     201                 :     // TODO: FeatureCollection
     202                 : 
     203              66 :     return poLayer_;
     204                 : }
     205                 : 
     206              74 : OGRSpatialReference* OGRGeoJSONReadSpatialReference( json_object* poObj) {
     207                 :     
     208                 : /* -------------------------------------------------------------------- */
     209                 : /*      Read spatial reference definition.                              */
     210                 : /* -------------------------------------------------------------------- */
     211              74 :     OGRSpatialReference* poSRS = NULL;
     212                 : 
     213              74 :     json_object* poObjSrs = OGRGeoJSONFindMemberByName( poObj, "crs" );
     214              74 :     if( NULL != poObjSrs )
     215                 :     {
     216              12 :         json_object* poObjSrsType = OGRGeoJSONFindMemberByName( poObjSrs, "type" );
     217              12 :         if (poObjSrsType == NULL)
     218               0 :             return NULL;
     219                 : 
     220              12 :         const char* pszSrsType = json_object_get_string( poObjSrsType );
     221                 : 
     222                 :         // TODO: Add URL and URN types support
     223              12 :         if( EQUALN( pszSrsType, "NAME", 4 ) )
     224                 :         {
     225              12 :             json_object* poObjSrsProps = OGRGeoJSONFindMemberByName( poObjSrs, "properties" );
     226              12 :             if (poObjSrsProps == NULL)
     227               0 :                 return NULL;
     228                 : 
     229              12 :             json_object* poNameURL = OGRGeoJSONFindMemberByName( poObjSrsProps, "name" );
     230              12 :             if (poNameURL == NULL)
     231               0 :                 return NULL;
     232                 : 
     233              12 :             const char* pszName = json_object_get_string( poNameURL );
     234                 : 
     235              12 :             poSRS = new OGRSpatialReference();
     236              12 :             if( OGRERR_NONE != poSRS->SetFromUserInput( pszName ) )
     237                 :             {
     238               0 :                 delete poSRS;
     239               0 :                 poSRS = NULL;
     240                 :             }
     241                 :         }
     242                 : 
     243              12 :         if( EQUALN( pszSrsType, "EPSG", 4 ) )
     244                 :         {
     245               0 :             json_object* poObjSrsProps = OGRGeoJSONFindMemberByName( poObjSrs, "properties" );
     246               0 :             if (poObjSrsProps == NULL)
     247               0 :                 return NULL;
     248                 : 
     249               0 :             json_object* poObjCode = OGRGeoJSONFindMemberByName( poObjSrsProps, "code" );
     250               0 :             if (poObjCode == NULL)
     251               0 :                 return NULL;
     252                 : 
     253               0 :             int nEPSG = json_object_get_int( poObjCode );
     254                 : 
     255               0 :             poSRS = new OGRSpatialReference();
     256               0 :             if( OGRERR_NONE != poSRS->importFromEPSG( nEPSG ) )
     257                 :             {
     258               0 :                 delete poSRS;
     259               0 :                 poSRS = NULL;
     260                 :             }
     261                 :         }
     262                 : 
     263              12 :         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              12 :         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              74 :     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              66 : bool OGRGeoJSONReader::GenerateLayerDefn()
     333                 : {
     334              66 :     CPLAssert( NULL != poGJObject_ );
     335              66 :     CPLAssert( NULL != poLayer_->GetLayerDefn() );
     336              66 :     CPLAssert( 0 == poLayer_->GetLayerDefn()->GetFieldCount() );
     337                 : 
     338              66 :     bool bSuccess = true;
     339                 : 
     340              66 :     if( bAttributesSkip_ )
     341               0 :         return true;
     342                 : 
     343                 : /* -------------------------------------------------------------------- */
     344                 : /*      Scan all features and generate layer definition.        */
     345                 : /* -------------------------------------------------------------------- */
     346              66 :     GeoJSONObject::Type objType = OGRGeoJSONGetType( poGJObject_ );
     347              66 :     if( GeoJSONObject::eFeature == objType )
     348                 :     {
     349               0 :         bSuccess = GenerateFeatureDefn( poGJObject_ );
     350                 :     }
     351              66 :     else if( GeoJSONObject::eFeatureCollection == objType )
     352                 :     {
     353              32 :         json_object* poObjFeatures = NULL;
     354              32 :         poObjFeatures = OGRGeoJSONFindMemberByName( poGJObject_, "features" );
     355              32 :         if( NULL != poObjFeatures
     356                 :             && json_type_array == json_object_get_type( poObjFeatures ) )
     357                 :         {
     358              32 :             json_object* poObjFeature = NULL;
     359              32 :             const int nFeatures = json_object_array_length( poObjFeatures );
     360             170 :             for( int i = 0; i < nFeatures; ++i )
     361                 :             {
     362             138 :                 poObjFeature = json_object_array_get_idx( poObjFeatures, i );
     363             138 :                 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              66 :   OGRFeatureDefn* poLayerDefn = poLayer_->GetLayerDefn();
     383              66 :   CPLAssert( NULL != poLayerDefn );
     384                 : 
     385              66 :   bool bHasFID = false;
     386                 : 
     387             136 :   for( int i = 0; i < poLayerDefn->GetFieldCount(); ++i )
     388                 :   {
     389              70 :     OGRFieldDefn* poDefn = poLayerDefn->GetFieldDefn(i);
     390              70 :     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              66 :     return bSuccess;
     412                 : }
     413                 : 
     414             142 : bool OGRGeoJSONReader::GenerateFeatureDefn( json_object* poObj )
     415                 : {
     416             142 :     OGRFeatureDefn* poDefn = poLayer_->GetLayerDefn();
     417             142 :     CPLAssert( NULL != poDefn );
     418                 : 
     419             142 :     bool bSuccess = false;
     420                 : 
     421                 : /* -------------------------------------------------------------------- */
     422                 : /*      Read collection of properties.                  */
     423                 : /* -------------------------------------------------------------------- */
     424             142 :     json_object* poObjProps = NULL;
     425             142 :     poObjProps = OGRGeoJSONFindMemberByName( poObj, "properties" );
     426             142 :     if( NULL != poObjProps &&
     427                 :         json_object_get_type(poObjProps) == json_type_object )
     428                 :     {
     429             142 :         if (bIsGeocouchSpatiallistFormat)
     430                 :         {
     431               6 :             poObjProps = json_object_object_get(poObjProps, "properties");
     432               6 :             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             142 :         it.key = NULL;
     441             142 :         it.val = NULL;
     442             142 :         it.entry = NULL;
     443             218 :         json_object_object_foreachC( poObjProps, it )
     444                 :         {
     445              80 :             int nFldIndex = poDefn->GetFieldIndex( it.key );
     446              80 :             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              78 :                 if (strcmp(it.key, "_id") == 0)
     451               4 :                     bFoundId = true;
     452              78 :                 else if (bFoundId && strcmp(it.key, "_rev") == 0)
     453               4 :                     bFoundRev = true;
     454              70 :                 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               4 :                     bFoundTypeFeature = true;
     458              66 :                 else if (bFoundTypeFeature && strcmp(it.key, "properties") == 0 &&
     459                 :                          it.val != NULL && json_object_get_type(it.val) == json_type_object)
     460                 :                 {
     461               4 :                     if (bFlattenGeocouchSpatiallistFormat < 0)
     462                 :                         bFlattenGeocouchSpatiallistFormat = CSLTestBoolean(
     463               4 :                             CPLGetConfigOption("GEOJSON_FLATTEN_GEOCOUCH", "TRUE"));
     464               4 :                     if (bFlattenGeocouchSpatiallistFormat)
     465                 :                     {
     466               4 :                         poDefn->DeleteFieldDefn(poDefn->GetFieldIndex("type"));
     467               4 :                         bIsGeocouchSpatiallistFormat = true;
     468               4 :                         return GenerateFeatureDefn(poObj);
     469                 :                     }
     470                 :                 }
     471                 : 
     472                 :                 OGRFieldDefn fldDefn( it.key,
     473              74 :                     GeoJSONPropertyToFieldType( it.val ) );
     474              74 :                 poDefn->AddFieldDefn( &fldDefn );
     475                 :             }
     476                 :             else
     477                 :             {
     478               2 :                 OGRFieldDefn* poFDefn = poDefn->GetFieldDefn(nFldIndex);
     479               2 :                 OGRFieldType eType = poFDefn->GetType();
     480               2 :                 if( eType == OFTInteger )
     481                 :                 {
     482               2 :                     OGRFieldType eNewType = GeoJSONPropertyToFieldType( it.val );
     483               2 :                     if( eNewType == OFTReal )
     484               2 :                         poFDefn->SetType(eNewType);
     485                 :                 }
     486                 :             }
     487                 :         }
     488                 : 
     489             138 :         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             138 :     return bSuccess;
     499                 : }
     500                 : 
     501                 : /************************************************************************/
     502                 : /*                           AddFeature                                 */
     503                 : /************************************************************************/
     504                 : 
     505              34 : bool OGRGeoJSONReader::AddFeature( OGRGeometry* poGeometry )
     506                 : {
     507              34 :     bool bAdded = false;
     508                 : 
     509                 :     // TODO: Should we check if geometry is of type of 
     510                 :     //       wkbGeometryCollection ?
     511                 : 
     512              34 :     if( NULL != poGeometry )
     513                 :     {
     514              34 :         OGRFeature* poFeature = NULL;
     515              34 :         poFeature = new OGRFeature( poLayer_->GetLayerDefn() );
     516              34 :         poFeature->SetGeometryDirectly( poGeometry );
     517                 : 
     518              34 :         bAdded = AddFeature( poFeature );
     519                 :     }
     520                 :     
     521              34 :     return bAdded;
     522                 : }
     523                 : 
     524                 : /************************************************************************/
     525                 : /*                           AddFeature                                 */
     526                 : /************************************************************************/
     527                 : 
     528             172 : bool OGRGeoJSONReader::AddFeature( OGRFeature* poFeature )
     529                 : {
     530             172 :     bool bAdded = false;
     531                 :   
     532             172 :     if( NULL != poFeature )
     533                 :     {
     534             168 :         poLayer_->AddFeature( poFeature );
     535             168 :         bAdded = true;
     536             168 :         delete poFeature;
     537                 :     }
     538                 : 
     539             172 :     return bAdded;
     540                 : }
     541                 : 
     542                 : /************************************************************************/
     543                 : /*                           ReadGeometry                               */
     544                 : /************************************************************************/
     545                 : 
     546             168 : OGRGeometry* OGRGeoJSONReader::ReadGeometry( json_object* poObj )
     547                 : {
     548             168 :     OGRGeometry* poGeometry = NULL;
     549                 : 
     550             168 :     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             168 :     if( NULL != poGeometry )
     560                 :     {
     561             112 :         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             168 :     return poGeometry;
     572                 : }
     573                 : 
     574                 : /************************************************************************/
     575                 : /*                           ReadFeature()                              */
     576                 : /************************************************************************/
     577                 : 
     578             138 : OGRFeature* OGRGeoJSONReader::ReadFeature( json_object* poObj )
     579                 : {
     580             138 :     CPLAssert( NULL != poObj );
     581             138 :     CPLAssert( NULL != poLayer_ );
     582                 : 
     583             138 :     OGRFeature* poFeature = NULL;
     584             138 :     poFeature = new OGRFeature( poLayer_->GetLayerDefn() );
     585                 : 
     586                 : /* -------------------------------------------------------------------- */
     587                 : /*      Translate GeoJSON "properties" object to feature attributes.    */
     588                 : /* -------------------------------------------------------------------- */
     589             138 :     CPLAssert( NULL != poFeature );
     590                 : 
     591             138 :     json_object* poObjProps = NULL;
     592             138 :     poObjProps = OGRGeoJSONFindMemberByName( poObj, "properties" );
     593             138 :     if( !bAttributesSkip_ && NULL != poObjProps &&
     594                 :         json_object_get_type(poObjProps) == json_type_object )
     595                 :     {
     596             138 :         if (bIsGeocouchSpatiallistFormat)
     597                 :         {
     598               6 :             json_object* poId = json_object_object_get(poObjProps, "_id");
     599               6 :             if (poId != NULL && json_object_get_type(poId) == json_type_string)
     600               6 :                 poFeature->SetField( "_id", json_object_get_string(poId) );
     601                 : 
     602               6 :             json_object* poRev = json_object_object_get(poObjProps, "_rev");
     603               6 :             if (poRev != NULL && json_object_get_type(poRev) == json_type_string)
     604               6 :                 poFeature->SetField( "_rev", json_object_get_string(poRev) );
     605                 : 
     606               6 :             poObjProps = json_object_object_get(poObjProps, "properties");
     607               6 :             if( NULL == poObjProps ||
     608                 :                 json_object_get_type(poObjProps) != json_type_object )
     609                 :             {
     610               0 :                 return poFeature;
     611                 :             }
     612                 :         }
     613                 : 
     614             138 :         int nField = -1;
     615             138 :         OGRFieldDefn* poFieldDefn = NULL;
     616                 :         json_object_iter it;
     617             138 :         it.key = NULL;
     618             138 :         it.val = NULL;
     619             138 :         it.entry = NULL;
     620             202 :         json_object_object_foreachC( poObjProps, it )
     621                 :         {
     622              64 :             nField = poFeature->GetFieldIndex(it.key);
     623              64 :             poFieldDefn = poFeature->GetFieldDefnRef(nField);
     624              64 :             CPLAssert( NULL != poFieldDefn );
     625              64 :             OGRFieldType eType = poFieldDefn->GetType();
     626                 : 
     627              64 :             if( it.val == NULL)
     628                 :             {
     629                 :                 /* nothing to do */
     630                 :             }
     631              64 :             else if( OFTInteger == eType )
     632                 :       {
     633               2 :                 poFeature->SetField( nField, json_object_get_int(it.val) );
     634                 :         
     635                 :         /* Check if FID available and set correct value. */
     636               2 :         if( EQUAL( it.key, poLayer_->GetFIDColumn() ) )
     637               0 :           poFeature->SetFID( json_object_get_int(it.val) );
     638                 :       }
     639              62 :             else if( OFTReal == eType )
     640                 :       {
     641              32 :                 poFeature->SetField( nField, json_object_get_double(it.val) );
     642                 :       }
     643              30 :             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              30 :             else if( OFTRealList == eType )
     659                 :             {
     660               0 :                 if ( json_object_get_type(it.val) == json_type_array )
     661                 :                 {
     662               0 :                     int nLength = json_object_array_length(it.val);
     663               0 :                     double* padfVal = (double*)CPLMalloc(sizeof(double) * nLength);
     664               0 :                     for(int i=0;i<nLength;i++)
     665                 :                     {
     666               0 :                         json_object* poRow = json_object_array_get_idx(it.val, i);
     667               0 :                         padfVal[i] = json_object_get_double(poRow);
     668                 :                     }
     669               0 :                     poFeature->SetField( nField, nLength, padfVal );
     670               0 :                     CPLFree(padfVal);
     671                 :                 }
     672                 :             }
     673              30 :             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              30 :                 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             138 :     if( -1 == poFeature->GetFID() )
     706                 :     {
     707             138 :         json_object* poObjId = NULL;
     708             138 :         poObjId = OGRGeoJSONFindMemberByName( poObj, OGRGeoJSONLayer::DefaultFIDColumn );
     709             138 :         if( NULL != poObjId
     710               0 :             && 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             138 :     if( -1 == poFeature->GetFID() )
     721                 :     {
     722             138 :         json_object* poObjId = OGRGeoJSONFindMemberByName( poObj, "id" );
     723             138 :         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             138 :     json_object* poObjGeom = NULL;
     731                 : 
     732             138 :     json_object* poTmp = poObj;
     733                 : 
     734                 :     json_object_iter it;
     735             138 :     it.key = NULL;
     736             138 :     it.val = NULL;
     737             138 :     it.entry = NULL;    
     738             548 :     json_object_object_foreachC(poTmp, it)
     739                 :     {
     740             410 :         if( EQUAL( it.key, "geometry" ) ) {
     741             134 :             if (it.val != NULL)
     742             134 :                 poObjGeom = it.val;
     743                 :             // we're done.  They had 'geometry':null
     744                 :             else
     745               0 :                 return poFeature;
     746                 :         }
     747                 :     }
     748                 :     
     749             138 :     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             134 :         OGRGeometry* poGeometry = ReadGeometry( poObjGeom );
     755             134 :         if( NULL != poGeometry )
     756                 :         {
     757              78 :             poFeature->SetGeometryDirectly( poGeometry );
     758                 :         }
     759                 :     }
     760                 :     else
     761                 :     {
     762                 :         CPLError( CE_Failure, CPLE_AppDefined,
     763                 :                   "Invalid Feature object. "
     764               4 :                   "Missing \'geometry\' member." );
     765               4 :         delete poFeature;
     766               4 :         return NULL;
     767                 :     }
     768                 : 
     769             134 :     return poFeature;
     770                 : }
     771                 : 
     772                 : /************************************************************************/
     773                 : /*                           ReadFeatureCollection()                    */
     774                 : /************************************************************************/
     775                 : 
     776                 : OGRGeoJSONLayer*
     777              32 : OGRGeoJSONReader::ReadFeatureCollection( json_object* poObj )
     778                 : {
     779              32 :     CPLAssert( NULL != poLayer_ );
     780                 : 
     781              32 :     json_object* poObjFeatures = NULL;
     782              32 :     poObjFeatures = OGRGeoJSONFindMemberByName( poObj, "features" );
     783              32 :     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              32 :     if( json_type_array == json_object_get_type( poObjFeatures ) )
     792                 :     {
     793              32 :         bool bAdded = false;
     794              32 :         OGRFeature* poFeature = NULL;
     795              32 :         json_object* poObjFeature = NULL;
     796                 : 
     797              32 :         const int nFeatures = json_object_array_length( poObjFeatures );
     798             170 :         for( int i = 0; i < nFeatures; ++i )
     799                 :         {
     800             138 :             poObjFeature = json_object_array_get_idx( poObjFeatures, i );
     801             138 :             poFeature = OGRGeoJSONReader::ReadFeature( poObjFeature );
     802             138 :             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              32 :     CPLAssert( NULL != poLayer_ );
     811              32 :     return poLayer_;
     812                 : }
     813                 : 
     814                 : /************************************************************************/
     815                 : /*                           OGRGeoJSONFindMemberByName                 */
     816                 : /************************************************************************/
     817                 : 
     818            2056 : json_object* OGRGeoJSONFindMemberByName( json_object* poObj,
     819                 :                                          const char* pszName )
     820                 : {
     821            2056 :     if( NULL == pszName || NULL == poObj)
     822               0 :         return NULL;
     823                 : 
     824            2056 :     json_object* poTmp = poObj;
     825                 : 
     826                 :     json_object_iter it;
     827            2056 :     it.key = NULL;
     828            2056 :     it.val = NULL;
     829            2056 :     it.entry = NULL;
     830            2056 :     if( NULL != json_object_get_object(poTmp) &&
     831                 :         NULL != json_object_get_object(poTmp)->head )
     832                 :     {
     833            4932 :         for( it.entry = json_object_get_object(poTmp)->head;
     834                 :              ( it.entry ?
     835                 :                ( it.key = (char*)it.entry->k,
     836                 :                  it.val = (json_object*)it.entry->v, it.entry) : 0);
     837                 :              it.entry = it.entry->next)
     838                 :         {
     839            4248 :             if( EQUAL( it.key, pszName ) )
     840            1372 :                 return it.val;
     841                 :         }
     842                 :     }
     843                 : 
     844             684 :     return NULL;
     845                 : }
     846                 : 
     847                 : /************************************************************************/
     848                 : /*                           OGRGeoJSONGetType                          */
     849                 : /************************************************************************/
     850                 : 
     851             462 : GeoJSONObject::Type OGRGeoJSONGetType( json_object* poObj )
     852                 : {
     853             462 :     if( NULL == poObj )
     854               0 :         return GeoJSONObject::eUnknown;
     855                 : 
     856             462 :     json_object* poObjType = NULL;
     857             462 :     poObjType = OGRGeoJSONFindMemberByName( poObj, "type" );
     858             462 :     if( NULL == poObjType )
     859               0 :         return GeoJSONObject::eUnknown;
     860                 : 
     861             462 :     const char* name = json_object_get_string( poObjType );
     862             462 :     if( EQUAL( name, "Point" ) )
     863              60 :         return GeoJSONObject::ePoint;
     864             402 :     else if( EQUAL( name, "LineString" ) )
     865              40 :         return GeoJSONObject::eLineString;
     866             362 :     else if( EQUAL( name, "Polygon" ) )
     867             174 :         return GeoJSONObject::ePolygon;
     868             188 :     else if( EQUAL( name, "MultiPoint" ) )
     869              28 :         return GeoJSONObject::eMultiPoint;
     870             160 :     else if( EQUAL( name, "MultiLineString" ) )
     871              28 :         return GeoJSONObject::eMultiLineString;
     872             132 :     else if( EQUAL( name, "MultiPolygon" ) )
     873              32 :         return GeoJSONObject::eMultiPolygon;
     874             100 :     else if( EQUAL( name, "GeometryCollection" ) )
     875              36 :         return GeoJSONObject::eGeometryCollection;
     876              64 :     else if( EQUAL( name, "Feature" ) )
     877               0 :         return GeoJSONObject::eFeature;
     878              64 :     else if( EQUAL( name, "FeatureCollection" ) )
     879              64 :         return GeoJSONObject::eFeatureCollection;
     880                 :     else
     881               0 :         return GeoJSONObject::eUnknown;
     882                 : }
     883                 : 
     884                 : /************************************************************************/
     885                 : /*                           OGRGeoJSONReadGeometry                     */
     886                 : /************************************************************************/
     887                 : 
     888             330 : OGRGeometry* OGRGeoJSONReadGeometry( json_object* poObj )
     889                 : {
     890             330 :     OGRGeometry* poGeometry = NULL;
     891                 : 
     892             330 :     GeoJSONObject::Type objType = OGRGeoJSONGetType( poObj );
     893             330 :     if( GeoJSONObject::ePoint == objType )
     894              48 :         poGeometry = OGRGeoJSONReadPoint( poObj );
     895             282 :     else if( GeoJSONObject::eMultiPoint == objType )
     896              20 :         poGeometry = OGRGeoJSONReadMultiPoint( poObj );
     897             262 :     else if( GeoJSONObject::eLineString == objType )
     898              32 :         poGeometry = OGRGeoJSONReadLineString( poObj );
     899             230 :     else if( GeoJSONObject::eMultiLineString == objType )
     900              20 :         poGeometry = OGRGeoJSONReadMultiLineString( poObj );
     901             210 :     else if( GeoJSONObject::ePolygon == objType )
     902             166 :         poGeometry = OGRGeoJSONReadPolygon( poObj );
     903              44 :     else if( GeoJSONObject::eMultiPolygon == objType )
     904              24 :         poGeometry = OGRGeoJSONReadMultiPolygon( poObj );
     905              20 :     else if( GeoJSONObject::eGeometryCollection == objType )
     906              20 :         poGeometry = OGRGeoJSONReadGeometryCollection( poObj );
     907                 :     else
     908                 :     {
     909                 :         CPLDebug( "GeoJSON",
     910                 :                   "Unsupported geometry type detected. "
     911               0 :                   "Feature gets NULL geometry assigned." );
     912                 :     }
     913                 :     // If we have a crs object in the current object, let's try and 
     914                 :     // set it too.
     915                 :     
     916             330 :     json_object* poObjSrs = OGRGeoJSONFindMemberByName( poObj, "crs" );
     917             330 :     if (poObjSrs != NULL) {
     918               8 :         OGRSpatialReference* poSRS = OGRGeoJSONReadSpatialReference(poObj);
     919               8 :         if (poSRS != NULL) {
     920               8 :             poGeometry->assignSpatialReference(poSRS);
     921               8 :             poSRS->Release();
     922                 :         }
     923                 :     }
     924             330 :     return poGeometry;
     925                 : }
     926                 : 
     927                 : /************************************************************************/
     928                 : /*                           OGRGeoJSONReadRawPoint                     */
     929                 : /************************************************************************/
     930                 : 
     931            3978 : bool OGRGeoJSONReadRawPoint( json_object* poObj, OGRPoint& point )
     932                 : {
     933            3978 :     CPLAssert( NULL != poObj );
     934                 : 
     935            3978 :     if( json_type_array == json_object_get_type( poObj ) ) 
     936                 :     {
     937            3978 :         const int nSize = json_object_array_length( poObj );
     938            3978 :         int iType = 0;
     939                 : 
     940            3978 :         if( nSize != GeoJSONObject::eMinCoordinateDimension
     941                 :             && nSize != GeoJSONObject::eMaxCoordinateDimension )
     942                 :         {
     943                 :             CPLDebug( "GeoJSON",
     944               4 :                       "Invalid coord dimension. Only 2D and 3D supported." );
     945               4 :             return false;
     946                 :         }
     947                 : 
     948            3974 :         json_object* poObjCoord = NULL;
     949                 : 
     950                 :         // Read X coordinate
     951            3974 :         poObjCoord = json_object_array_get_idx( poObj, 0 );
     952            3974 :         if (poObjCoord == NULL)
     953                 :         {
     954               8 :             CPLDebug( "GeoJSON", "Point: got null object." );
     955               8 :             return false;
     956                 :         }
     957                 :         
     958            3966 :         iType = json_object_get_type(poObjCoord);
     959            3966 :         if ( (json_type_double != iType) && (json_type_int != iType) )
     960                 :         {
     961                 :             CPLError( CE_Failure, CPLE_AppDefined,
     962                 :                       "Invalid X coordinate. Type is not double or integer for \'%s\'.",
     963               0 :                       json_object_to_json_string(poObj) );
     964               0 :             return false;
     965                 :         }
     966                 :         
     967            3966 :         if (iType == json_type_double)
     968            3896 :             point.setX(json_object_get_double( poObjCoord ));
     969                 :         else
     970              70 :             point.setX(json_object_get_int( poObjCoord ));
     971                 :         
     972                 :         // Read Y coordiante
     973            3966 :         poObjCoord = json_object_array_get_idx( poObj, 1 );
     974            3966 :         if (poObjCoord == NULL)
     975                 :         {
     976               4 :             CPLDebug( "GeoJSON", "Point: got null object." );
     977               4 :             return false;
     978                 :         }
     979                 :         
     980            3962 :         iType = json_object_get_type(poObjCoord);
     981            3962 :         if ( (json_type_double != iType) && (json_type_int != iType) )
     982                 :         {
     983                 :             CPLError( CE_Failure, CPLE_AppDefined,
     984                 :                       "Invalid Y coordinate. Type is not double or integer for \'%s\'.",
     985               0 :                       json_object_to_json_string(poObj) );
     986               0 :             return false;
     987                 :         }
     988                 : 
     989            3962 :         if (iType == json_type_double)
     990            3896 :             point.setY(json_object_get_double( poObjCoord ));
     991                 :         else
     992              66 :             point.setY(json_object_get_int( poObjCoord ));
     993                 :         
     994                 :         // Read Z coordinate
     995            3962 :         if( nSize == GeoJSONObject::eMaxCoordinateDimension )
     996                 :         {
     997                 :             // Don't *expect* mixed-dimension geometries, although the 
     998                 :             // spec doesn't explicitly forbid this.
     999               4 :             poObjCoord = json_object_array_get_idx( poObj, 2 );
    1000               4 :             if (poObjCoord == NULL)
    1001                 :             {
    1002               4 :                 CPLDebug( "GeoJSON", "Point: got null object." );
    1003               4 :                 return false;
    1004                 :             }
    1005                 :             
    1006               0 :             iType = json_object_get_type(poObjCoord);
    1007               0 :             if ( (json_type_double != iType) && (json_type_int != iType) )
    1008                 :             {
    1009                 :                 CPLError( CE_Failure, CPLE_AppDefined,
    1010                 :                           "Invalid Z coordinate. Type is not double or integer for \'%s\'.",
    1011               0 :                           json_object_to_json_string(poObj) );
    1012               0 :                 return false;
    1013                 :             }
    1014                 : 
    1015               0 :             if (iType == json_type_double)
    1016               0 :                 point.setZ(json_object_get_double( poObjCoord ));
    1017                 :             else
    1018               0 :                 point.setZ(json_object_get_int( poObjCoord ));
    1019                 :         }
    1020                 :         else
    1021                 :         {
    1022            3958 :             point.flattenTo2D();
    1023                 :         }
    1024            3958 :         return true;
    1025                 :     }
    1026                 :     
    1027               0 :     return false;
    1028                 : }
    1029                 : 
    1030                 : /************************************************************************/
    1031                 : /*                           OGRGeoJSONReadPoint                        */
    1032                 : /************************************************************************/
    1033                 : 
    1034              48 : OGRPoint* OGRGeoJSONReadPoint( json_object* poObj )
    1035                 : {
    1036              48 :     CPLAssert( NULL != poObj );
    1037                 : 
    1038              48 :     json_object* poObjCoords = NULL;
    1039              48 :     poObjCoords = OGRGeoJSONFindMemberByName( poObj, "coordinates" );
    1040              48 :     if( NULL == poObjCoords )
    1041                 :     {
    1042                 :         CPLError( CE_Failure, CPLE_AppDefined,
    1043               4 :                   "Invalid Point object. Missing \'coordinates\' member." );
    1044               4 :         return NULL;
    1045                 :     }
    1046                 : 
    1047              44 :     OGRPoint* poPoint = new OGRPoint();
    1048              44 :     if( !OGRGeoJSONReadRawPoint( poObjCoords, *poPoint ) )
    1049                 :     {
    1050              20 :         CPLDebug( "GeoJSON", "Point: raw point parsing failure." );
    1051              20 :         delete poPoint;
    1052              20 :         return NULL;
    1053                 :     }
    1054                 : 
    1055              24 :     return poPoint;
    1056                 : }
    1057                 : 
    1058                 : /************************************************************************/
    1059                 : /*                           OGRGeoJSONReadMultiPoint                   */
    1060                 : /************************************************************************/
    1061                 : 
    1062              20 : OGRMultiPoint* OGRGeoJSONReadMultiPoint( json_object* poObj )
    1063                 : {
    1064              20 :     CPLAssert( NULL != poObj );
    1065                 : 
    1066              20 :     OGRMultiPoint* poMultiPoint = NULL;
    1067                 : 
    1068              20 :     json_object* poObjPoints = NULL;
    1069              20 :     poObjPoints = OGRGeoJSONFindMemberByName( poObj, "coordinates" );
    1070              20 :     if( NULL == poObjPoints )
    1071                 :     {
    1072                 :         CPLError( CE_Failure, CPLE_AppDefined,
    1073                 :                   "Invalid MultiPoint object. "
    1074               4 :                   "Missing \'coordinates\' member." );
    1075               4 :         return NULL;
    1076                 :     }
    1077                 : 
    1078              16 :     if( json_type_array == json_object_get_type( poObjPoints ) )
    1079                 :     {
    1080              16 :         const int nPoints = json_object_array_length( poObjPoints );
    1081                 : 
    1082              16 :         poMultiPoint = new OGRMultiPoint();
    1083                 : 
    1084              16 :         for( int i = 0; i < nPoints; ++i)
    1085                 :         {
    1086              36 :             json_object* poObjCoords = NULL;
    1087              36 :             poObjCoords = json_object_array_get_idx( poObjPoints, i );
    1088                 : 
    1089              36 :             OGRPoint pt;
    1090              36 :             if( poObjCoords != NULL && !OGRGeoJSONReadRawPoint( poObjCoords, pt ) )
    1091                 :             {
    1092               0 :                 delete poMultiPoint;
    1093                 :                 CPLDebug( "GeoJSON",
    1094               0 :                           "LineString: raw point parsing failure." );
    1095               0 :                 return NULL;
    1096                 :             }
    1097              36 :             poMultiPoint->addGeometry( &pt );
    1098                 :         }
    1099                 :     }
    1100                 : 
    1101              16 :     return poMultiPoint;
    1102                 : }
    1103                 : 
    1104                 : /************************************************************************/
    1105                 : /*                           OGRGeoJSONReadLineString                   */
    1106                 : /************************************************************************/
    1107                 : 
    1108              60 : OGRLineString* OGRGeoJSONReadLineString( json_object* poObj , bool bRaw)
    1109                 : {
    1110              60 :     CPLAssert( NULL != poObj );
    1111                 : 
    1112              60 :     OGRLineString* poLine = NULL;
    1113              60 :     json_object* poObjPoints = NULL;
    1114                 :     
    1115              60 :     if( !bRaw )
    1116                 :     {
    1117              32 :         poObjPoints = OGRGeoJSONFindMemberByName( poObj, "coordinates" );
    1118              32 :         if( NULL == poObjPoints )
    1119                 :         {
    1120                 :             CPLError( CE_Failure, CPLE_AppDefined,
    1121                 :                     "Invalid LineString object. "
    1122               4 :                     "Missing \'coordinates\' member." );
    1123               4 :                 return NULL;
    1124                 :         }
    1125                 :     }
    1126                 :     else
    1127                 :     {
    1128              28 :         poObjPoints = poObj;
    1129                 :     }
    1130                 : 
    1131              56 :     if( json_type_array == json_object_get_type( poObjPoints ) )
    1132                 :     {
    1133              56 :         const int nPoints = json_object_array_length( poObjPoints );
    1134                 : 
    1135              56 :         poLine = new OGRLineString();
    1136              56 :         poLine->setNumPoints( nPoints );
    1137                 : 
    1138              56 :         for( int i = 0; i < nPoints; ++i)
    1139                 :         {
    1140             104 :             json_object* poObjCoords = NULL;
    1141             104 :             poObjCoords = json_object_array_get_idx( poObjPoints, i );
    1142             104 :             if (poObjCoords == NULL)
    1143                 :             {
    1144              16 :                 delete poLine;
    1145                 :                 CPLDebug( "GeoJSON",
    1146              16 :                           "LineString: got null object." );
    1147              16 :                 return NULL;
    1148                 :             }
    1149                 :             
    1150              88 :             OGRPoint pt;
    1151              88 :             if( !OGRGeoJSONReadRawPoint( poObjCoords, pt ) )
    1152                 :             {
    1153               0 :                 delete poLine;
    1154                 :                 CPLDebug( "GeoJSON",
    1155               0 :                           "LineString: raw point parsing failure." );
    1156               0 :                 return NULL;
    1157                 :             }
    1158              88 :             if (pt.getCoordinateDimension() == 2) {
    1159              88 :                 poLine->setPoint( i, pt.getX(), pt.getY());
    1160                 :             } else {
    1161               0 :                 poLine->setPoint( i, pt.getX(), pt.getY(), pt.getZ() );
    1162                 :             }
    1163                 :             
    1164                 :         }
    1165                 :     }
    1166                 : 
    1167              40 :     return poLine;
    1168                 : }
    1169                 : 
    1170                 : /************************************************************************/
    1171                 : /*                           OGRGeoJSONReadMultiLineString              */
    1172                 : /************************************************************************/
    1173                 : 
    1174              20 : OGRMultiLineString* OGRGeoJSONReadMultiLineString( json_object* poObj )
    1175                 : {
    1176              20 :     CPLAssert( NULL != poObj );
    1177                 : 
    1178              20 :     OGRMultiLineString* poMultiLine = NULL;
    1179                 : 
    1180              20 :     json_object* poObjLines = NULL;
    1181              20 :     poObjLines = OGRGeoJSONFindMemberByName( poObj, "coordinates" );
    1182              20 :     if( NULL == poObjLines )
    1183                 :     {
    1184                 :         CPLError( CE_Failure, CPLE_AppDefined,
    1185                 :                   "Invalid MultiLineString object. "
    1186               4 :                   "Missing \'coordinates\' member." );
    1187               4 :         return NULL;
    1188                 :     }
    1189                 : 
    1190              16 :     if( json_type_array == json_object_get_type( poObjLines ) )
    1191                 :     {
    1192              16 :         const int nLines = json_object_array_length( poObjLines );
    1193                 : 
    1194              16 :         poMultiLine = new OGRMultiLineString();
    1195                 : 
    1196              52 :         for( int i = 0; i < nLines; ++i)
    1197                 :         {
    1198              36 :             json_object* poObjLine = NULL;
    1199              36 :             poObjLine = json_object_array_get_idx( poObjLines, i );
    1200                 : 
    1201                 :             OGRLineString* poLine;
    1202              36 :             if (poObjLine != NULL)
    1203              28 :                 poLine = OGRGeoJSONReadLineString( poObjLine , true );
    1204                 :             else
    1205               8 :                 poLine = new OGRLineString();
    1206                 : 
    1207              36 :             if( NULL != poLine )
    1208                 :             {
    1209              28 :                 poMultiLine->addGeometryDirectly( poLine );
    1210                 :             }
    1211                 :         }
    1212                 :     }
    1213                 : 
    1214              16 :     return poMultiLine;
    1215                 : }
    1216                 : 
    1217                 : /************************************************************************/
    1218                 : /*                           OGRGeoJSONReadLinearRing                   */
    1219                 : /************************************************************************/
    1220                 : 
    1221             186 : OGRLinearRing* OGRGeoJSONReadLinearRing( json_object* poObj )
    1222                 : {
    1223             186 :     CPLAssert( NULL != poObj );
    1224                 : 
    1225             186 :     OGRLinearRing* poRing = NULL;
    1226                 : 
    1227             186 :     if( json_type_array == json_object_get_type( poObj ) )
    1228                 :     {
    1229             186 :         const int nPoints = json_object_array_length( poObj );
    1230                 : 
    1231             186 :         poRing= new OGRLinearRing();
    1232             186 :         poRing->setNumPoints( nPoints );
    1233                 : 
    1234             186 :         for( int i = 0; i < nPoints; ++i)
    1235                 :         {
    1236            3822 :             json_object* poObjCoords = NULL;
    1237            3822 :             poObjCoords = json_object_array_get_idx( poObj, i );
    1238            3822 :             if (poObjCoords == NULL)
    1239                 :             {
    1240               0 :                 delete poRing;
    1241                 :                 CPLDebug( "GeoJSON",
    1242               0 :                           "LinearRing: got null object." );
    1243               0 :                 return NULL;
    1244                 :             }
    1245                 : 
    1246            3822 :             OGRPoint pt;
    1247            3822 :             if( !OGRGeoJSONReadRawPoint( poObjCoords, pt ) )
    1248                 :             {
    1249               0 :                 delete poRing;
    1250                 :                 CPLDebug( "GeoJSON",
    1251               0 :                           "LinearRing: raw point parsing failure." );
    1252               0 :                 return NULL;
    1253                 :             }
    1254                 :             
    1255            3822 :             if( 2 == pt.getCoordinateDimension() )
    1256            3822 :                 poRing->setPoint( i, pt.getX(), pt.getY());
    1257                 :             else
    1258               0 :                 poRing->setPoint( i, pt.getX(), pt.getY(), pt.getZ() );
    1259                 :         }
    1260                 :     }
    1261                 : 
    1262             186 :     return poRing;
    1263                 : }
    1264                 : 
    1265                 : /************************************************************************/
    1266                 : /*                           OGRGeoJSONReadPolygon                      */
    1267                 : /************************************************************************/
    1268                 : 
    1269             198 : OGRPolygon* OGRGeoJSONReadPolygon( json_object* poObj , bool bRaw )
    1270                 : {
    1271             198 :     CPLAssert( NULL != poObj );
    1272                 : 
    1273             198 :     OGRPolygon* poPolygon = NULL;
    1274                 : 
    1275             198 :     json_object* poObjRings = NULL;
    1276                 :     
    1277             198 :     if( !bRaw )
    1278                 :     {
    1279             166 :         poObjRings = OGRGeoJSONFindMemberByName( poObj, "coordinates" );
    1280             166 :         if( NULL == poObjRings )
    1281                 :         {
    1282                 :             CPLError( CE_Failure, CPLE_AppDefined,
    1283                 :                       "Invalid Polygon object. "
    1284               4 :                       "Missing \'coordinates\' member." );
    1285               4 :             return NULL;
    1286                 :         }
    1287                 :     }
    1288                 :     else
    1289                 :     {
    1290              32 :         poObjRings = poObj;
    1291                 :     }
    1292                 :     
    1293             194 :     if( json_type_array == json_object_get_type( poObjRings ) )
    1294                 :     {
    1295             194 :         const int nRings = json_object_array_length( poObjRings );
    1296             194 :         if( nRings > 0 )
    1297                 :         {
    1298             186 :             json_object* poObjPoints = NULL;
    1299             186 :             poObjPoints = json_object_array_get_idx( poObjRings, 0 );
    1300             186 :             if (poObjPoints == NULL)
    1301                 :             {
    1302               8 :                 poPolygon = new OGRPolygon();
    1303              16 :                 poPolygon->addRingDirectly( new OGRLinearRing() );
    1304                 :             }
    1305                 :             else
    1306                 :             {
    1307             178 :                 OGRLinearRing* poRing = OGRGeoJSONReadLinearRing( poObjPoints );
    1308             178 :                 if( NULL != poRing )
    1309                 :                 {
    1310             178 :                     poPolygon = new OGRPolygon();
    1311             178 :                     poPolygon->addRingDirectly( poRing );
    1312                 :                 }
    1313                 :             }
    1314                 : 
    1315             198 :             for( int i = 1; i < nRings && NULL != poPolygon; ++i )
    1316                 :             {
    1317              12 :                 poObjPoints = json_object_array_get_idx( poObjRings, i );
    1318              12 :                 if (poObjPoints == NULL)
    1319                 :                 {
    1320               4 :                     poPolygon->addRingDirectly( new OGRLinearRing() );
    1321                 :                 }
    1322                 :                 else
    1323                 :                 {
    1324               8 :                     OGRLinearRing* poRing = OGRGeoJSONReadLinearRing( poObjPoints );
    1325               8 :                     if( NULL != poRing )
    1326                 :                     {
    1327               8 :                         poPolygon->addRingDirectly( poRing );
    1328                 :                     }
    1329                 :                 }
    1330                 :             }
    1331                 :         }
    1332                 :     }
    1333                 : 
    1334             194 :     return poPolygon;
    1335                 : }
    1336                 : 
    1337                 : /************************************************************************/
    1338                 : /*                           OGRGeoJSONReadMultiPolygon                 */
    1339                 : /************************************************************************/
    1340                 : 
    1341              24 : OGRMultiPolygon* OGRGeoJSONReadMultiPolygon( json_object* poObj )
    1342                 : {
    1343              24 :     CPLAssert( NULL != poObj );
    1344                 : 
    1345              24 :     OGRMultiPolygon* poMultiPoly = NULL;
    1346                 : 
    1347              24 :     json_object* poObjPolys = NULL;
    1348              24 :     poObjPolys = OGRGeoJSONFindMemberByName( poObj, "coordinates" );
    1349              24 :     if( NULL == poObjPolys )
    1350                 :     {
    1351                 :         CPLError( CE_Failure, CPLE_AppDefined,
    1352                 :                   "Invalid MultiPolygon object. "
    1353               4 :                   "Missing \'coordinates\' member." );
    1354               4 :         return NULL;
    1355                 :     }
    1356                 : 
    1357              20 :     if( json_type_array == json_object_get_type( poObjPolys ) )
    1358                 :     {
    1359              20 :         const int nPolys = json_object_array_length( poObjPolys );
    1360                 : 
    1361              20 :         poMultiPoly = new OGRMultiPolygon();
    1362                 : 
    1363              64 :         for( int i = 0; i < nPolys; ++i)
    1364                 :         {
    1365                 : 
    1366              44 :             json_object* poObjPoly = NULL;
    1367              44 :             poObjPoly = json_object_array_get_idx( poObjPolys, i );
    1368              44 :             if (poObjPoly == NULL)
    1369                 :             {
    1370              12 :                 poMultiPoly->addGeometryDirectly( new OGRPolygon() );
    1371                 :             }
    1372                 :             else
    1373                 :             {
    1374              32 :                 OGRPolygon* poPoly = OGRGeoJSONReadPolygon( poObjPoly , true );
    1375              32 :                 if( NULL != poPoly )
    1376                 :                 {
    1377              24 :                     poMultiPoly->addGeometryDirectly( poPoly );
    1378                 :                 }
    1379                 :             }
    1380                 :         }
    1381                 :     }
    1382                 : 
    1383              20 :     return poMultiPoly;
    1384                 : }
    1385                 : /************************************************************************/
    1386                 : /*                           OGRGeoJSONReadGeometryCollection           */
    1387                 : /************************************************************************/
    1388                 : 
    1389              20 : OGRGeometryCollection* OGRGeoJSONReadGeometryCollection( json_object* poObj )
    1390                 : {
    1391              20 :     CPLAssert( NULL != poObj );
    1392                 : 
    1393              20 :     OGRGeometry* poGeometry = NULL;
    1394              20 :     OGRGeometryCollection* poCollection = NULL;
    1395                 : 
    1396              20 :     json_object* poObjGeoms = NULL;
    1397              20 :     poObjGeoms = OGRGeoJSONFindMemberByName( poObj, "geometries" );
    1398              20 :     if( NULL == poObjGeoms )
    1399                 :     {
    1400                 :         CPLError( CE_Failure, CPLE_AppDefined,
    1401                 :                   "Invalid GeometryCollection object. "
    1402               4 :                   "Missing \'geometries\' member." );
    1403               4 :         return NULL;
    1404                 :     }
    1405                 : 
    1406              16 :     if( json_type_array == json_object_get_type( poObjGeoms ) )
    1407                 :     {
    1408              16 :         const int nGeoms = json_object_array_length( poObjGeoms );
    1409              16 :         if( nGeoms > 0 )
    1410                 :         {
    1411              16 :             poCollection = new OGRGeometryCollection();
    1412                 :         }
    1413                 : 
    1414              16 :         json_object* poObjGeom = NULL;
    1415              48 :         for( int i = 0; i < nGeoms; ++i )
    1416                 :         {
    1417              32 :             poObjGeom = json_object_array_get_idx( poObjGeoms, i );
    1418              32 :             if (poObjGeom == NULL)
    1419                 :             {
    1420              12 :                 CPLDebug( "GeoJSON", "Skipping null sub-geometry");
    1421              12 :                 continue;
    1422                 :             }
    1423                 : 
    1424              20 :             poGeometry = OGRGeoJSONReadGeometry( poObjGeom );
    1425              20 :             if( NULL != poGeometry )
    1426                 :             {
    1427              20 :                 poCollection->addGeometryDirectly( poGeometry );
    1428                 :             }
    1429                 :         }
    1430                 :     }
    1431                 : 
    1432              16 :     return poCollection;
    1433                 : }
    1434                 : 
    1435                 : /************************************************************************/
    1436                 : /*                           OGR_G_ExportToJson                         */
    1437                 : /************************************************************************/
    1438                 : 
    1439               0 : OGRGeometryH OGR_G_CreateGeometryFromJson( const char* pszJson )
    1440                 : {
    1441               0 :     VALIDATE_POINTER1( pszJson, "OGR_G_CreateGeometryFromJson", NULL );
    1442                 : 
    1443               0 :     if( NULL != pszJson )
    1444                 :     {
    1445               0 :         json_tokener* jstok = NULL;
    1446               0 :         json_object* poObj = NULL;
    1447                 : 
    1448               0 :         jstok = json_tokener_new();
    1449               0 :         poObj = json_tokener_parse_ex(jstok, pszJson, -1);
    1450               0 :         if( jstok->err != json_tokener_success)
    1451                 :         {
    1452                 :             CPLError( CE_Failure, CPLE_AppDefined,
    1453                 :                       "GeoJSON parsing error: %s (at offset %d)",
    1454               0 :                       json_tokener_errors[jstok->err], jstok->char_offset);
    1455               0 :             json_tokener_free(jstok);
    1456               0 :             return NULL;
    1457                 :         }
    1458               0 :         json_tokener_free(jstok);
    1459                 : 
    1460               0 :         OGRGeometry* poGeometry = NULL;
    1461               0 :         poGeometry = OGRGeoJSONReadGeometry( poObj );
    1462                 :         
    1463                 :         /* Release JSON tree. */
    1464               0 :         json_object_put( poObj );
    1465                 : 
    1466               0 :         return (OGRGeometryH)poGeometry;
    1467                 :     }
    1468                 : 
    1469                 :     /* Translation failed */
    1470               0 :     return NULL;
    1471                 : }
    1472                 : 

Generated by: LCOV version 1.7