1 /******************************************************************************
2  * $Id: ogrtopojsonreader.cpp 28886 2015-04-12 23:09:13Z rouault $
3  *
4  * Project:  OpenGIS Simple Features Reference Implementation
5  * Purpose:  Implementation of OGRTopoJSONReader class
6  * Author:   Even Rouault, even dot rouault at mines dash paris dot org
7  *
8  ******************************************************************************
9  * Copyright (c) 2013, Even Rouault <even dot rouault at mines-paris dot org>
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 
30 #include "ogrgeojsonreader.h"
31 #include "ogrgeojsonutils.h"
32 #include "ogr_geojson.h"
33 #include <json.h> // JSON-C
34 #include <ogr_api.h>
35 
36 /************************************************************************/
37 /*                          OGRTopoJSONReader()                         */
38 /************************************************************************/
39 
OGRTopoJSONReader()40 OGRTopoJSONReader::OGRTopoJSONReader()
41     : poGJObject_( NULL )
42 {
43     // Take a deep breath and get to work.
44 }
45 
46 /************************************************************************/
47 /*                         ~OGRTopoJSONReader()                         */
48 /************************************************************************/
49 
~OGRTopoJSONReader()50 OGRTopoJSONReader::~OGRTopoJSONReader()
51 {
52     if( NULL != poGJObject_ )
53     {
54         json_object_put(poGJObject_);
55     }
56 
57     poGJObject_ = NULL;
58 }
59 
60 /************************************************************************/
61 /*                           Parse()                                    */
62 /************************************************************************/
63 
Parse(const char * pszText)64 OGRErr OGRTopoJSONReader::Parse( const char* pszText )
65 {
66     if( NULL != pszText )
67     {
68         json_tokener* jstok = NULL;
69         json_object* jsobj = NULL;
70 
71         jstok = json_tokener_new();
72         jsobj = json_tokener_parse_ex(jstok, pszText, -1);
73         if( jstok->err != json_tokener_success)
74         {
75             CPLError( CE_Failure, CPLE_AppDefined,
76                       "TopoJSON parsing error: %s (at offset %d)",
77             	      json_tokener_error_desc(jstok->err), jstok->char_offset);
78 
79             json_tokener_free(jstok);
80             return OGRERR_CORRUPT_DATA;
81         }
82         json_tokener_free(jstok);
83 
84         /* JSON tree is shared for while lifetime of the reader object
85          * and will be released in the destructor.
86          */
87         poGJObject_ = jsobj;
88     }
89 
90     return OGRERR_NONE;
91 }
92 
93 typedef struct
94 {
95     double dfScale0, dfScale1;
96     double dfTranslate0, dfTranslate1;
97 } ScalingParams;
98 
99 /************************************************************************/
100 /*                            ParsePoint()                              */
101 /************************************************************************/
102 
ParsePoint(json_object * poPoint,double * pdfX,double * pdfY)103 static int ParsePoint(json_object* poPoint, double* pdfX, double* pdfY)
104 {
105     if( poPoint != NULL && json_type_array == json_object_get_type(poPoint) &&
106         json_object_array_length(poPoint) == 2 )
107     {
108         json_object* poX = json_object_array_get_idx(poPoint, 0);
109         json_object* poY = json_object_array_get_idx(poPoint, 1);
110         if( poX != NULL &&
111             (json_type_int == json_object_get_type(poX) ||
112                 json_type_double == json_object_get_type(poX)) &&
113             poY != NULL &&
114             (json_type_int == json_object_get_type(poY) ||
115                 json_type_double == json_object_get_type(poY)) )
116         {
117             *pdfX = json_object_get_double(poX);
118             *pdfY = json_object_get_double(poY);
119             return TRUE;
120         }
121     }
122     return FALSE;
123 }
124 
125 /************************************************************************/
126 /*                             ParseArc()                               */
127 /************************************************************************/
128 
ParseArc(OGRLineString * poLS,json_object * poArcsDB,int nArcID,int bReverse,ScalingParams * psParams)129 static void ParseArc(OGRLineString* poLS, json_object* poArcsDB, int nArcID,
130                      int bReverse, ScalingParams* psParams)
131 {
132     json_object* poArcDB = json_object_array_get_idx(poArcsDB, nArcID);
133     if( poArcDB == NULL || json_type_array != json_object_get_type(poArcDB) )
134         return;
135     int nPoints = json_object_array_length(poArcDB);
136     double dfAccX = 0, dfAccY = 0;
137     int nBaseIndice = poLS->getNumPoints();
138     for(int i=0; i<nPoints; i++)
139     {
140         json_object* poPoint = json_object_array_get_idx(poArcDB, i);
141         double dfX = 0.0, dfY = 0.0;
142         if( ParsePoint( poPoint, &dfX, &dfY ) )
143         {
144             dfAccX += dfX;
145             dfAccY += dfY;
146             double dfX = dfAccX * psParams->dfScale0 + psParams->dfTranslate0;
147             double dfY = dfAccY * psParams->dfScale1 + psParams->dfTranslate1;
148             if( i == 0 )
149             {
150                 if( !bReverse && poLS->getNumPoints() > 0 )
151                 {
152                     poLS->setNumPoints( nBaseIndice + nPoints - 1 );
153                     nBaseIndice --;
154                     continue;
155                 }
156                 else if( bReverse && poLS->getNumPoints() > 0 )
157                 {
158                     poLS->setNumPoints( nBaseIndice + nPoints - 1 );
159                     nPoints --;
160                     if( nPoints == 0 )
161                         break;
162                 }
163                 else
164                     poLS->setNumPoints( nBaseIndice + nPoints );
165             }
166 
167             if( !bReverse )
168                 poLS->setPoint(nBaseIndice + i, dfX, dfY);
169             else
170                 poLS->setPoint(nBaseIndice + nPoints - 1 - i, dfX, dfY);
171         }
172     }
173 }
174 
175 /************************************************************************/
176 /*                        ParseLineString()                             */
177 /************************************************************************/
178 
ParseLineString(OGRLineString * poLS,json_object * poRing,json_object * poArcsDB,ScalingParams * psParams)179 static void ParseLineString(OGRLineString* poLS, json_object* poRing,
180                             json_object* poArcsDB, ScalingParams* psParams)
181 {
182     int nArcsDB = json_object_array_length(poArcsDB);
183 
184     int nArcsRing = json_object_array_length(poRing);
185     for(int j=0; j<nArcsRing; j++)
186     {
187         json_object* poArcId = json_object_array_get_idx(poRing, j);
188         if( poArcId != NULL && json_type_int == json_object_get_type(poArcId) )
189         {
190             int nArcId = json_object_get_int(poArcId);
191             int bReverse = FALSE;
192             if( nArcId < 0 )
193             {
194                 nArcId = - nArcId - 1;
195                 bReverse = TRUE;
196             }
197             if( nArcId < nArcsDB )
198             {
199                 ParseArc(poLS, poArcsDB, nArcId, bReverse, psParams);
200             }
201         }
202     }
203 }
204 
205 /************************************************************************/
206 /*                          ParsePolygon()                              */
207 /************************************************************************/
208 
ParsePolygon(OGRPolygon * poPoly,json_object * poArcsObj,json_object * poArcsDB,ScalingParams * psParams)209 static void ParsePolygon(OGRPolygon* poPoly, json_object* poArcsObj,
210                          json_object* poArcsDB, ScalingParams* psParams)
211 {
212     int nRings = json_object_array_length(poArcsObj);
213     for(int i=0; i<nRings; i++)
214     {
215         OGRLinearRing* poLR = new OGRLinearRing();
216         poPoly->addRingDirectly(poLR);
217 
218         json_object* poRing = json_object_array_get_idx(poArcsObj, i);
219         if( poRing != NULL && json_type_array == json_object_get_type(poRing) )
220         {
221             ParseLineString(poLR, poRing, poArcsDB, psParams);
222         }
223     }
224 }
225 
226 /************************************************************************/
227 /*                       ParseMultiLineString()                         */
228 /************************************************************************/
229 
ParseMultiLineString(OGRMultiLineString * poMLS,json_object * poArcsObj,json_object * poArcsDB,ScalingParams * psParams)230 static void ParseMultiLineString(OGRMultiLineString* poMLS, json_object* poArcsObj,
231                                  json_object* poArcsDB, ScalingParams* psParams)
232 {
233     int nRings = json_object_array_length(poArcsObj);
234     for(int i=0; i<nRings; i++)
235     {
236         OGRLineString* poLS = new OGRLineString();
237         poMLS->addGeometryDirectly(poLS);
238 
239         json_object* poRing = json_object_array_get_idx(poArcsObj, i);
240         if( poRing != NULL && json_type_array == json_object_get_type(poRing) )
241         {
242             ParseLineString(poLS, poRing, poArcsDB, psParams);
243         }
244     }
245 }
246 
247 /************************************************************************/
248 /*                       ParseMultiPolygon()                            */
249 /************************************************************************/
250 
ParseMultiPolygon(OGRMultiPolygon * poMultiPoly,json_object * poArcsObj,json_object * poArcsDB,ScalingParams * psParams)251 static void ParseMultiPolygon(OGRMultiPolygon* poMultiPoly, json_object* poArcsObj,
252                          json_object* poArcsDB, ScalingParams* psParams)
253 {
254     int nPolys = json_object_array_length(poArcsObj);
255     for(int i=0; i<nPolys; i++)
256     {
257         OGRPolygon* poPoly = new OGRPolygon();
258         poMultiPoly->addGeometryDirectly(poPoly);
259 
260         json_object* poPolyArcs = json_object_array_get_idx(poArcsObj, i);
261         if( poPolyArcs != NULL && json_type_array == json_object_get_type(poPolyArcs) )
262         {
263             ParsePolygon(poPoly, poPolyArcs, poArcsDB, psParams);
264         }
265     }
266 }
267 
268 /************************************************************************/
269 /*                          ParseObject()                               */
270 /************************************************************************/
271 
ParseObject(const char * pszId,json_object * poObj,OGRGeoJSONLayer * poLayer,json_object * poArcsDB,ScalingParams * psParams)272 static void ParseObject(const char* pszId,
273                         json_object* poObj, OGRGeoJSONLayer* poLayer,
274                         json_object* poArcsDB, ScalingParams* psParams)
275 {
276     json_object* poType = OGRGeoJSONFindMemberByName(poObj, "type");
277     if( poType == NULL || json_object_get_type(poType) != json_type_string )
278         return;
279     const char* pszType = json_object_get_string(poType);
280 
281     json_object* poArcsObj = OGRGeoJSONFindMemberByName(poObj, "arcs");
282     json_object* poCoordinatesObj = OGRGeoJSONFindMemberByName(poObj, "coordinates");
283     if( strcmp(pszType, "Point") == 0 || strcmp(pszType, "MultiPoint") == 0 )
284     {
285         if( poCoordinatesObj == NULL || json_type_array != json_object_get_type(poCoordinatesObj) )
286             return;
287     }
288     else
289     {
290         if( poArcsObj == NULL || json_type_array != json_object_get_type(poArcsObj) )
291             return;
292     }
293 
294     if( pszId == NULL )
295     {
296         json_object* poId = OGRGeoJSONFindMemberByName(poObj, "id");
297         if( poId != NULL &&
298             (json_type_string == json_object_get_type(poId) ||
299              json_type_int == json_object_get_type(poId)) )
300         {
301             pszId = json_object_get_string(poId);
302         }
303     }
304 
305     OGRFeature* poFeature = new OGRFeature(poLayer->GetLayerDefn());
306     if( pszId != NULL )
307         poFeature->SetField("id", pszId);
308 
309     json_object* poProperties = OGRGeoJSONFindMemberByName(poObj, "properties");
310     if( poProperties != NULL && json_type_object == json_object_get_type(poProperties) )
311     {
312         int nField = -1;
313         json_object_iter it;
314         it.key = NULL;
315         it.val = NULL;
316         it.entry = NULL;
317         json_object_object_foreachC( poProperties, it )
318         {
319             nField = poFeature->GetFieldIndex(it.key);
320             OGRGeoJSONReaderSetField(poLayer, poFeature, nField, it.key, it.val, FALSE, 0);
321         }
322     }
323 
324     OGRGeometry* poGeom = NULL;
325     if( strcmp(pszType, "Point") == 0 )
326     {
327         double dfX = 0.0, dfY = 0.0;
328         if( ParsePoint( poCoordinatesObj, &dfX, &dfY ) )
329         {
330             dfX = dfX * psParams->dfScale0 + psParams->dfTranslate0;
331             dfY = dfY * psParams->dfScale1 + psParams->dfTranslate1;
332             poGeom = new OGRPoint(dfX, dfY);
333         }
334         else
335             poGeom = new OGRPoint();
336     }
337     else if( strcmp(pszType, "MultiPoint") == 0 )
338     {
339         OGRMultiPoint* poMP = new OGRMultiPoint();
340         poGeom = poMP;
341         int nTuples = json_object_array_length(poCoordinatesObj);
342         for(int i=0; i<nTuples; i++)
343         {
344             json_object* poPair = json_object_array_get_idx(poCoordinatesObj, i);
345             double dfX = 0.0, dfY = 0.0;
346             if( ParsePoint( poPair, &dfX, &dfY ) )
347             {
348                 dfX = dfX * psParams->dfScale0 + psParams->dfTranslate0;
349                 dfY = dfY * psParams->dfScale1 + psParams->dfTranslate1;
350                 poMP->addGeometryDirectly(new OGRPoint(dfX, dfY));
351             }
352         }
353     }
354     else if( strcmp(pszType, "LineString") == 0 )
355     {
356         OGRLineString* poLS = new OGRLineString();
357         poGeom = poLS;
358         ParseLineString(poLS, poArcsObj, poArcsDB, psParams);
359     }
360     else if( strcmp(pszType, "MultiLineString") == 0 )
361     {
362         OGRMultiLineString* poMLS = new OGRMultiLineString();
363         poGeom = poMLS;
364         ParseMultiLineString(poMLS, poArcsObj, poArcsDB, psParams);
365     }
366     else if( strcmp(pszType, "Polygon") == 0 )
367     {
368         OGRPolygon* poPoly = new OGRPolygon();
369         poGeom = poPoly;
370         ParsePolygon(poPoly, poArcsObj, poArcsDB, psParams);
371     }
372     else if( strcmp(pszType, "MultiPolygon") == 0 )
373     {
374         OGRMultiPolygon* poMultiPoly = new OGRMultiPolygon();
375         poGeom = poMultiPoly;
376         ParseMultiPolygon(poMultiPoly, poArcsObj, poArcsDB, psParams);
377     }
378 
379     if( poGeom != NULL )
380         poFeature->SetGeometryDirectly(poGeom);
381     poLayer->AddFeature(poFeature);
382     delete poFeature;
383 }
384 
385 
386 /************************************************************************/
387 /*                        EstablishLayerDefn()                          */
388 /************************************************************************/
389 
EstablishLayerDefn(OGRFeatureDefn * poDefn,json_object * poObj)390 static void EstablishLayerDefn(OGRFeatureDefn* poDefn,
391                                json_object* poObj)
392 {
393     json_object* poObjProps = OGRGeoJSONFindMemberByName( poObj, "properties" );
394     if( NULL != poObjProps &&
395         json_object_get_type(poObjProps) == json_type_object )
396     {
397         json_object_iter it;
398         it.key = NULL;
399         it.val = NULL;
400         it.entry = NULL;
401         json_object_object_foreachC( poObjProps, it )
402         {
403             OGRGeoJSONReaderAddOrUpdateField(poDefn, it.key, it.val, FALSE, 0);
404         }
405     }
406 }
407 
408 /************************************************************************/
409 /*                        ParseObjectMain()                             */
410 /************************************************************************/
411 
ParseObjectMain(const char * pszId,json_object * poObj,OGRGeoJSONDataSource * poDS,OGRGeoJSONLayer ** ppoMainLayer,json_object * poArcs,ScalingParams * psParams,int nPassNumber)412 static int  ParseObjectMain(const char* pszId, json_object* poObj,
413                             OGRGeoJSONDataSource* poDS,
414                             OGRGeoJSONLayer **ppoMainLayer,
415                             json_object* poArcs,
416                             ScalingParams* psParams,
417                             int nPassNumber)
418 {
419     int bNeedSecondPass = FALSE;
420 
421     if( poObj != NULL && json_type_object == json_object_get_type( poObj ) )
422     {
423         json_object* poType = OGRGeoJSONFindMemberByName(poObj, "type");
424         if( poType != NULL && json_type_string == json_object_get_type( poType ) )
425         {
426             const char* pszType = json_object_get_string(poType);
427             if( nPassNumber == 1 && strcmp(pszType, "GeometryCollection") == 0 )
428             {
429                 json_object* poGeometries = OGRGeoJSONFindMemberByName(poObj, "geometries");
430                 if( poGeometries != NULL &&
431                     json_type_array == json_object_get_type( poGeometries ) )
432                 {
433                     if( pszId == NULL )
434                     {
435                         json_object* poId = OGRGeoJSONFindMemberByName(poObj, "id");
436                         if( poId != NULL &&
437                             (json_type_string == json_object_get_type(poId) ||
438                             json_type_int == json_object_get_type(poId)) )
439                         {
440                             pszId = json_object_get_string(poId);
441                         }
442                     }
443 
444                     OGRGeoJSONLayer* poLayer = new OGRGeoJSONLayer(
445                             pszId ? pszId : "TopoJSON", NULL,
446                             wkbUnknown, poDS );
447                     OGRFeatureDefn* poDefn = poLayer->GetLayerDefn();
448                     {
449                         OGRFieldDefn fldDefn( "id", OFTString );
450                         poDefn->AddFieldDefn( &fldDefn );
451                     }
452 
453                     int nGeometries = json_object_array_length(poGeometries);
454                     /* First pass to establish schema */
455                     for(int i=0; i<nGeometries; i++)
456                     {
457                         json_object* poGeom =
458                             json_object_array_get_idx(poGeometries, i);
459                         if( poGeom != NULL &&
460                             json_type_object == json_object_get_type( poGeom ) )
461                         {
462                             EstablishLayerDefn(poDefn, poGeom);
463                         }
464                     }
465 
466                     /* Second pass to build objects */
467                     for(int i=0; i<nGeometries; i++)
468                     {
469                         json_object* poGeom =
470                             json_object_array_get_idx(poGeometries, i);
471                         if( poGeom != NULL &&
472                             json_type_object == json_object_get_type( poGeom ) )
473                         {
474                             ParseObject(NULL, poGeom, poLayer, poArcs, psParams);
475                         }
476                     }
477 
478                     poDS->AddLayer(poLayer);
479                 }
480             }
481             else if( strcmp(pszType, "Point") == 0 ||
482                      strcmp(pszType, "MultiPoint") == 0 ||
483                      strcmp(pszType, "LineString") == 0 ||
484                      strcmp(pszType, "MultiLineString") == 0 ||
485                      strcmp(pszType, "Polygon") == 0 ||
486                      strcmp(pszType, "MultiPolygon") == 0 )
487             {
488                 if( nPassNumber == 1 )
489                 {
490                     if( *ppoMainLayer == NULL )
491                     {
492                         *ppoMainLayer = new OGRGeoJSONLayer(
493                             "TopoJSON", NULL, wkbUnknown, poDS );
494                         {
495                             OGRFieldDefn fldDefn( "id", OFTString );
496                             (*ppoMainLayer)->GetLayerDefn()->AddFieldDefn( &fldDefn );
497                         }
498                     }
499                     OGRFeatureDefn* poDefn = (*ppoMainLayer)->GetLayerDefn();
500                     EstablishLayerDefn(poDefn, poObj);
501                     bNeedSecondPass = TRUE;
502                 }
503                 else
504                     ParseObject(pszId, poObj, *ppoMainLayer, poArcs, psParams);
505             }
506         }
507     }
508     return bNeedSecondPass;
509 }
510 
511 /************************************************************************/
512 /*                           ReadLayers()                               */
513 /************************************************************************/
514 
ReadLayers(OGRGeoJSONDataSource * poDS)515 void OGRTopoJSONReader::ReadLayers( OGRGeoJSONDataSource* poDS )
516 {
517     if( NULL == poGJObject_ )
518     {
519         CPLDebug( "TopoJSON",
520                   "Missing parset TopoJSON data. Forgot to call Parse()?" );
521         return;
522     }
523 
524     ScalingParams sParams;
525     sParams.dfScale0 = 1.0;
526     sParams.dfScale1 = 1.0;
527     sParams.dfTranslate0 = 0.0;
528     sParams.dfTranslate1 = 0.0;
529     json_object* poObjTransform = OGRGeoJSONFindMemberByName( poGJObject_, "transform" );
530     if( NULL != poObjTransform && json_type_object == json_object_get_type( poObjTransform ) )
531     {
532         json_object* poObjScale = OGRGeoJSONFindMemberByName( poObjTransform, "scale" );
533         if( NULL != poObjScale && json_type_array == json_object_get_type( poObjScale ) &&
534             json_object_array_length( poObjScale ) == 2 )
535         {
536             json_object* poScale0 = json_object_array_get_idx(poObjScale, 0);
537             json_object* poScale1 = json_object_array_get_idx(poObjScale, 1);
538             if( poScale0 != NULL &&
539                 (json_object_get_type(poScale0) == json_type_double ||
540                  json_object_get_type(poScale0) == json_type_int) &&
541                 poScale1 != NULL &&
542                 (json_object_get_type(poScale1) == json_type_double ||
543                  json_object_get_type(poScale1) == json_type_int) )
544             {
545                 sParams.dfScale0 = json_object_get_double(poScale0);
546                 sParams.dfScale1 = json_object_get_double(poScale1);
547             }
548         }
549 
550         json_object* poObjTranslate = OGRGeoJSONFindMemberByName( poObjTransform, "translate" );
551         if( NULL != poObjTranslate && json_type_array == json_object_get_type( poObjTranslate ) &&
552             json_object_array_length( poObjTranslate ) == 2 )
553         {
554             json_object* poTranslate0 = json_object_array_get_idx(poObjTranslate, 0);
555             json_object* poTranslate1 = json_object_array_get_idx(poObjTranslate, 1);
556             if( poTranslate0 != NULL &&
557                 (json_object_get_type(poTranslate0) == json_type_double ||
558                  json_object_get_type(poTranslate0) == json_type_int) &&
559                 poTranslate1 != NULL &&
560                 (json_object_get_type(poTranslate1) == json_type_double ||
561                  json_object_get_type(poTranslate1) == json_type_int) )
562             {
563                 sParams.dfTranslate0 = json_object_get_double(poTranslate0);
564                 sParams.dfTranslate1 = json_object_get_double(poTranslate1);
565             }
566         }
567     }
568 
569     json_object* poArcs = OGRGeoJSONFindMemberByName( poGJObject_, "arcs" );
570     if( poArcs == NULL || json_type_array != json_object_get_type( poArcs ) )
571         return;
572 
573     OGRGeoJSONLayer* poMainLayer = NULL;
574 
575     json_object* poObjects = OGRGeoJSONFindMemberByName( poGJObject_, "objects" );
576     if( poObjects == NULL )
577         return;
578 
579     if( json_type_object == json_object_get_type( poObjects ) )
580     {
581         json_object_iter it;
582         it.key = NULL;
583         it.val = NULL;
584         it.entry = NULL;
585         int bNeedSecondPass = FALSE;
586         json_object_object_foreachC( poObjects, it )
587         {
588             json_object* poObj = it.val;
589             bNeedSecondPass |= ParseObjectMain(it.key, poObj, poDS, &poMainLayer, poArcs, &sParams, 1);
590         }
591         if( bNeedSecondPass )
592         {
593             it.key = NULL;
594             it.val = NULL;
595             it.entry = NULL;
596             json_object_object_foreachC( poObjects, it )
597             {
598                 json_object* poObj = it.val;
599                 ParseObjectMain(it.key, poObj, poDS, &poMainLayer, poArcs, &sParams, 2);
600             }
601         }
602     }
603     else if( json_type_array == json_object_get_type( poObjects ) )
604     {
605         int nObjects = json_object_array_length(poObjects);
606         int bNeedSecondPass = FALSE;
607         for(int i=0; i<nObjects; i++)
608         {
609             json_object* poObj = json_object_array_get_idx(poObjects, i);
610             bNeedSecondPass |= ParseObjectMain(NULL, poObj, poDS, &poMainLayer, poArcs, &sParams, 1);
611         }
612         if( bNeedSecondPass )
613         {
614             for(int i=0; i<nObjects; i++)
615             {
616                 json_object* poObj = json_object_array_get_idx(poObjects, i);
617                 ParseObjectMain(NULL, poObj, poDS, &poMainLayer, poArcs, &sParams, 2);
618             }
619         }
620     }
621 
622     if( poMainLayer != NULL )
623         poDS->AddLayer(poMainLayer);
624 
625 }
626