1 : /******************************************************************************
2 : * $Id$
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 <ogr_api.h>
34 :
35 : /************************************************************************/
36 : /* OGRGeoJSONReader */
37 : /************************************************************************/
38 :
39 14 : OGRGeoJSONReader::OGRGeoJSONReader()
40 : : poGJObject_( NULL ), poLayer_( NULL ),
41 : bGeometryPreserve_( true ),
42 14 : bAttributesSkip_( false )
43 : {
44 : // Take a deep breath and get to work.
45 14 : }
46 :
47 : /************************************************************************/
48 : /* ~OGRGeoJSONReader */
49 : /************************************************************************/
50 :
51 14 : OGRGeoJSONReader::~OGRGeoJSONReader()
52 : {
53 14 : if( NULL != poGJObject_ )
54 : {
55 14 : json_object_put(poGJObject_);
56 : }
57 :
58 14 : poGJObject_ = NULL;
59 14 : poLayer_ = NULL;
60 14 : }
61 :
62 : /************************************************************************/
63 : /* Parse */
64 : /************************************************************************/
65 :
66 14 : OGRErr OGRGeoJSONReader::Parse( const char* pszText )
67 : {
68 14 : if( NULL != pszText )
69 : {
70 14 : json_tokener* jstok = NULL;
71 14 : json_object* jsobj = NULL;
72 :
73 14 : jstok = json_tokener_new();
74 14 : jsobj = json_tokener_parse_ex(jstok, pszText, -1);
75 14 : if( jstok->err != json_tokener_success)
76 : {
77 : CPLError( CE_Failure, CPLE_AppDefined,
78 : "GeoJSON parsing error: %s (at offset %d)",
79 0 : json_tokener_errors[jstok->err], jstok->char_offset);
80 :
81 0 : json_tokener_free(jstok);
82 0 : return OGRERR_CORRUPT_DATA;
83 : }
84 14 : json_tokener_free(jstok);
85 :
86 : /* JSON tree is shared for while lifetime of the reader object
87 : * and will be released in the destructor.
88 : */
89 14 : poGJObject_ = jsobj;
90 : }
91 :
92 14 : return OGRERR_NONE;
93 : }
94 :
95 : /************************************************************************/
96 : /* ReadLayer */
97 : /************************************************************************/
98 :
99 14 : OGRGeoJSONLayer* OGRGeoJSONReader::ReadLayer( const char* pszName,
100 : OGRGeoJSONDataSource* poDS )
101 : {
102 : CPLAssert( NULL == poLayer_ );
103 :
104 14 : if( NULL == poGJObject_ )
105 : {
106 : CPLDebug( "GeoJSON",
107 0 : "Missing parset GeoJSON data. Forgot to call Parse()?" );
108 0 : return NULL;
109 : }
110 :
111 : poLayer_ = new OGRGeoJSONLayer( pszName, NULL,
112 : OGRGeoJSONLayer::DefaultGeometryType,
113 14 : NULL, poDS );
114 :
115 14 : if( !GenerateLayerDefn() )
116 : {
117 : CPLError( CE_Failure, CPLE_AppDefined,
118 0 : "Layer schema generation failed." );
119 :
120 0 : delete poLayer_;
121 0 : return NULL;
122 : }
123 :
124 : /* -------------------------------------------------------------------- */
125 : /* Translate single geometry-only Feature object. */
126 : /* -------------------------------------------------------------------- */
127 14 : GeoJSONObject::Type objType = OGRGeoJSONGetType( poGJObject_ );
128 :
129 22 : if( GeoJSONObject::ePoint == objType
130 : || GeoJSONObject::eMultiPoint == objType
131 : || GeoJSONObject::eLineString == objType
132 : || GeoJSONObject::eMultiLineString == objType
133 : || GeoJSONObject::ePolygon == objType
134 : || GeoJSONObject::eMultiPolygon == objType
135 : || GeoJSONObject::eGeometryCollection == objType )
136 : {
137 8 : OGRGeometry* poGeometry = NULL;
138 8 : poGeometry = ReadGeometry( poGJObject_ );
139 8 : if( !AddFeature( poGeometry ) )
140 : {
141 : CPLDebug( "GeoJSON",
142 0 : "Translation of single geometry failed." );
143 0 : delete poLayer_;
144 0 : return NULL;
145 : }
146 : }
147 : /* -------------------------------------------------------------------- */
148 : /* Translate single but complete Feature object. */
149 : /* -------------------------------------------------------------------- */
150 6 : else if( GeoJSONObject::eFeature == objType )
151 : {
152 0 : OGRFeature* poFeature = NULL;
153 0 : poFeature = ReadFeature( poGJObject_ );
154 0 : if( !AddFeature( poFeature ) )
155 : {
156 : CPLDebug( "GeoJSON",
157 0 : "Translation of single feature failed." );
158 :
159 0 : delete poLayer_;
160 0 : return NULL;
161 : }
162 : }
163 : /* -------------------------------------------------------------------- */
164 : /* Translate multi-feature FeatureCollection object. */
165 : /* -------------------------------------------------------------------- */
166 6 : else if( GeoJSONObject::eFeatureCollection == objType )
167 : {
168 6 : OGRGeoJSONLayer* poThisLayer = NULL;
169 6 : poThisLayer = ReadFeatureCollection( poGJObject_ );
170 : CPLAssert( poLayer_ == poThisLayer );
171 : }
172 : else
173 : {
174 : CPLError( CE_Failure, CPLE_AppDefined,
175 0 : "Unrecognized GeoJSON structure." );
176 :
177 0 : delete poLayer_;
178 0 : return NULL;
179 : }
180 :
181 14 : OGRSpatialReference* poSRS = NULL;
182 14 : poSRS = OGRGeoJSONReadSpatialReference( poGJObject_ );
183 14 : if (poSRS == NULL ) {
184 : // If there is none defined, we use 4326
185 13 : poSRS = new OGRSpatialReference();
186 13 : if( OGRERR_NONE != poSRS->importFromEPSG( 4326 ) )
187 : {
188 0 : delete poSRS;
189 0 : poSRS = NULL;
190 : }
191 13 : poLayer_->SetSpatialRef( poSRS );
192 13 : delete poSRS;
193 : }
194 : else {
195 1 : poLayer_->SetSpatialRef( poSRS );
196 1 : delete poSRS;
197 : }
198 :
199 : // TODO: FeatureCollection
200 :
201 14 : return poLayer_;
202 : }
203 :
204 16 : OGRSpatialReference* OGRGeoJSONReadSpatialReference( json_object* poObj) {
205 :
206 : /* -------------------------------------------------------------------- */
207 : /* Read spatial reference definition. */
208 : /* -------------------------------------------------------------------- */
209 16 : OGRSpatialReference* poSRS = NULL;
210 :
211 16 : json_object* poObjSrs = OGRGeoJSONFindMemberByName( poObj, "crs" );
212 16 : if( NULL != poObjSrs )
213 : {
214 3 : json_object* poObjSrsType = OGRGeoJSONFindMemberByName( poObjSrs, "type" );
215 3 : const char* pszSrsType = json_object_get_string( poObjSrsType );
216 :
217 : // TODO: Add URL and URN types support
218 3 : if( EQUALN( pszSrsType, "NAME", 4 ) )
219 : {
220 3 : json_object* poObjSrsProps = OGRGeoJSONFindMemberByName( poObjSrs, "properties" );
221 : CPLAssert( NULL != poObjSrsProps );
222 :
223 3 : json_object* poNameURL = OGRGeoJSONFindMemberByName( poObjSrsProps, "name" );
224 : CPLAssert( NULL != poNameURL );
225 :
226 3 : const char* pszName = json_object_get_string( poNameURL );
227 :
228 3 : poSRS = new OGRSpatialReference();
229 3 : if( OGRERR_NONE != poSRS->SetFromUserInput( pszName ) )
230 : {
231 0 : delete poSRS;
232 0 : poSRS = NULL;
233 : }
234 : }
235 :
236 3 : if( EQUALN( pszSrsType, "EPSG", 4 ) )
237 : {
238 0 : json_object* poObjSrsProps = OGRGeoJSONFindMemberByName( poObjSrs, "properties" );
239 : CPLAssert( NULL != poObjSrsProps );
240 :
241 0 : json_object* poObjCode = OGRGeoJSONFindMemberByName( poObjSrsProps, "code" );
242 : CPLAssert( NULL != poObjCode );
243 :
244 0 : int nEPSG = json_object_get_int( poObjCode );
245 :
246 0 : poSRS = new OGRSpatialReference();
247 0 : if( OGRERR_NONE != poSRS->importFromEPSG( nEPSG ) )
248 : {
249 0 : delete poSRS;
250 0 : poSRS = NULL;
251 : }
252 : }
253 3 : if( EQUALN( pszSrsType, "URL", 3 ) || EQUALN( pszSrsType, "LINK", 4 ) )
254 : {
255 0 : json_object* poObjSrsProps = OGRGeoJSONFindMemberByName( poObjSrs, "properties" );
256 : CPLAssert( NULL != poObjSrsProps );
257 :
258 0 : json_object* poObjURL = OGRGeoJSONFindMemberByName( poObjSrsProps, "url" );
259 :
260 0 : if (NULL == poObjURL) {
261 0 : poObjURL = OGRGeoJSONFindMemberByName( poObjSrsProps, "href" );
262 : }
263 : CPLAssert( NULL != poObjURL );
264 :
265 0 : const char* pszURL = json_object_get_string( poObjURL );
266 :
267 0 : poSRS = new OGRSpatialReference();
268 0 : if( OGRERR_NONE != poSRS->importFromUrl( pszURL ) )
269 : {
270 0 : delete poSRS;
271 0 : poSRS = NULL;
272 :
273 : }
274 : }
275 : }
276 :
277 16 : return poSRS;
278 : }
279 : /************************************************************************/
280 : /* SetPreserveGeometryType */
281 : /************************************************************************/
282 :
283 0 : void OGRGeoJSONReader::SetPreserveGeometryType( bool bPreserve )
284 : {
285 0 : bGeometryPreserve_ = bPreserve;
286 0 : }
287 :
288 : /************************************************************************/
289 : /* SetSkipAttributes */
290 : /************************************************************************/
291 :
292 0 : void OGRGeoJSONReader::SetSkipAttributes( bool bSkip )
293 : {
294 0 : bAttributesSkip_ = bSkip;
295 0 : }
296 :
297 : /************************************************************************/
298 : /* GenerateFeatureDefn */
299 : /************************************************************************/
300 :
301 14 : bool OGRGeoJSONReader::GenerateLayerDefn()
302 : {
303 : CPLAssert( NULL != poGJObject_ );
304 : CPLAssert( NULL != poLayer_->GetLayerDefn() );
305 : CPLAssert( 0 == poLayer_->GetLayerDefn()->GetFieldCount() );
306 :
307 14 : bool bSuccess = true;
308 :
309 14 : if( bAttributesSkip_ )
310 0 : return true;
311 :
312 : /* -------------------------------------------------------------------- */
313 : /* Scan all features and generate layer definition. */
314 : /* -------------------------------------------------------------------- */
315 14 : GeoJSONObject::Type objType = OGRGeoJSONGetType( poGJObject_ );
316 14 : if( GeoJSONObject::eFeature == objType )
317 : {
318 0 : bSuccess = GenerateFeatureDefn( poGJObject_ );
319 : }
320 14 : else if( GeoJSONObject::eFeatureCollection == objType )
321 : {
322 6 : json_object* poObjFeatures = NULL;
323 6 : poObjFeatures = OGRGeoJSONFindMemberByName( poGJObject_, "features" );
324 6 : if( NULL != poObjFeatures
325 : && json_type_array == json_object_get_type( poObjFeatures ) )
326 : {
327 6 : json_object* poObjFeature = NULL;
328 6 : const int nFeatures = json_object_array_length( poObjFeatures );
329 12 : for( int i = 0; i < nFeatures; ++i )
330 : {
331 6 : poObjFeature = json_object_array_get_idx( poObjFeatures, i );
332 6 : if( !GenerateFeatureDefn( poObjFeature ) )
333 : {
334 0 : CPLDebug( "GeoJSON", "Create feature schema failure." );
335 0 : bSuccess = false;
336 : }
337 : }
338 : }
339 : else
340 : {
341 : CPLError( CE_Failure, CPLE_AppDefined,
342 : "Invalid FeatureCollection object. "
343 0 : "Missing \'features\' member." );
344 0 : bSuccess = false;
345 : }
346 : }
347 :
348 : /* -------------------------------------------------------------------- */
349 : /* Validate and add FID column if necessary. */
350 : /* -------------------------------------------------------------------- */
351 14 : OGRFeatureDefn* poLayerDefn = poLayer_->GetLayerDefn();
352 : CPLAssert( NULL != poLayerDefn );
353 :
354 14 : bool bHasFID = false;
355 :
356 26 : for( int i = 0; i < poLayerDefn->GetFieldCount(); ++i )
357 : {
358 12 : OGRFieldDefn* poDefn = poLayerDefn->GetFieldDefn(i);
359 12 : if( EQUAL( poDefn->GetNameRef(), OGRGeoJSONLayer::DefaultFIDColumn )
360 : && OFTInteger == poDefn->GetType() )
361 : {
362 0 : poLayer_->SetFIDColumn( poDefn->GetNameRef() );
363 0 : bHasFID = true;
364 0 : break;
365 : }
366 : }
367 :
368 : // TODO - mloskot: This is wrong! We want to add only FID field if
369 : // found in source layer (by default name or by FID_PROPERTY= specifier,
370 : // the latter has to be implemented).
371 : /*
372 : if( !bHasFID )
373 : {
374 : OGRFieldDefn fldDefn( OGRGeoJSONLayer::DefaultFIDColumn, OFTInteger );
375 : poLayerDefn->AddFieldDefn( &fldDefn );
376 : poLayer_->SetFIDColumn( fldDefn.GetNameRef() );
377 : }
378 : */
379 :
380 14 : return bSuccess;
381 : }
382 :
383 6 : bool OGRGeoJSONReader::GenerateFeatureDefn( json_object* poObj )
384 : {
385 6 : OGRFeatureDefn* poDefn = poLayer_->GetLayerDefn();
386 : CPLAssert( NULL != poDefn );
387 :
388 6 : bool bSuccess = false;
389 :
390 : /* -------------------------------------------------------------------- */
391 : /* Read collection of properties. */
392 : /* -------------------------------------------------------------------- */
393 6 : json_object* poObjProps = NULL;
394 6 : poObjProps = OGRGeoJSONFindMemberByName( poObj, "properties" );
395 6 : if( NULL != poObjProps )
396 : {
397 : json_object_iter it;
398 6 : it.key = NULL;
399 6 : it.val = NULL;
400 6 : it.entry = NULL;
401 18 : json_object_object_foreachC( poObjProps, it )
402 : {
403 12 : if( -1 == poDefn->GetFieldIndex( it.key ) )
404 : {
405 : OGRFieldDefn fldDefn( it.key,
406 12 : GeoJSONPropertyToFieldType( it.val ) );
407 12 : poDefn->AddFieldDefn( &fldDefn );
408 : }
409 : }
410 :
411 6 : bSuccess = true; // SUCCESS
412 : }
413 : else
414 : {
415 : CPLError( CE_Failure, CPLE_AppDefined,
416 : "Invalid Feature object. "
417 0 : "Missing \'properties\' member." );
418 : }
419 :
420 6 : return bSuccess;
421 : }
422 :
423 : /************************************************************************/
424 : /* AddFeature */
425 : /************************************************************************/
426 :
427 8 : bool OGRGeoJSONReader::AddFeature( OGRGeometry* poGeometry )
428 : {
429 8 : bool bAdded = false;
430 :
431 : // TODO: Should we check if geometry is of type of
432 : // wkbGeometryCollection ?
433 :
434 8 : if( NULL != poGeometry )
435 : {
436 8 : OGRFeature* poFeature = NULL;
437 8 : poFeature = new OGRFeature( poLayer_->GetLayerDefn() );
438 8 : poFeature->SetGeometryDirectly( poGeometry );
439 :
440 8 : bAdded = AddFeature( poFeature );
441 : }
442 :
443 8 : return bAdded;
444 : }
445 :
446 : /************************************************************************/
447 : /* AddFeature */
448 : /************************************************************************/
449 :
450 14 : bool OGRGeoJSONReader::AddFeature( OGRFeature* poFeature )
451 : {
452 14 : bool bAdded = false;
453 :
454 14 : if( NULL != poFeature )
455 : {
456 14 : poLayer_->AddFeature( poFeature );
457 14 : bAdded = true;
458 14 : delete poFeature;
459 : }
460 :
461 14 : return bAdded;
462 : }
463 :
464 : /************************************************************************/
465 : /* ReadGeometry */
466 : /************************************************************************/
467 :
468 14 : OGRGeometry* OGRGeoJSONReader::ReadGeometry( json_object* poObj )
469 : {
470 14 : OGRGeometry* poGeometry = NULL;
471 :
472 14 : poGeometry = OGRGeoJSONReadGeometry( poObj );
473 :
474 : /* -------------------------------------------------------------------- */
475 : /* Wrap geometry with GeometryCollection as a common denominator. */
476 : /* Sometimes a GeoJSON text may consist of objects of different */
477 : /* geometry types. Users may request wrapping all geometries with */
478 : /* OGRGeometryCollection type by using option */
479 : /* GEOMETRY_AS_COLLECTION=NO|YES (NO is default). */
480 : /* -------------------------------------------------------------------- */
481 14 : if( NULL != poGeometry )
482 : {
483 14 : if( !bGeometryPreserve_
484 0 : && wkbGeometryCollection != poGeometry->getGeometryType() )
485 : {
486 0 : OGRGeometryCollection* poMetaGeometry = NULL;
487 0 : poMetaGeometry = new OGRGeometryCollection();
488 0 : poMetaGeometry->addGeometryDirectly( poGeometry );
489 0 : return poMetaGeometry;
490 : }
491 : }
492 :
493 14 : return poGeometry;
494 : }
495 :
496 : /************************************************************************/
497 : /* ReadFeature() */
498 : /************************************************************************/
499 :
500 6 : OGRFeature* OGRGeoJSONReader::ReadFeature( json_object* poObj )
501 : {
502 : CPLAssert( NULL != poObj );
503 : CPLAssert( NULL != poLayer_ );
504 :
505 6 : OGRFeature* poFeature = NULL;
506 6 : poFeature = new OGRFeature( poLayer_->GetLayerDefn() );
507 :
508 : /* -------------------------------------------------------------------- */
509 : /* Translate GeoJSON "properties" object to feature attributes. */
510 : /* -------------------------------------------------------------------- */
511 : CPLAssert( NULL != poFeature );
512 :
513 6 : json_object* poObjProps = NULL;
514 6 : poObjProps = OGRGeoJSONFindMemberByName( poObj, "properties" );
515 12 : if( !bAttributesSkip_ && NULL != poObjProps )
516 : {
517 6 : int nField = -1;
518 6 : OGRFieldDefn* poFieldDefn = NULL;
519 : json_object_iter it;
520 6 : it.key = NULL;
521 6 : it.val = NULL;
522 6 : it.entry = NULL;
523 18 : json_object_object_foreachC( poObjProps, it )
524 : {
525 12 : nField = poFeature->GetFieldIndex(it.key);
526 12 : poFieldDefn = poFeature->GetFieldDefnRef(nField);
527 : CPLAssert( NULL != poFieldDefn );
528 :
529 : /* Unset FID. */
530 12 : poFeature->SetFID( -1 );
531 :
532 12 : if( OFTInteger == poFieldDefn->GetType() )
533 : {
534 0 : poFeature->SetField( nField, json_object_get_int(it.val) );
535 :
536 : /* Check if FID available and set correct value. */
537 0 : if( EQUAL( it.key, poLayer_->GetFIDColumn() ) )
538 0 : poFeature->SetFID( json_object_get_int(it.val) );
539 : }
540 12 : else if( OFTReal == poFieldDefn->GetType() )
541 : {
542 6 : poFeature->SetField( nField, json_object_get_double(it.val) );
543 : }
544 : else
545 : {
546 6 : poFeature->SetField( nField, json_object_get_string(it.val) );
547 : }
548 : }
549 : }
550 :
551 : /* -------------------------------------------------------------------- */
552 : /* If FID not set, try to use feature-level ID if available */
553 : /* and of integral type. Otherwise, leave unset (-1) then index */
554 : /* in features sequence will be used as FID. */
555 : /* -------------------------------------------------------------------- */
556 6 : if( -1 == poFeature->GetFID() )
557 : {
558 6 : json_object* poObjId = NULL;
559 6 : poObjId = OGRGeoJSONFindMemberByName( poObj, OGRGeoJSONLayer::DefaultFIDColumn );
560 6 : if( NULL != poObjId
561 0 : && EQUAL( OGRGeoJSONLayer::DefaultFIDColumn, poLayer_->GetFIDColumn() )
562 : && OFTInteger == GeoJSONPropertyToFieldType( poObjId ) )
563 : {
564 0 : poFeature->SetFID( json_object_get_int( poObjId ) );
565 0 : int nField = poFeature->GetFieldIndex( poLayer_->GetFIDColumn() );
566 0 : if( -1 != nField )
567 0 : poFeature->SetField( nField, (int) poFeature->GetFID() );
568 : }
569 : }
570 :
571 : /* -------------------------------------------------------------------- */
572 : /* Translate geometry sub-object of GeoJSON Feature. */
573 : /* -------------------------------------------------------------------- */
574 6 : json_object* poObjGeom = NULL;
575 :
576 6 : json_object* poTmp = poObj;
577 :
578 : json_object_iter it;
579 6 : it.key = NULL;
580 6 : it.val = NULL;
581 6 : it.entry = NULL;
582 24 : json_object_object_foreachC(poTmp, it)
583 : {
584 18 : if( EQUAL( it.key, "geometry" ) ) {
585 6 : if (it.val != NULL)
586 6 : poObjGeom = it.val;
587 : // we're done. They had 'geometry':null
588 : else
589 0 : return poFeature;
590 : }
591 : }
592 :
593 6 : if( NULL != poObjGeom )
594 : {
595 : // NOTE: If geometry can not be parsed or read correctly
596 : // then NULL geometry is assigned to a feature and
597 : // geometry type for layer is classified as wkbUnknown.
598 6 : OGRGeometry* poGeometry = ReadGeometry( poObjGeom );
599 6 : if( NULL != poGeometry )
600 : {
601 6 : poFeature->SetGeometryDirectly( poGeometry );
602 : }
603 : }
604 : else
605 : {
606 : CPLError( CE_Failure, CPLE_AppDefined,
607 : "Invalid Feature object. "
608 0 : "Missing \'geometry\' member." );
609 0 : return NULL;
610 : }
611 :
612 6 : return poFeature;
613 : }
614 :
615 : /************************************************************************/
616 : /* ReadFeatureCollection() */
617 : /************************************************************************/
618 :
619 : OGRGeoJSONLayer*
620 6 : OGRGeoJSONReader::ReadFeatureCollection( json_object* poObj )
621 : {
622 : CPLAssert( NULL != poLayer_ );
623 :
624 6 : json_object* poObjFeatures = NULL;
625 6 : poObjFeatures = OGRGeoJSONFindMemberByName( poObj, "features" );
626 6 : if( NULL == poObjFeatures )
627 : {
628 : CPLError( CE_Failure, CPLE_AppDefined,
629 : "Invalid FeatureCollection object. "
630 0 : "Missing \'features\' member." );
631 0 : return NULL;
632 : }
633 :
634 6 : if( json_type_array == json_object_get_type( poObjFeatures ) )
635 : {
636 6 : bool bAdded = false;
637 6 : OGRFeature* poFeature = NULL;
638 6 : json_object* poObjFeature = NULL;
639 :
640 6 : const int nFeatures = json_object_array_length( poObjFeatures );
641 12 : for( int i = 0; i < nFeatures; ++i )
642 : {
643 6 : poObjFeature = json_object_array_get_idx( poObjFeatures, i );
644 6 : poFeature = OGRGeoJSONReader::ReadFeature( poObjFeature );
645 6 : bAdded = AddFeature( poFeature );
646 : CPLAssert( bAdded );
647 : }
648 : CPLAssert( nFeatures == poLayer_->GetFeatureCount() );
649 : }
650 :
651 : // We're returning class member to follow the same pattern of
652 : // Read* functions call convention.
653 : CPLAssert( NULL != poLayer_ );
654 6 : return poLayer_;
655 : }
656 :
657 : /************************************************************************/
658 : /* OGRGeoJSONFindMemberByName */
659 : /************************************************************************/
660 :
661 137 : json_object* OGRGeoJSONFindMemberByName( json_object* poObj,
662 : const char* pszName )
663 : {
664 137 : if( NULL == pszName || NULL == poObj)
665 0 : return NULL;
666 :
667 137 : json_object* poTmp = poObj;
668 :
669 : json_object_iter it;
670 137 : it.key = NULL;
671 137 : it.val = NULL;
672 137 : it.entry = NULL;
673 137 : if( NULL != json_object_get_object(poTmp) )
674 : {
675 : CPLAssert( NULL != json_object_get_object(poTmp)->head );
676 :
677 268 : for( it.entry = json_object_get_object(poTmp)->head;
678 : ( it.entry ?
679 : ( it.key = (char*)it.entry->k,
680 : it.val = (json_object*)it.entry->v, it.entry) : 0);
681 : it.entry = it.entry->next)
682 : {
683 233 : if( EQUAL( it.key, pszName ) )
684 102 : return it.val;
685 : }
686 : }
687 :
688 35 : return NULL;
689 : }
690 :
691 : /************************************************************************/
692 : /* OGRGeoJSONGetType */
693 : /************************************************************************/
694 :
695 46 : GeoJSONObject::Type OGRGeoJSONGetType( json_object* poObj )
696 : {
697 46 : if( NULL == poObj )
698 0 : return GeoJSONObject::eUnknown;
699 :
700 46 : json_object* poObjType = NULL;
701 46 : poObjType = OGRGeoJSONFindMemberByName( poObj, "type" );
702 46 : if( NULL == poObjType )
703 0 : return GeoJSONObject::eUnknown;
704 :
705 46 : const char* name = json_object_get_string( poObjType );
706 46 : if( EQUAL( name, "Point" ) )
707 6 : return GeoJSONObject::ePoint;
708 40 : else if( EQUAL( name, "LineString" ) )
709 6 : return GeoJSONObject::eLineString;
710 34 : else if( EQUAL( name, "Polygon" ) )
711 4 : return GeoJSONObject::ePolygon;
712 30 : else if( EQUAL( name, "MultiPoint" ) )
713 4 : return GeoJSONObject::eMultiPoint;
714 26 : else if( EQUAL( name, "MultiLineString" ) )
715 4 : return GeoJSONObject::eMultiLineString;
716 22 : else if( EQUAL( name, "MultiPolygon" ) )
717 4 : return GeoJSONObject::eMultiPolygon;
718 18 : else if( EQUAL( name, "GeometryCollection" ) )
719 6 : return GeoJSONObject::eGeometryCollection;
720 12 : else if( EQUAL( name, "Feature" ) )
721 0 : return GeoJSONObject::eFeature;
722 12 : else if( EQUAL( name, "FeatureCollection" ) )
723 12 : return GeoJSONObject::eFeatureCollection;
724 : else
725 0 : return GeoJSONObject::eUnknown;
726 : }
727 :
728 : /************************************************************************/
729 : /* OGRGeoJSONReadGeometry */
730 : /************************************************************************/
731 :
732 18 : OGRGeometry* OGRGeoJSONReadGeometry( json_object* poObj )
733 : {
734 18 : OGRGeometry* poGeometry = NULL;
735 :
736 18 : GeoJSONObject::Type objType = OGRGeoJSONGetType( poObj );
737 18 : if( GeoJSONObject::ePoint == objType )
738 4 : poGeometry = OGRGeoJSONReadPoint( poObj );
739 14 : else if( GeoJSONObject::eMultiPoint == objType )
740 2 : poGeometry = OGRGeoJSONReadMultiPoint( poObj );
741 12 : else if( GeoJSONObject::eLineString == objType )
742 4 : poGeometry = OGRGeoJSONReadLineString( poObj );
743 8 : else if( GeoJSONObject::eMultiLineString == objType )
744 2 : poGeometry = OGRGeoJSONReadMultiLineString( poObj );
745 6 : else if( GeoJSONObject::ePolygon == objType )
746 2 : poGeometry = OGRGeoJSONReadPolygon( poObj );
747 4 : else if( GeoJSONObject::eMultiPolygon == objType )
748 2 : poGeometry = OGRGeoJSONReadMultiPolygon( poObj );
749 2 : else if( GeoJSONObject::eGeometryCollection == objType )
750 2 : poGeometry = OGRGeoJSONReadGeometryCollection( poObj );
751 : else
752 : {
753 : CPLDebug( "GeoJSON",
754 : "Unsupported geometry type detected. "
755 0 : "Feature gets NULL geometry assigned." );
756 : }
757 : // If we have a crs object in the current object, let's try and
758 : // set it too.
759 :
760 18 : json_object* poObjSrs = OGRGeoJSONFindMemberByName( poObj, "crs" );
761 18 : if (poObjSrs != NULL) {
762 2 : OGRSpatialReference* poSRS = OGRGeoJSONReadSpatialReference(poObj);
763 2 : if (poSRS != NULL) {
764 2 : poGeometry->assignSpatialReference(poSRS);
765 2 : poSRS->Release();
766 : }
767 : }
768 18 : return poGeometry;
769 : }
770 :
771 : /************************************************************************/
772 : /* OGRGeoJSONReadRawPoint */
773 : /************************************************************************/
774 :
775 64 : bool OGRGeoJSONReadRawPoint( json_object* poObj, OGRPoint& point )
776 : {
777 : CPLAssert( NULL != poObj );
778 :
779 64 : if( json_type_array == json_object_get_type( poObj ) )
780 : {
781 64 : const int nSize = json_object_array_length( poObj );
782 64 : int iType = 0;
783 :
784 64 : if( nSize != GeoJSONObject::eMinCoordinateDimension
785 : && nSize != GeoJSONObject::eMaxCoordinateDimension )
786 : {
787 : CPLDebug( "GeoJSON",
788 0 : "Invalid coord dimension. Only 2D and 3D supported." );
789 0 : return false;
790 : }
791 :
792 64 : json_object* poObjCoord = NULL;
793 :
794 : // Read X coordinate
795 64 : poObjCoord = json_object_array_get_idx( poObj, 0 );
796 :
797 64 : iType = json_object_get_type(poObjCoord);
798 64 : if ( (json_type_double != iType) && (json_type_int != iType) )
799 : {
800 : CPLError( CE_Failure, CPLE_AppDefined,
801 : "Invalid X coordinate. Type is not double or integer for \'%s\'.",
802 0 : json_object_to_json_string(poObj) );
803 0 : return false;
804 : }
805 :
806 64 : if (iType == json_type_double)
807 64 : point.setX(json_object_get_double( poObjCoord ));
808 : else
809 0 : point.setX(json_object_get_int( poObjCoord ));
810 :
811 : // Read Y coordiante
812 64 : poObjCoord = json_object_array_get_idx( poObj, 1 );
813 :
814 64 : iType = json_object_get_type(poObjCoord);
815 64 : if ( (json_type_double != iType) && (json_type_int != iType) )
816 : {
817 : CPLError( CE_Failure, CPLE_AppDefined,
818 : "Invalid Y coordinate. Type is not double or integer for \'%s\'.",
819 0 : json_object_to_json_string(poObj) );
820 0 : return false;
821 : }
822 :
823 64 : if (iType == json_type_double)
824 64 : point.setY(json_object_get_double( poObjCoord ));
825 : else
826 0 : point.setY(json_object_get_int( poObjCoord ));
827 :
828 : // Read Z coordinate
829 64 : if( nSize == GeoJSONObject::eMaxCoordinateDimension )
830 : {
831 : // Don't *expect* mixed-dimension geometries, although the
832 : // spec doesn't explicitly forbid this.
833 0 : poObjCoord = json_object_array_get_idx( poObj, 2 );
834 :
835 0 : iType = json_object_get_type(poObjCoord);
836 0 : if ( (json_type_double != iType) && (json_type_int != iType) )
837 : {
838 : CPLError( CE_Failure, CPLE_AppDefined,
839 : "Invalid Z coordinate. Type is not double or integer for \'%s\'.",
840 0 : json_object_to_json_string(poObj) );
841 0 : return false;
842 : }
843 :
844 0 : if (iType == json_type_double)
845 0 : point.setZ(json_object_get_double( poObjCoord ));
846 : else
847 0 : point.setZ(json_object_get_int( poObjCoord ));
848 : }
849 : else
850 : {
851 64 : point.flattenTo2D();
852 : }
853 64 : return true;
854 : }
855 :
856 0 : return false;
857 : }
858 :
859 : /************************************************************************/
860 : /* OGRGeoJSONReadPoint */
861 : /************************************************************************/
862 :
863 4 : OGRPoint* OGRGeoJSONReadPoint( json_object* poObj )
864 : {
865 : CPLAssert( NULL != poObj );
866 :
867 4 : OGRPoint* poPoint = new OGRPoint();
868 :
869 4 : json_object* poObjCoords = NULL;
870 4 : poObjCoords = OGRGeoJSONFindMemberByName( poObj, "coordinates" );
871 4 : if( NULL == poObjCoords )
872 : {
873 : CPLError( CE_Failure, CPLE_AppDefined,
874 0 : "Invalid Point object. Missing \'coordinates\' member." );
875 0 : return NULL;
876 : }
877 :
878 4 : if( !OGRGeoJSONReadRawPoint( poObjCoords, *poPoint ) )
879 : {
880 0 : CPLDebug( "GeoJSON", "Point: raw point parsing failure." );
881 0 : delete poPoint;
882 0 : return NULL;
883 : }
884 :
885 4 : return poPoint;
886 : }
887 :
888 : /************************************************************************/
889 : /* OGRGeoJSONReadMultiPoint */
890 : /************************************************************************/
891 :
892 2 : OGRMultiPoint* OGRGeoJSONReadMultiPoint( json_object* poObj )
893 : {
894 : CPLAssert( NULL != poObj );
895 :
896 2 : OGRMultiPoint* poMultiPoint = NULL;
897 :
898 2 : json_object* poObjPoints = NULL;
899 2 : poObjPoints = OGRGeoJSONFindMemberByName( poObj, "coordinates" );
900 2 : if( NULL == poObjPoints )
901 : {
902 : CPLError( CE_Failure, CPLE_AppDefined,
903 : "Invalid MultiPoint object. "
904 0 : "Missing \'coordinates\' member." );
905 0 : return NULL;
906 : }
907 :
908 2 : if( json_type_array == json_object_get_type( poObjPoints ) )
909 : {
910 2 : const int nPoints = json_object_array_length( poObjPoints );
911 :
912 2 : poMultiPoint = new OGRMultiPoint();
913 :
914 2 : for( int i = 0; i < nPoints; ++i)
915 : {
916 4 : json_object* poObjCoords = NULL;
917 4 : poObjCoords = json_object_array_get_idx( poObjPoints, i );
918 :
919 4 : OGRPoint pt;
920 4 : if( !OGRGeoJSONReadRawPoint( poObjCoords, pt ) )
921 : {
922 0 : delete poMultiPoint;
923 : CPLDebug( "GeoJSON",
924 0 : "LineString: raw point parsing failure." );
925 0 : return NULL;
926 : }
927 4 : poMultiPoint->addGeometry( &pt );
928 : }
929 : }
930 :
931 2 : return poMultiPoint;
932 : }
933 :
934 : /************************************************************************/
935 : /* OGRGeoJSONReadLineString */
936 : /************************************************************************/
937 :
938 8 : OGRLineString* OGRGeoJSONReadLineString( json_object* poObj , bool bRaw)
939 : {
940 : CPLAssert( NULL != poObj );
941 :
942 8 : OGRLineString* poLine = NULL;
943 8 : json_object* poObjPoints = NULL;
944 :
945 8 : if( !bRaw )
946 : {
947 4 : poObjPoints = OGRGeoJSONFindMemberByName( poObj, "coordinates" );
948 4 : if( NULL == poObjPoints )
949 : {
950 : CPLError( CE_Failure, CPLE_AppDefined,
951 : "Invalid LineString object. "
952 0 : "Missing \'coordinates\' member." );
953 0 : return NULL;
954 : }
955 : }
956 : else
957 : {
958 4 : poObjPoints = poObj;
959 : }
960 :
961 8 : if( json_type_array == json_object_get_type( poObjPoints ) )
962 : {
963 8 : const int nPoints = json_object_array_length( poObjPoints );
964 :
965 8 : poLine = new OGRLineString();
966 8 : poLine->setNumPoints( nPoints );
967 :
968 8 : for( int i = 0; i < nPoints; ++i)
969 : {
970 16 : json_object* poObjCoords = NULL;
971 16 : poObjCoords = json_object_array_get_idx( poObjPoints, i );
972 :
973 16 : OGRPoint pt;
974 16 : if( !OGRGeoJSONReadRawPoint( poObjCoords, pt ) )
975 : {
976 0 : delete poLine;
977 : CPLDebug( "GeoJSON",
978 0 : "LineString: raw point parsing failure." );
979 0 : return NULL;
980 : }
981 16 : if (pt.getCoordinateDimension() == 2) {
982 16 : poLine->setPoint( i, pt.getX(), pt.getY());
983 : } else {
984 0 : poLine->setPoint( i, pt.getX(), pt.getY(), pt.getZ() );
985 : }
986 :
987 : }
988 : }
989 :
990 8 : return poLine;
991 : }
992 :
993 : /************************************************************************/
994 : /* OGRGeoJSONReadMultiLineString */
995 : /************************************************************************/
996 :
997 2 : OGRMultiLineString* OGRGeoJSONReadMultiLineString( json_object* poObj )
998 : {
999 : CPLAssert( NULL != poObj );
1000 :
1001 2 : OGRMultiLineString* poMultiLine = NULL;
1002 :
1003 2 : json_object* poObjLines = NULL;
1004 2 : poObjLines = OGRGeoJSONFindMemberByName( poObj, "coordinates" );
1005 2 : if( NULL == poObjLines )
1006 : {
1007 : CPLError( CE_Failure, CPLE_AppDefined,
1008 : "Invalid MultiLineString object. "
1009 0 : "Missing \'coordinates\' member." );
1010 0 : return NULL;
1011 : }
1012 :
1013 2 : if( json_type_array == json_object_get_type( poObjLines ) )
1014 : {
1015 2 : const int nLines = json_object_array_length( poObjLines );
1016 :
1017 2 : poMultiLine = new OGRMultiLineString();
1018 :
1019 6 : for( int i = 0; i < nLines; ++i)
1020 : {
1021 4 : json_object* poObjLine = NULL;
1022 4 : poObjLine = json_object_array_get_idx( poObjLines, i );
1023 :
1024 4 : OGRLineString* poLine = OGRGeoJSONReadLineString( poObjLine , true );
1025 4 : if( NULL != poLine )
1026 : {
1027 4 : poMultiLine->addGeometryDirectly( poLine );
1028 : }
1029 : }
1030 : }
1031 :
1032 2 : return poMultiLine;
1033 : }
1034 :
1035 : /************************************************************************/
1036 : /* OGRGeoJSONReadLinearRing */
1037 : /************************************************************************/
1038 :
1039 8 : OGRLinearRing* OGRGeoJSONReadLinearRing( json_object* poObj )
1040 : {
1041 : CPLAssert( NULL != poObj );
1042 :
1043 8 : OGRLinearRing* poRing = NULL;
1044 :
1045 8 : if( json_type_array == json_object_get_type( poObj ) )
1046 : {
1047 8 : const int nPoints = json_object_array_length( poObj );
1048 :
1049 8 : poRing= new OGRLinearRing();
1050 8 : poRing->setNumPoints( nPoints );
1051 :
1052 8 : for( int i = 0; i < nPoints; ++i)
1053 : {
1054 40 : json_object* poObjCoords = NULL;
1055 40 : poObjCoords = json_object_array_get_idx( poObj, i );
1056 :
1057 40 : OGRPoint pt;
1058 40 : if( !OGRGeoJSONReadRawPoint( poObjCoords, pt ) )
1059 : {
1060 0 : delete poRing;
1061 : CPLDebug( "GeoJSON",
1062 0 : "LinearRing: raw point parsing failure." );
1063 0 : return NULL;
1064 : }
1065 :
1066 40 : if( 2 == pt.getCoordinateDimension() )
1067 40 : poRing->setPoint( i, pt.getX(), pt.getY());
1068 : else
1069 0 : poRing->setPoint( i, pt.getX(), pt.getY(), pt.getZ() );
1070 : }
1071 : }
1072 :
1073 8 : return poRing;
1074 : }
1075 :
1076 : /************************************************************************/
1077 : /* OGRGeoJSONReadPolygon */
1078 : /************************************************************************/
1079 :
1080 7 : OGRPolygon* OGRGeoJSONReadPolygon( json_object* poObj , bool bRaw )
1081 : {
1082 : CPLAssert( NULL != poObj );
1083 :
1084 7 : OGRPolygon* poPolygon = NULL;
1085 :
1086 7 : json_object* poObjRings = NULL;
1087 :
1088 7 : if( !bRaw )
1089 : {
1090 2 : poObjRings = OGRGeoJSONFindMemberByName( poObj, "coordinates" );
1091 2 : if( NULL == poObjRings )
1092 : {
1093 : CPLError( CE_Failure, CPLE_AppDefined,
1094 : "Invalid Polygon object. "
1095 0 : "Missing \'geometries\' member." );
1096 0 : return NULL;
1097 : }
1098 : }
1099 : else
1100 : {
1101 5 : poObjRings = poObj;
1102 : }
1103 :
1104 7 : if( json_type_array == json_object_get_type( poObjRings ) )
1105 : {
1106 7 : const int nRings = json_object_array_length( poObjRings );
1107 7 : if( nRings > 0 )
1108 : {
1109 7 : json_object* poObjPoints = NULL;
1110 7 : poObjPoints = json_object_array_get_idx( poObjRings, 0 );
1111 :
1112 7 : OGRLinearRing* poRing = OGRGeoJSONReadLinearRing( poObjPoints );
1113 7 : if( NULL != poRing )
1114 : {
1115 7 : poPolygon = new OGRPolygon();
1116 7 : poPolygon->addRingDirectly( poRing );
1117 : }
1118 :
1119 8 : for( int i = 1; i < nRings && NULL != poPolygon; ++i )
1120 : {
1121 1 : poObjPoints = json_object_array_get_idx( poObjRings, i );
1122 1 : OGRLinearRing* poRing = OGRGeoJSONReadLinearRing( poObjPoints );
1123 1 : if( NULL != poRing )
1124 : {
1125 1 : poPolygon->addRingDirectly( poRing );
1126 : }
1127 : }
1128 : }
1129 : }
1130 :
1131 7 : return poPolygon;
1132 : }
1133 :
1134 : /************************************************************************/
1135 : /* OGRGeoJSONReadMultiPolygon */
1136 : /************************************************************************/
1137 :
1138 2 : OGRMultiPolygon* OGRGeoJSONReadMultiPolygon( json_object* poObj )
1139 : {
1140 : CPLAssert( NULL != poObj );
1141 :
1142 2 : OGRMultiPolygon* poMultiPoly = NULL;
1143 :
1144 2 : json_object* poObjPolys = NULL;
1145 2 : poObjPolys = OGRGeoJSONFindMemberByName( poObj, "coordinates" );
1146 2 : if( NULL == poObjPolys )
1147 : {
1148 : CPLError( CE_Failure, CPLE_AppDefined,
1149 : "Invalid MultiPolygon object. "
1150 0 : "Missing \'coordinates\' member." );
1151 0 : return NULL;
1152 : }
1153 :
1154 2 : if( json_type_array == json_object_get_type( poObjPolys ) )
1155 : {
1156 2 : const int nPolys = json_object_array_length( poObjPolys );
1157 :
1158 2 : poMultiPoly = new OGRMultiPolygon();
1159 :
1160 7 : for( int i = 0; i < nPolys; ++i)
1161 : {
1162 :
1163 5 : json_object* poObjPoly = NULL;
1164 5 : poObjPoly = json_object_array_get_idx( poObjPolys, i );
1165 :
1166 5 : OGRPolygon* poPoly = OGRGeoJSONReadPolygon( poObjPoly , true );
1167 5 : if( NULL != poPoly )
1168 : {
1169 5 : poMultiPoly->addGeometryDirectly( poPoly );
1170 : }
1171 :
1172 : }
1173 : }
1174 :
1175 2 : return poMultiPoly;
1176 : }
1177 : /************************************************************************/
1178 : /* OGRGeoJSONReadGeometryCollection */
1179 : /************************************************************************/
1180 :
1181 2 : OGRGeometryCollection* OGRGeoJSONReadGeometryCollection( json_object* poObj )
1182 : {
1183 : CPLAssert( NULL != poObj );
1184 :
1185 2 : OGRGeometry* poGeometry = NULL;
1186 2 : OGRGeometryCollection* poCollection = NULL;
1187 :
1188 2 : json_object* poObjGeoms = NULL;
1189 2 : poObjGeoms = OGRGeoJSONFindMemberByName( poObj, "geometries" );
1190 2 : if( NULL == poObjGeoms )
1191 : {
1192 : CPLError( CE_Failure, CPLE_AppDefined,
1193 : "Invalid GeometryCollection object. "
1194 0 : "Missing \'geometries\' member." );
1195 0 : return NULL;
1196 : }
1197 :
1198 2 : if( json_type_array == json_object_get_type( poObjGeoms ) )
1199 : {
1200 2 : const int nGeoms = json_object_array_length( poObjGeoms );
1201 2 : if( nGeoms > 0 )
1202 : {
1203 2 : poCollection = new OGRGeometryCollection();
1204 : }
1205 :
1206 2 : json_object* poObjGeom = NULL;
1207 6 : for( int i = 0; i < nGeoms; ++i )
1208 : {
1209 4 : poObjGeom = json_object_array_get_idx( poObjGeoms, i );
1210 :
1211 4 : poGeometry = OGRGeoJSONReadGeometry( poObjGeom );
1212 4 : if( NULL != poGeometry )
1213 : {
1214 4 : poCollection->addGeometryDirectly( poGeometry );
1215 : }
1216 : }
1217 : }
1218 :
1219 2 : return poCollection;
1220 : }
1221 :
1222 : /************************************************************************/
1223 : /* OGR_G_ExportToJson */
1224 : /************************************************************************/
1225 :
1226 0 : OGRGeometryH OGR_G_CreateGeometryFromJson( const char* pszJson )
1227 : {
1228 0 : VALIDATE_POINTER1( pszJson, "OGR_G_CreateGeometryFromJson", NULL );
1229 :
1230 0 : if( NULL != pszJson )
1231 : {
1232 0 : json_tokener* jstok = NULL;
1233 0 : json_object* poObj = NULL;
1234 :
1235 0 : jstok = json_tokener_new();
1236 0 : poObj = json_tokener_parse_ex(jstok, pszJson, -1);
1237 0 : if( jstok->err != json_tokener_success)
1238 : {
1239 : CPLError( CE_Failure, CPLE_AppDefined,
1240 : "GeoJSON parsing error: %s (at offset %d)",
1241 0 : json_tokener_errors[jstok->err], jstok->char_offset);
1242 0 : json_tokener_free(jstok);
1243 0 : return NULL;
1244 : }
1245 0 : json_tokener_free(jstok);
1246 :
1247 0 : OGRGeometry* poGeometry = NULL;
1248 0 : poGeometry = OGRGeoJSONReadGeometry( poObj );
1249 :
1250 : /* Release JSON tree. */
1251 0 : json_object_put( poObj );
1252 :
1253 0 : return (OGRGeometryH)poGeometry;
1254 : }
1255 :
1256 : /* Translation failed */
1257 0 : return NULL;
1258 : }
1259 :
|