LTP GCOV extension - code coverage report
Current view: directory - ogr/ogrsf_frmts/geojson - ogrgeojsondatasource.cpp
Test: gdal_filtered.info
Date: 2010-07-12 Instrumented lines: 180
Code covered: 60.0 % Executed lines: 108

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

Generated by: LTP GCOV extension version 1.5