LCOV - code coverage report
Current view: directory - ogr/ogrsf_frmts/geojson - ogrgeojsondatasource.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 160 96 60.0 %
Date: 2010-01-09 Functions: 16 14 87.5 %

       1                 : /******************************************************************************
       2                 :  * $Id$
       3                 :  *
       4                 :  * Project:  OpenGIS Simple Features Reference Implementation
       5                 :  * Purpose:  Implementation of OGRGeoJSONDataSource 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 "ogr_geojson.h"
      30                 : #include "ogrgeojsonutils.h"
      31                 : #include "ogrgeojsonreader.h"
      32                 : #include <cpl_http.h>
      33                 : #include <jsonc/json.h> // JSON-C
      34                 : #include <cstdlib>
      35                 : 
      36                 : /************************************************************************/
      37                 : /*                           OGRGeoJSONDataSource()                     */
      38                 : /************************************************************************/
      39                 : 
      40             123 : OGRGeoJSONDataSource::OGRGeoJSONDataSource()
      41                 :     : pszName_(NULL), pszGeoData_(NULL),
      42                 :         papoLayers_(NULL), nLayers_(0), fpOut_(NULL),
      43                 :         flTransGeom_( OGRGeoJSONDataSource::eGeometryPreserve ),
      44             123 :         flTransAttrs_( OGRGeoJSONDataSource::eAtributesPreserve )
      45                 : {
      46                 :     // I've got constructed. Lunch time!
      47             123 : }
      48                 : 
      49                 : /************************************************************************/
      50                 : /*                           ~OGRGeoJSONDataSource()                    */
      51                 : /************************************************************************/
      52                 : 
      53             246 : OGRGeoJSONDataSource::~OGRGeoJSONDataSource()
      54                 : {
      55             123 :     Clear();
      56                 :     
      57             123 :     if( NULL != fpOut_ )
      58                 :     {
      59               0 :         if ( fpOut_ != stdout )
      60                 :         {
      61               0 :             VSIFClose( fpOut_ );
      62               0 :             fpOut_ = NULL;
      63                 :         }
      64                 :     }
      65             246 : }
      66                 : 
      67                 : /************************************************************************/
      68                 : /*                           Open()                                     */
      69                 : /************************************************************************/
      70                 : 
      71             117 : int OGRGeoJSONDataSource::Open( const char* pszName )
      72                 : {
      73                 :     CPLAssert( NULL != pszName );
      74                 : 
      75                 : /* -------------------------------------------------------------------- */
      76                 : /*      Release resources allocated during previous request.            */
      77                 : /* -------------------------------------------------------------------- */
      78             117 :     if( NULL != papoLayers_ )
      79                 :     {
      80                 :         CPLAssert( nLayers_ > 0 );
      81               0 :         Clear();
      82                 :     }
      83                 : 
      84                 : /* -------------------------------------------------------------------- */
      85                 : /*      Determine type of data source: text file (.geojson, .json),     */
      86                 : /*      Web Service or text passed directly and load data.              */
      87                 : /* -------------------------------------------------------------------- */
      88                 :     GeoJSONSourceType nSrcType;
      89                 :     
      90             117 :     nSrcType = GeoJSONGetSourceType( pszName );
      91             117 :     if( eGeoJSONSourceService == nSrcType )
      92                 :     {
      93               0 :         if( !ReadFromService( pszName ) )
      94               0 :             return FALSE;
      95                 :     }
      96             117 :     else if( eGeoJSONSourceText == nSrcType )
      97                 :     {
      98               0 :         pszGeoData_ = CPLStrdup( pszName );
      99                 :     }
     100             117 :     else if( eGeoJSONSourceFile == nSrcType )
     101                 :     {
     102              14 :         if( !ReadFromFile( pszName ) )
     103               0 :             return FALSE;
     104                 :     }
     105                 :     else
     106                 :     {
     107             103 :         Clear();
     108             103 :         return FALSE;
     109                 :     }
     110                 : 
     111                 : /* -------------------------------------------------------------------- */
     112                 : /*      Construct OGR layer and feature objects from                    */
     113                 : /*      GeoJSON text tree.                                              */
     114                 : /* -------------------------------------------------------------------- */
     115              14 :     if( NULL == pszGeoData_ )
     116                 :     {
     117               0 :         Clear();
     118               0 :         return FALSE;
     119                 :     }
     120                 : 
     121              14 :     OGRGeoJSONLayer* poLayer = LoadLayer();
     122              14 :     if( NULL == poLayer )
     123                 :     {
     124               0 :         Clear();
     125                 :         
     126                 :         CPLError( CE_Failure, CPLE_OpenFailed, 
     127               0 :                   "Failed to read GeoJSON data" );
     128               0 :         return FALSE;
     129                 :     }
     130                 : 
     131              14 :     poLayer->DetectGeometryType();
     132                 : 
     133                 : /* -------------------------------------------------------------------- */
     134                 : /*      NOTE: Currently, the driver generates only one layer per        */
     135                 : /*      single GeoJSON file, input or service request.                  */
     136                 : /* -------------------------------------------------------------------- */
     137              14 :     const int nLayerIndex = 0;
     138              14 :     nLayers_ = 1;
     139                 :     
     140                 :     papoLayers_ =
     141              14 :         (OGRGeoJSONLayer**)CPLMalloc( sizeof(OGRGeoJSONLayer*) * nLayers_ );
     142              14 :     papoLayers_[nLayerIndex] = poLayer; 
     143                 : 
     144                 :     CPLAssert( NULL != papoLayers_ );
     145                 :     CPLAssert( nLayers_ > 0 );
     146              14 :     return TRUE;
     147                 : }
     148                 : 
     149                 : /************************************************************************/
     150                 : /*                           GetName()                                  */
     151                 : /************************************************************************/
     152                 : 
     153              20 : const char* OGRGeoJSONDataSource::GetName()
     154                 : {
     155              20 :     return pszName_;
     156                 : }
     157                 : 
     158                 : /************************************************************************/
     159                 : /*                           GetLayerCount()                            */
     160                 : /************************************************************************/
     161                 : 
     162              16 : int OGRGeoJSONDataSource::GetLayerCount()
     163                 : {
     164              16 :     return nLayers_;
     165                 : }
     166                 : 
     167                 : /************************************************************************/
     168                 : /*                           GetLayer()                                 */
     169                 : /************************************************************************/
     170                 : 
     171              14 : OGRLayer* OGRGeoJSONDataSource::GetLayer( int nLayer )
     172                 : {
     173              14 :     if( 0 <= nLayer || nLayer < nLayers_ )
     174                 :     {
     175                 :         CPLAssert( NULL != papoLayers_[nLayer] );
     176                 : 
     177              14 :         OGRLayer* poLayer = papoLayers_[nLayer];
     178                 : 
     179                 :         /* Return layer in readable state. */
     180              14 :         poLayer->ResetReading();
     181              14 :         return poLayer;
     182                 :     }
     183                 : 
     184               0 :     return NULL;
     185                 : }
     186                 : 
     187                 : /************************************************************************/
     188                 : /*                            CreateLayer()                             */
     189                 : /************************************************************************/
     190                 : 
     191               6 : OGRLayer* OGRGeoJSONDataSource::CreateLayer( const char* pszName_,
     192                 :                                              OGRSpatialReference* poSRS,
     193                 :                                              OGRwkbGeometryType eGType,
     194                 :                                              char** papszOptions )
     195                 : {
     196               6 :     OGRGeoJSONLayer* poLayer = NULL;
     197               6 :     poLayer = new OGRGeoJSONLayer( pszName_, poSRS, eGType, papszOptions, this );
     198                 : 
     199                 : /* -------------------------------------------------------------------- */
     200                 : /*      Add layer to data source layer list.                            */
     201                 : /* -------------------------------------------------------------------- */
     202                 :     
     203                 :     // TOOD: Waiting for multi-layer support
     204                 :     CPLAssert( 0 == nLayers_ );
     205                 : 
     206                 :     papoLayers_ = (OGRGeoJSONLayer **)
     207               6 :         CPLRealloc( papoLayers_,  sizeof(OGRGeoJSONLayer*) * (nLayers_ + 1) );
     208                 :     
     209               6 :     papoLayers_[nLayers_++] = poLayer;
     210                 : 
     211               6 :     if( NULL != fpOut_ )
     212                 :     {
     213               6 :         VSIFPrintf( fpOut_, "{\n\"type\": \"FeatureCollection\",\n\"features\": [\n" );
     214                 :     }
     215                 : 
     216               6 :     return poLayer;
     217                 : }
     218                 : 
     219                 : /************************************************************************/
     220                 : /*                           TestCapability()                           */
     221                 : /************************************************************************/
     222                 : 
     223               0 : int OGRGeoJSONDataSource::TestCapability( const char* pszCap )
     224                 : {
     225               0 :     if( EQUAL( pszCap, ODsCCreateLayer ) )
     226               0 :         return TRUE;
     227               0 :     else if( EQUAL( pszCap, ODsCDeleteLayer ) )
     228               0 :         return FALSE;
     229                 :     else
     230               0 :         return FALSE;
     231                 : }
     232                 : 
     233               6 : int OGRGeoJSONDataSource::Create( const char* pszName, char** papszOptions )
     234                 : {
     235                 :     UNREFERENCED_PARAM(papszOptions);
     236                 : 
     237                 :     CPLAssert( NULL == fpOut_ );
     238                 : 
     239                 : /* -------------------------------------------------------------------- */
     240                 : /*     File overwrite not supported.                                    */
     241                 : /* -------------------------------------------------------------------- */
     242                 :     VSIStatBufL sStatBuf;
     243               6 :     if( 0 == VSIStatL( pszName, &sStatBuf ) )
     244                 :     {
     245                 :         CPLError( CE_Failure, CPLE_NotSupported,
     246               0 :                   "The GeoJSON driver does not overwrite existing files." );
     247               0 :         return FALSE;
     248                 :     }
     249                 :     
     250                 : /* -------------------------------------------------------------------- */
     251                 : /*      Create the output file.                                         */
     252                 : /* -------------------------------------------------------------------- */
     253               6 :     if( EQUAL( pszName, "stdout" ) )
     254               0 :         fpOut_ = stdout;
     255                 :     else
     256               6 :         fpOut_ = VSIFOpen( pszName, "w" );
     257                 : 
     258               6 :     if( NULL == fpOut_)
     259                 :     {
     260                 :         CPLError( CE_Failure, CPLE_OpenFailed, 
     261                 :                   "Failed to create GeoJSON datasource: %s.", 
     262               0 :                   pszName );
     263               0 :         return FALSE;
     264                 :     }
     265                 : 
     266               6 :     pszName_ = CPLStrdup( pszName );
     267                 : 
     268               6 :     return TRUE;
     269                 : }
     270                 : 
     271                 : /************************************************************************/
     272                 : /*                           SetGeometryTranslation()                   */
     273                 : /************************************************************************/
     274                 : 
     275                 : void
     276             117 : OGRGeoJSONDataSource::SetGeometryTranslation( GeometryTranslation type )
     277                 : {
     278             117 :     flTransGeom_ = type;
     279             117 : }
     280                 : 
     281                 : /************************************************************************/
     282                 : /*                           SetAttributesTranslation()                 */
     283                 : /************************************************************************/
     284                 : 
     285             117 : void OGRGeoJSONDataSource::SetAttributesTranslation( AttributesTranslation type )
     286                 : {
     287             117 :     flTransAttrs_ = type;
     288             117 : }
     289                 : 
     290                 : /************************************************************************/
     291                 : /*                  PRIVATE FUNCTIONS IMPLEMENTATION                    */
     292                 : /************************************************************************/
     293                 : 
     294             226 : void OGRGeoJSONDataSource::Clear()
     295                 : {
     296             246 :     for( int i = 0; i < nLayers_; i++ )
     297                 :     {
     298                 :         CPLAssert( NULL != papoLayers_ );
     299              20 :         delete papoLayers_[i];
     300                 :     }
     301                 : 
     302             226 :     CPLFree( papoLayers_ );
     303             226 :     papoLayers_ = NULL;
     304             226 :     nLayers_ = 0;
     305                 : 
     306             226 :     CPLFree( pszName_ );
     307             226 :     pszName_ = NULL;
     308                 : 
     309             226 :     CPLFree( pszGeoData_ );
     310             226 :     pszGeoData_ = NULL;
     311                 : 
     312             226 :     if( NULL != fpOut_ && stdout != fpOut_ )
     313                 :     {
     314               6 :         VSIFClose( fpOut_ );
     315                 :     }
     316             226 :     fpOut_ = NULL;
     317             226 : }
     318                 : 
     319                 : /************************************************************************/
     320                 : /*                           ReadFromFile()                             */
     321                 : /************************************************************************/
     322                 : 
     323              14 : int OGRGeoJSONDataSource::ReadFromFile( const char* pszSource )
     324                 : {
     325                 :     CPLAssert( NULL == pszGeoData_ );
     326                 : 
     327              14 :     if( NULL == pszSource )
     328                 :     {
     329               0 :         CPLDebug( "GeoJSON", "Input file path is null" );
     330               0 :         return FALSE;
     331                 :     }
     332                 : 
     333              14 :     FILE* fp = NULL;
     334                 : 
     335              14 :     fp = VSIFOpen( pszSource, "rb" );
     336              14 :     if( NULL == fp )
     337               0 :         return FALSE;
     338                 : 
     339              14 :     size_t nDataLen = 0;
     340                 : 
     341              14 :     VSIFSeek( fp, 0, SEEK_END );
     342              14 :     nDataLen = VSIFTell( fp );
     343              14 :     VSIFSeek( fp, 0, SEEK_SET );
     344                 : 
     345              14 :     pszGeoData_ = (char*)CPLMalloc(nDataLen + 1);
     346              14 :     if( NULL == pszGeoData_ )
     347               0 :         return FALSE;
     348                 : 
     349              14 :     pszGeoData_[nDataLen] = '\0';
     350              14 :     if( ( nDataLen != VSIFRead( pszGeoData_, 1, nDataLen, fp ) ) )
     351                 :     {
     352               0 :         Clear();
     353               0 :         VSIFClose( fp );
     354               0 :         return FALSE;
     355                 :     }
     356              14 :     VSIFClose( fp );
     357                 : 
     358              14 :     pszName_ = CPLStrdup( pszSource );
     359                 : 
     360                 :     CPLAssert( NULL != pszGeoData_ );
     361              14 :     return TRUE;
     362                 : }
     363                 : 
     364                 : /************************************************************************/
     365                 : /*                           ReadFromService()                          */
     366                 : /************************************************************************/
     367                 : 
     368               0 : int OGRGeoJSONDataSource::ReadFromService( const char* pszSource )
     369                 : {
     370                 :     CPLAssert( NULL == pszGeoData_ );
     371                 :     CPLAssert( NULL != pszSource );
     372                 : 
     373               0 :     if( eGeoJSONProtocolUnknown == GeoJSONGetProtocolType( pszSource ) )
     374                 :     {
     375               0 :         CPLDebug( "GeoJSON", "Unknown service type (use HTTP, HTTPS, FTP)" );
     376               0 :         return FALSE;
     377                 :     }
     378                 : 
     379                 : /* -------------------------------------------------------------------- */
     380                 : /*      Fetch the GeoJSON result.                                        */
     381                 : /* -------------------------------------------------------------------- */
     382               0 :     CPLErrorReset();
     383                 : 
     384               0 :     CPLHTTPResult* pResult = NULL;
     385               0 :     char* papsOptions[] = { (char*) "HEADERS=Accept: text/plain Accept: application/json", NULL };
     386                 : 
     387               0 :     pResult = CPLHTTPFetch( pszSource, papsOptions );
     388                 : 
     389                 : /* -------------------------------------------------------------------- */
     390                 : /*      Try to handle CURL/HTTP errors.                                 */
     391                 : /* -------------------------------------------------------------------- */
     392               0 :     if( NULL == pResult
     393                 :         || 0 == pResult->nDataLen || 0 != CPLGetLastErrorNo() )
     394                 :     {
     395               0 :         CPLHTTPDestroyResult( pResult );
     396               0 :         return FALSE;
     397                 :     }
     398                 : 
     399               0 :    if( 0 != pResult->nStatus )
     400                 :     {
     401                 :         CPLError( CE_Failure, CPLE_AppDefined, 
     402                 :                   "Curl reports error: %d: %s",
     403               0 :                   pResult->nStatus, pResult->pszErrBuf );
     404               0 :         CPLHTTPDestroyResult( pResult );
     405               0 :         return FALSE;
     406                 :     }
     407                 : 
     408                 : /* -------------------------------------------------------------------- */
     409                 : /*      Copy returned GeoJSON data to text buffer.                      */
     410                 : /* -------------------------------------------------------------------- */
     411               0 :     const char* pszData = reinterpret_cast<char*>(pResult->pabyData);
     412                 : 
     413               0 :     if ( eGeoJSONProtocolUnknown != GeoJSONGetProtocolType( pszData ) )
     414                 :     {
     415                 :         CPLError( CE_Failure, CPLE_AppDefined, 
     416                 :             "The data that was downloaded also starts with "
     417                 :             "protocol prefix (http://, https:// or ftp://) "
     418               0 :             "and cannot be processed as GeoJSON data.");
     419               0 :         CPLHTTPDestroyResult( pResult );
     420               0 :         return FALSE;
     421                 :     }
     422                 : 
     423                 :     // TODO: Eventually, CPLHTTPResult::pabyData could be assigned
     424                 :     //       to pszGeoData_, so we will avoid copying of potentially (?) big data.
     425               0 :     pszGeoData_ = (char*)CPLMalloc( sizeof(char) * pResult->nDataLen + 1 );
     426                 :     CPLAssert( NULL != pszGeoData_ );
     427                 : 
     428               0 :     strncpy( pszGeoData_, pszData, pResult->nDataLen );
     429               0 :     pszGeoData_[pResult->nDataLen] = '\0';
     430                 : 
     431               0 :     pszName_ = CPLStrdup( pszSource );
     432                 : 
     433                 : /* -------------------------------------------------------------------- */
     434                 : /*      Cleanup HTTP resources.                                         */
     435                 : /* -------------------------------------------------------------------- */
     436               0 :     CPLHTTPDestroyResult( pResult );
     437                 : 
     438                 :     CPLAssert( NULL != pszGeoData_ );
     439               0 :     return TRUE;
     440                 : }
     441                 : 
     442                 : /************************************************************************/
     443                 : /*                           LoadLayer()                          */
     444                 : /************************************************************************/
     445                 : 
     446              14 : OGRGeoJSONLayer* OGRGeoJSONDataSource::LoadLayer()
     447                 : {
     448              14 :     if( NULL == pszGeoData_ )
     449                 :     {
     450                 :         CPLError( CE_Failure, CPLE_ObjectNull,
     451               0 :                   "GeoJSON data buffer empty" );
     452               0 :         return NULL;
     453                 :     }
     454                 : 
     455              14 :     OGRErr err = OGRERR_NONE;
     456              14 :     OGRGeoJSONLayer* poLayer = NULL;    
     457                 :     
     458                 : /* -------------------------------------------------------------------- */
     459                 : /*      Configure GeoJSON format translator.                            */
     460                 : /* -------------------------------------------------------------------- */
     461              14 :     OGRGeoJSONReader reader;
     462                 : 
     463              14 :     if( eGeometryAsCollection == flTransGeom_ )
     464                 :     {
     465               0 :         reader.SetPreserveGeometryType( false );
     466               0 :         CPLDebug( "GeoJSON", "Geometry as OGRGeometryCollection type." );
     467                 :     }
     468                 :     
     469              14 :     if( eAtributesSkip == flTransAttrs_ )
     470                 :     {
     471               0 :         reader.SetSkipAttributes( true );
     472               0 :         CPLDebug( "GeoJSON", "Skip all attributes." );
     473                 :     }
     474                 :     
     475                 : /* -------------------------------------------------------------------- */
     476                 : /*      Parse GeoJSON and build valid OGRLayer instance.                */
     477                 : /* -------------------------------------------------------------------- */
     478              14 :     err = reader.Parse( pszGeoData_ );
     479              14 :     if( OGRERR_NONE == err )
     480                 :     {
     481                 :         // TODO: Think about better name selection
     482              14 :         poLayer = reader.ReadLayer( OGRGeoJSONLayer::DefaultName, this );
     483                 :     }
     484                 : 
     485              14 :     return poLayer;
     486                 : }
     487                 : 

Generated by: LCOV version 1.7