[postgis-tickets] r17672 - ST_GeomFromGeoJSON crash on empty rings

Darafei komzpa at gmail.com
Sun Aug 4 12:45:16 PDT 2019


Author: komzpa
Date: 2019-08-04 00:45:16 -0700 (Sun, 04 Aug 2019)
New Revision: 17672

Modified:
   trunk/NEWS
   trunk/liblwgeom/lwin_geojson.c
   trunk/regress/core/in_geojson.sql
   trunk/regress/core/in_geojson_expected
Log:
ST_GeomFromGeoJSON crash on empty rings

Closes #4470
Closes https://github.com/postgis/postgis/pull/453


Modified: trunk/NEWS
===================================================================
--- trunk/NEWS	2019-08-04 07:42:45 UTC (rev 17671)
+++ trunk/NEWS	2019-08-04 07:45:16 UTC (rev 17672)
@@ -220,7 +220,9 @@
   - #4327, Avoid pfree'ing the result of getenv (Raúl Marín)
   - #4406, Throw on invalid characters when decoding geohash (Raúl Marín)
   - #4459, Fix ST_Subdivide crash on intermediate EMPTY (Darafei Praliaskouski)
+  - #4470, ST_GeomFromGeoJSON crash on empty rings (Darafei Praliaskouski)
 
+
 PostGIS 2.5.0
 2018/09/23
 WARNING: If compiling with PostgreSQL+JIT, LLVM >= 6 is required

Modified: trunk/liblwgeom/lwin_geojson.c
===================================================================
--- trunk/liblwgeom/lwin_geojson.c	2019-08-04 07:42:45 UTC (rev 17671)
+++ trunk/liblwgeom/lwin_geojson.c	2019-08-04 07:45:16 UTC (rev 17672)
@@ -18,13 +18,12 @@
  *
  **********************************************************************
  *
+ * Copyright 2019 Darafei Praliaskouski <me at komzpa.net>
  * Copyright 2013 Sandro Santilli <strk at kbt.io>
  * Copyright 2011 Kashif Rasul <kashif.rasul at gmail.com>
  *
  **********************************************************************/
 
-
-#include <assert.h>
 #include "liblwgeom.h"
 #include "lwgeom_log.h"
 #include "../postgis_config.h"
@@ -41,29 +40,23 @@
 
 #ifndef JSON_C_VERSION
 /* Adds support for libjson < 0.10 */
-# define json_tokener_error_desc(x) json_tokener_errors[(x)]
+#define json_tokener_error_desc(x) json_tokener_errors[(x)]
 #endif
 
 #include <string.h>
 
-static void geojson_lwerror(char *msg, __attribute__((__unused__)) int error_code)
-{
-	LWDEBUGF(3, "lwgeom_from_geojson ERROR %i", error_code);
-	lwerror("%s", msg);
-}
-
 /* Prototype */
-static LWGEOM* parse_geojson(json_object *geojson, int *hasz, int root_srid);
+static LWGEOM *parse_geojson(json_object *geojson, int *hasz);
 
-static json_object*
-findMemberByName(json_object* poObj, const char* pszName )
+static inline json_object *
+findMemberByName(json_object *poObj, const char *pszName)
 {
-	json_object* poTmp;
+	json_object *poTmp;
 	json_object_iter it;
 
 	poTmp = poObj;
 
-	if( NULL == pszName || NULL == poObj)
+	if (!pszName || !poObj)
 		return NULL;
 
 	it.key = NULL;
@@ -70,21 +63,19 @@
 	it.val = NULL;
 	it.entry = NULL;
 
-	if( NULL != json_object_get_object(poTmp) )
+	if (json_object_get_object(poTmp))
 	{
-		if( NULL == json_object_get_object(poTmp)->head )
+		if (!json_object_get_object(poTmp)->head)
 		{
-			geojson_lwerror("invalid GeoJSON representation", 2);
+			lwerror("invalid GeoJSON representation");
 			return NULL;
 		}
 
-		for( it.entry = json_object_get_object(poTmp)->head;
-		        ( it.entry ?
-		          ( it.key = (char*)it.entry->k,
-		            it.val = (json_object*)it.entry->v, it.entry) : 0);
-		        it.entry = it.entry->next)
+		for (it.entry = json_object_get_object(poTmp)->head;
+		     (it.entry ? (it.key = (char *)it.entry->k, it.val = (json_object *)it.entry->v, it.entry) : 0);
+		     it.entry = it.entry->next)
 		{
-			if( strcasecmp((char *)it.key, pszName )==0 )
+			if (strcasecmp((char *)it.key, pszName) == 0)
 				return it.val;
 		}
 	}
@@ -92,60 +83,56 @@
 	return NULL;
 }
 
+static inline json_object *
+parse_coordinates(json_object *geojson)
+{
+	json_object *coordinates = findMemberByName(geojson, "coordinates");
+	if (!coordinates)
+	{
+		lwerror("Unable to find 'coordinates' in GeoJSON string");
+		return NULL;
+	}
 
-static int
+	if (json_type_array != json_object_get_type(coordinates))
+	{
+		lwerror("The 'coordinates' in GeoJSON are not an array");
+		return NULL;
+	}
+	return coordinates;
+}
+
+
+static inline int
 parse_geojson_coord(json_object *poObj, int *hasz, POINTARRAY *pa)
 {
-	POINT4D pt;
+	POINT4D pt = {0, 0, 0, 0};
 
-	LWDEBUGF(3, "parse_geojson_coord called for object %s.", json_object_to_json_string( poObj ) );
-
-	if( json_type_array == json_object_get_type( poObj ) )
+	if (json_type_array == json_object_get_type(poObj))
 	{
 
-		json_object* poObjCoord = NULL;
-		const int nSize = json_object_array_length( poObj );
-		LWDEBUGF(3, "parse_geojson_coord called for array size %d.", nSize );
-
-		if ( nSize < 2 )
+		json_object *poObjCoord = NULL;
+		const int nSize = json_object_array_length(poObj);
+		if (nSize < 2)
 		{
-			geojson_lwerror("Too few ordinates in GeoJSON", 4);
+			lwerror("Too few ordinates in GeoJSON");
 			return LW_FAILURE;
 		}
 
 		/* Read X coordinate */
-		poObjCoord = json_object_array_get_idx( poObj, 0 );
-		pt.x = json_object_get_double( poObjCoord );
-		LWDEBUGF(3, "parse_geojson_coord pt.x = %f.", pt.x );
+		poObjCoord = json_object_array_get_idx(poObj, 0);
+		pt.x = json_object_get_double(poObjCoord);
 
 		/* Read Y coordinate */
-		poObjCoord = json_object_array_get_idx( poObj, 1 );
-		pt.y = json_object_get_double( poObjCoord );
-		LWDEBUGF(3, "parse_geojson_coord pt.y = %f.", pt.y );
+		poObjCoord = json_object_array_get_idx(poObj, 1);
+		pt.y = json_object_get_double(poObjCoord);
 
-		if( nSize > 2 ) /* should this be >= 3 ? */
+		if (nSize > 2) /* should this be >= 3 ? */
 		{
 			/* Read Z coordinate */
-			poObjCoord = json_object_array_get_idx( poObj, 2 );
-			pt.z = json_object_get_double( poObjCoord );
-			LWDEBUGF(3, "parse_geojson_coord pt.z = %f.", pt.z );
+			poObjCoord = json_object_array_get_idx(poObj, 2);
+			pt.z = json_object_get_double(poObjCoord);
 			*hasz = LW_TRUE;
 		}
-		else if ( nSize == 2 )
-		{
-			*hasz = LW_FALSE;
-			/* Initialize Z coordinate, if required */
-			if ( FLAGS_GET_Z(pa->flags) ) pt.z = 0.0;
-		}
-		else
-		{
-			/* TODO: should we account for nSize > 3 ? */
-			/* more than 3 coordinates, we're just dropping dimensions here... */
-		}
-
-		/* Initialize M coordinate, if required */
-		if ( FLAGS_GET_M(pa->flags) ) pt.m = 0.0;
-
 	}
 	else
 	{
@@ -156,126 +143,76 @@
 	return ptarray_append_point(pa, &pt, LW_TRUE);
 }
 
-static LWGEOM*
-parse_geojson_point(json_object *geojson, int *hasz, int root_srid)
+static inline LWGEOM *
+parse_geojson_point(json_object *geojson, int *hasz)
 {
-	LWGEOM *geom;
-	POINTARRAY *pa;
-	json_object* coords = NULL;
-
-	LWDEBUGF(3, "parse_geojson_point called with root_srid = %d.", root_srid );
-
-	coords = findMemberByName( geojson, "coordinates" );
-	if ( ! coords )
-	{
-		geojson_lwerror("Unable to find 'coordinates' in GeoJSON string", 4);
-		return NULL;
-	}
-
-	pa = ptarray_construct_empty(1, 0, 1);
+	json_object *coords = parse_coordinates(geojson);
+	POINTARRAY *pa = ptarray_construct_empty(1, 0, 1);
 	parse_geojson_coord(coords, hasz, pa);
-
-	geom = (LWGEOM *) lwpoint_construct(root_srid, NULL, pa);
-	LWDEBUG(2, "parse_geojson_point finished.");
-	return geom;
+	return (LWGEOM *)lwpoint_construct(0, NULL, pa);
 }
 
-static LWGEOM*
-parse_geojson_linestring(json_object *geojson, int *hasz, int root_srid)
+static inline LWGEOM *
+parse_geojson_linestring(json_object *geojson, int *hasz)
 {
-	LWGEOM *geom;
-	POINTARRAY *pa;
-	json_object* points = NULL;
-	int i = 0;
-
-	LWDEBUG(2, "parse_geojson_linestring called.");
-
-	points = findMemberByName( geojson, "coordinates" );
-	if ( ! points )
+	json_object *points = parse_coordinates(geojson);
+	POINTARRAY *pa = ptarray_construct_empty(1, 0, 1);
+	const int nPoints = json_object_array_length(points);
+	for (int i = 0; i < nPoints; i++)
 	{
-		geojson_lwerror("Unable to find 'coordinates' in GeoJSON string", 4);
-	return NULL;
+		json_object *coords = json_object_array_get_idx(points, i);
+		parse_geojson_coord(coords, hasz, pa);
 	}
-
-	pa = ptarray_construct_empty(1, 0, 1);
-
-	if( json_type_array == json_object_get_type( points ) )
-	{
-		const int nPoints = json_object_array_length( points );
-		for(i = 0; i < nPoints; ++i)
-		{
-			json_object* coords = NULL;
-			coords = json_object_array_get_idx( points, i );
-			parse_geojson_coord(coords, hasz, pa);
-		}
-	}
-
-	geom = (LWGEOM *) lwline_construct(root_srid, NULL, pa);
-
-	LWDEBUG(2, "parse_geojson_linestring finished.");
-	return geom;
+	return (LWGEOM *)lwline_construct(0, NULL, pa);
 }
 
-static LWGEOM*
-parse_geojson_polygon(json_object *geojson, int *hasz, int root_srid)
+static inline LWPOLY *
+parse_geojson_poly_rings(json_object *rings, int *hasz)
 {
-	POINTARRAY **ppa = NULL;
-	json_object* rings = NULL;
-	json_object* points = NULL;
-	int i = 0, j = 0;
-	int nRings = 0, nPoints = 0;
-
-	rings = findMemberByName( geojson, "coordinates" );
-	if ( ! rings )
-	{
-		geojson_lwerror("Unable to find 'coordinates' in GeoJSON string", 4);
+	if (!rings)
 		return NULL;
-	}
+	int nRings = json_object_array_length(rings);
 
-	if ( json_type_array != json_object_get_type(rings) )
-	{
-		geojson_lwerror("The 'coordinates' in GeoJSON are not an array", 4);
-		return NULL;
-	}
+	/* No rings => POLYGON EMPTY */
+	if (!nRings)
+		return lwpoly_construct_empty(0, 1, 0);
 
-	nRings = json_object_array_length( rings );
+	/* Expecting up to nRings otherwise */
+	POINTARRAY **ppa = (POINTARRAY **)lwalloc(sizeof(POINTARRAY *) * nRings);
+	int o = 0;
 
-	/* No rings => POLYGON EMPTY */
-	if ( ! nRings )
+	for (int i = 0; i < nRings; i++)
 	{
-		return (LWGEOM *)lwpoly_construct_empty(root_srid, 0, 0);
-	}
-
-	for ( i = 0; i < nRings; i++ )
-	{
-		points = json_object_array_get_idx(rings, i);
-		if ( ! points || json_object_get_type(points) != json_type_array )
+		json_object *points = json_object_array_get_idx(rings, i);
+		if (!points || json_object_get_type(points) != json_type_array)
 		{
-			geojson_lwerror("The 'coordinates' in GeoJSON ring are not an array", 4);
+			lwerror("The 'coordinates' in GeoJSON ring are not an array");
 			return NULL;
 		}
-		nPoints = json_object_array_length(points);
+		int nPoints = json_object_array_length(points);
 
 		/* Skip empty rings */
-		if ( nPoints == 0 ) continue;
+		if (!nPoints)
+		{
+			/* Empty outer? Don't promote first hole to outer, holes don't matter. */
+			if (!i)
+				break;
+			else
+				continue;
+		}
 
-		if ( ! ppa )
-			ppa = (POINTARRAY**)lwalloc(sizeof(POINTARRAY*) * nRings);
-
-		ppa[i] = ptarray_construct_empty(1, 0, 1);
-		for ( j = 0; j < nPoints; j++ )
+		ppa[o++] = ptarray_construct_empty(1, 0, 1);
+		for (int j = 0; j < nPoints; j++)
 		{
-			json_object* coords = NULL;
-			coords = json_object_array_get_idx( points, j );
+			json_object *coords = NULL;
+			coords = json_object_array_get_idx(points, j);
 			if (LW_FAILURE == parse_geojson_coord(coords, hasz, ppa[i]))
 			{
 				int k;
-				for (k = 0; k <= i; k++)
-				{
+				for (k = 0; k < o; k++)
 					ptarray_free(ppa[k]);
-				}
 				lwfree(ppa);
-				geojson_lwerror("The 'coordinates' in GeoJSON polygon are not sufficiently nested", 4);
+				lwerror("The 'coordinates' in GeoJSON are not sufficiently nested");
 				return NULL;
 			}
 		}
@@ -282,202 +219,102 @@
 	}
 
 	/* All the rings were empty! */
-	if ( ! ppa )
-		return (LWGEOM *)lwpoly_construct_empty(root_srid, 0, 0);
+	if (!o)
+	{
+		lwfree(ppa);
+		return lwpoly_construct_empty(0, 1, 0);
+	}
 
-	return (LWGEOM *) lwpoly_construct(root_srid, NULL, nRings, ppa);
+	return lwpoly_construct(0, NULL, o, ppa);
 }
 
-static LWGEOM*
-parse_geojson_multipoint(json_object *geojson, int *hasz, int root_srid)
+static inline LWGEOM *
+parse_geojson_polygon(json_object *geojson, int *hasz)
 {
-	LWGEOM *geom;
-	int i = 0;
-	json_object* poObjPoints = NULL;
+	return (LWGEOM *)parse_geojson_poly_rings(parse_coordinates(geojson), hasz);
+}
 
-	if (!root_srid)
-	{
-		geom = (LWGEOM *)lwcollection_construct_empty(MULTIPOINTTYPE, root_srid, 1, 0);
-	}
-	else
-	{
-		geom = (LWGEOM *)lwcollection_construct_empty(MULTIPOINTTYPE, -1, 1, 0);
-	}
+static inline LWGEOM *
+parse_geojson_multipoint(json_object *geojson, int *hasz)
+{
+	json_object *points = parse_coordinates(geojson);
+	LWMPOINT *geom = (LWMPOINT *)lwcollection_construct_empty(MULTIPOINTTYPE, 0, 1, 0);
 
-	poObjPoints = findMemberByName( geojson, "coordinates" );
-	if ( ! poObjPoints )
+	const int nPoints = json_object_array_length(points);
+	for (int i = 0; i < nPoints; ++i)
 	{
-		geojson_lwerror("Unable to find 'coordinates' in GeoJSON string", 4);
-		return NULL;
+		POINTARRAY *pa = ptarray_construct_empty(1, 0, 1);
+		json_object *coord = json_object_array_get_idx(points, i);
+		parse_geojson_coord(coord, hasz, pa);
+		geom = lwmpoint_add_lwpoint(geom, lwpoint_construct(0, NULL, pa));
 	}
 
-	if( json_type_array == json_object_get_type( poObjPoints ) )
-	{
-		const int nPoints = json_object_array_length( poObjPoints );
-		for( i = 0; i < nPoints; ++i)
-		{
-			POINTARRAY *pa;
-			json_object* poObjCoords = NULL;
-			poObjCoords = json_object_array_get_idx( poObjPoints, i );
-
-			pa = ptarray_construct_empty(1, 0, 1);
-			parse_geojson_coord(poObjCoords, hasz, pa);
-
-			geom = (LWGEOM*)lwmpoint_add_lwpoint((LWMPOINT*)geom,
-			                                     (LWPOINT*)lwpoint_construct(root_srid, NULL, pa));
-		}
-	}
-
-	return geom;
+	return (LWGEOM *)geom;
 }
 
-static LWGEOM*
-parse_geojson_multilinestring(json_object *geojson, int *hasz, int root_srid)
+static inline LWGEOM *
+parse_geojson_multilinestring(json_object *geojson, int *hasz)
 {
-	LWGEOM *geom = NULL;
-	int i, j;
-	json_object* poObjLines = NULL;
-
-	if (!root_srid)
+	json_object *poObjLines = parse_coordinates(geojson);
+	LWMLINE *geom = (LWMLINE *)lwcollection_construct_empty(MULTILINETYPE, 0, 1, 0);
+	const int nLines = json_object_array_length(poObjLines);
+	for (int i = 0; i < nLines; ++i)
 	{
-		geom = (LWGEOM *)lwcollection_construct_empty(MULTILINETYPE, root_srid, 1, 0);
-	}
-	else
-	{
-		geom = (LWGEOM *)lwcollection_construct_empty(MULTILINETYPE, -1, 1, 0);
-	}
+		POINTARRAY *pa = ptarray_construct_empty(1, 0, 1);
+		json_object *poObjLine = json_object_array_get_idx(poObjLines, i);
 
-	poObjLines = findMemberByName( geojson, "coordinates" );
-	if ( ! poObjLines )
-	{
-		geojson_lwerror("Unable to find 'coordinates' in GeoJSON string", 4);
-		return NULL;
-	}
-
-	if( json_type_array == json_object_get_type( poObjLines ) )
-	{
-		const int nLines = json_object_array_length( poObjLines );
-		for( i = 0; i < nLines; ++i)
+		if (json_type_array == json_object_get_type(poObjLine))
 		{
-			POINTARRAY *pa = NULL;
-			json_object* poObjLine = NULL;
-			poObjLine = json_object_array_get_idx( poObjLines, i );
-			pa = ptarray_construct_empty(1, 0, 1);
-
-			if( json_type_array == json_object_get_type( poObjLine ) )
+			const int nPoints = json_object_array_length(poObjLine);
+			for (int j = 0; j < nPoints; ++j)
 			{
-				const int nPoints = json_object_array_length( poObjLine );
-				for(j = 0; j < nPoints; ++j)
-				{
-					json_object* coords = NULL;
-					coords = json_object_array_get_idx( poObjLine, j );
-					parse_geojson_coord(coords, hasz, pa);
-				}
+				json_object *coords = json_object_array_get_idx(poObjLine, j);
+				parse_geojson_coord(coords, hasz, pa);
+			}
 
-				geom = (LWGEOM*)lwmline_add_lwline((LWMLINE*)geom,
-				                                   (LWLINE*)lwline_construct(root_srid, NULL, pa));
-			}
+			geom = lwmline_add_lwline(geom, lwline_construct(0, NULL, pa));
 		}
 	}
 
-	return geom;
+	return (LWGEOM *)geom;
 }
 
-static LWGEOM*
-parse_geojson_multipolygon(json_object *geojson, int *hasz, int root_srid)
+static inline LWGEOM *
+parse_geojson_multipolygon(json_object *geojson, int *hasz)
 {
-	LWGEOM *geom = NULL;
-	int i, j, k;
-	json_object* poObjPolys = NULL;
+	LWGEOM *geom = (LWGEOM *)lwcollection_construct_empty(MULTIPOLYGONTYPE, 0, 1, 0);
+	json_object *polys = parse_coordinates(geojson);
+	int nPolys = json_object_array_length(polys);
 
-	if (!root_srid)
+	for (int i = 0; i < nPolys; ++i)
 	{
-		geom = (LWGEOM *)lwcollection_construct_empty(MULTIPOLYGONTYPE, root_srid, 1, 0);
+		json_object *rings = json_object_array_get_idx(polys, i);
+		LWPOLY *poly = parse_geojson_poly_rings(rings, hasz);
+		geom = (LWGEOM *)lwmpoly_add_lwpoly((LWMPOLY *)geom, poly);
 	}
-	else
-	{
-		geom = (LWGEOM *)lwcollection_construct_empty(MULTIPOLYGONTYPE, -1, 1, 0);
-	}
 
-	poObjPolys = findMemberByName( geojson, "coordinates" );
-	if ( ! poObjPolys )
-	{
-		geojson_lwerror("Unable to find 'coordinates' in GeoJSON string", 4);
-		return NULL;
-	}
-
-	if( json_type_array == json_object_get_type( poObjPolys ) )
-	{
-		const int nPolys = json_object_array_length( poObjPolys );
-
-		for(i = 0; i < nPolys; ++i)
-		{
-			json_object* poObjPoly = json_object_array_get_idx( poObjPolys, i );
-
-			if( json_type_array == json_object_get_type( poObjPoly ) )
-			{
-				LWPOLY *lwpoly = lwpoly_construct_empty(geom->srid, lwgeom_has_z(geom), lwgeom_has_m(geom));
-				int nRings = json_object_array_length( poObjPoly );
-
-				for(j = 0; j < nRings; ++j)
-				{
-					json_object* points = json_object_array_get_idx( poObjPoly, j );
-
-					if( json_type_array == json_object_get_type( points ) )
-					{
-
-						POINTARRAY *pa = ptarray_construct_empty(1, 0, 1);
-
-						int nPoints = json_object_array_length( points );
-						for ( k=0; k < nPoints; k++ )
-						{
-							json_object* coords = json_object_array_get_idx( points, k );
-							parse_geojson_coord(coords, hasz, pa);
-						}
-
-						lwpoly_add_ring(lwpoly, pa);
-					}
-				}
-				geom = (LWGEOM*)lwmpoly_add_lwpoly((LWMPOLY*)geom, lwpoly);
-			}
-		}
-	}
-
 	return geom;
 }
 
-static LWGEOM*
-parse_geojson_geometrycollection(json_object *geojson, int *hasz, int root_srid)
+static inline LWGEOM *
+parse_geojson_geometrycollection(json_object *geojson, int *hasz)
 {
-	LWGEOM *geom = NULL;
-	int i;
-	json_object* poObjGeoms = NULL;
-
-	if (!root_srid)
+	LWGEOM *geom = (LWGEOM *)lwcollection_construct_empty(COLLECTIONTYPE, 0, 1, 0);
+	json_object *poObjGeoms = findMemberByName(geojson, "geometries");
+	if (!poObjGeoms)
 	{
-		geom = (LWGEOM *)lwcollection_construct_empty(COLLECTIONTYPE, root_srid, 1, 0);
-	}
-	else
-	{
-		geom = (LWGEOM *)lwcollection_construct_empty(COLLECTIONTYPE, -1, 1, 0);
-	}
-
-	poObjGeoms = findMemberByName( geojson, "geometries" );
-	if ( ! poObjGeoms )
-	{
-		geojson_lwerror("Unable to find 'geometries' in GeoJSON string", 4);
+		lwerror("Unable to find 'geometries' in GeoJSON string");
 		return NULL;
 	}
 
-	if( json_type_array == json_object_get_type( poObjGeoms ) )
+	if (json_type_array == json_object_get_type(poObjGeoms))
 	{
-		const int nGeoms = json_object_array_length( poObjGeoms );
-		json_object* poObjGeom = NULL;
-		for(i = 0; i < nGeoms; ++i )
+		const int nGeoms = json_object_array_length(poObjGeoms);
+		for (int i = 0; i < nGeoms; ++i)
 		{
-			poObjGeom = json_object_array_get_idx( poObjGeoms, i );
-			geom = (LWGEOM*)lwcollection_add_lwgeom((LWCOLLECTION *)geom,
-			                                        parse_geojson(poObjGeom, hasz, root_srid));
+			json_object *poObjGeom = json_object_array_get_idx(poObjGeoms, i);
+			geom = (LWGEOM *)lwcollection_add_lwgeom((LWCOLLECTION *)geom,
+								 parse_geojson(poObjGeom, hasz));
 		}
 	}
 
@@ -484,47 +321,47 @@
 	return geom;
 }
 
-static LWGEOM*
-parse_geojson(json_object *geojson, int *hasz, int root_srid)
+static inline LWGEOM *
+parse_geojson(json_object *geojson, int *hasz)
 {
-	json_object* type = NULL;
-	const char* name;
+	json_object *type = NULL;
+	const char *name;
 
-	if( NULL == geojson )
+	if (!geojson)
 	{
-		geojson_lwerror("invalid GeoJSON representation", 2);
+		lwerror("invalid GeoJSON representation");
 		return NULL;
 	}
 
-	type = findMemberByName( geojson, "type" );
-	if( NULL == type )
+	type = findMemberByName(geojson, "type");
+	if (!type)
 	{
-		geojson_lwerror("unknown GeoJSON type", 3);
+		lwerror("unknown GeoJSON type");
 		return NULL;
 	}
 
-	name = json_object_get_string( type );
+	name = json_object_get_string(type);
 
-	if( strcasecmp( name, "Point" )==0 )
-		return parse_geojson_point(geojson, hasz, root_srid);
+	if (strcasecmp(name, "Point") == 0)
+		return parse_geojson_point(geojson, hasz);
 
-	if( strcasecmp( name, "LineString" )==0 )
-		return parse_geojson_linestring(geojson, hasz, root_srid);
+	if (strcasecmp(name, "LineString") == 0)
+		return parse_geojson_linestring(geojson, hasz);
 
-	if( strcasecmp( name, "Polygon" )==0 )
-		return parse_geojson_polygon(geojson, hasz, root_srid);
+	if (strcasecmp(name, "Polygon") == 0)
+		return parse_geojson_polygon(geojson, hasz);
 
-	if( strcasecmp( name, "MultiPoint" )==0 )
-		return parse_geojson_multipoint(geojson, hasz, root_srid);
+	if (strcasecmp(name, "MultiPoint") == 0)
+		return parse_geojson_multipoint(geojson, hasz);
 
-	if( strcasecmp( name, "MultiLineString" )==0 )
-		return parse_geojson_multilinestring(geojson, hasz, root_srid);
+	if (strcasecmp(name, "MultiLineString") == 0)
+		return parse_geojson_multilinestring(geojson, hasz);
 
-	if( strcasecmp( name, "MultiPolygon" )==0 )
-		return parse_geojson_multipolygon(geojson, hasz, root_srid);
+	if (strcasecmp(name, "MultiPolygon") == 0)
+		return parse_geojson_multipolygon(geojson, hasz);
 
-	if( strcasecmp( name, "GeometryCollection" )==0 )
-		return parse_geojson_geometrycollection(geojson, hasz, root_srid);
+	if (strcasecmp(name, "GeometryCollection") == 0)
+		return parse_geojson_geometrycollection(geojson, hasz);
 
 	lwerror("invalid GeoJson representation");
 	return NULL; /* Never reach */
@@ -532,7 +369,7 @@
 
 #endif /* HAVE_LIBJSON or HAVE_LIBJSON_C --} */
 
-LWGEOM*
+LWGEOM *
 lwgeom_from_geojson(const char *geojson, char **srs)
 {
 #ifndef HAVE_LIBJSON
@@ -539,45 +376,37 @@
 	*srs = NULL;
 	lwerror("You need JSON-C for lwgeom_from_geojson");
 	return NULL;
-#else /* HAVE_LIBJSON */
+#else  /* HAVE_LIBJSON */
 
-	/* size_t geojson_size = strlen(geojson); */
-
-	LWGEOM *lwgeom;
-	int hasz=LW_TRUE;
-	json_tokener* jstok = NULL;
-	json_object* poObj = NULL;
-	json_object* poObjSrs = NULL;
-	*srs = NULL;
-
 	/* Begin to Parse json */
-	jstok = json_tokener_new();
-	poObj = json_tokener_parse_ex(jstok, geojson, -1);
-	if( jstok->err != json_tokener_success)
+	json_tokener *jstok = json_tokener_new();
+	json_object *poObj = json_tokener_parse_ex(jstok, geojson, -1);
+	if (jstok->err != json_tokener_success)
 	{
 		char err[256];
 		snprintf(err, 256, "%s (at offset %d)", json_tokener_error_desc(jstok->err), jstok->char_offset);
 		json_tokener_free(jstok);
 		json_object_put(poObj);
-		geojson_lwerror(err, 1);
+		lwerror(err);
 		return NULL;
 	}
 	json_tokener_free(jstok);
 
-	poObjSrs = findMemberByName( poObj, "crs" );
+	*srs = NULL;
+	json_object *poObjSrs = findMemberByName(poObj, "crs");
 	if (poObjSrs != NULL)
 	{
-		json_object* poObjSrsType = findMemberByName( poObjSrs, "type" );
+		json_object *poObjSrsType = findMemberByName(poObjSrs, "type");
 		if (poObjSrsType != NULL)
 		{
-			json_object* poObjSrsProps = findMemberByName( poObjSrs, "properties" );
-			if ( poObjSrsProps )
+			json_object *poObjSrsProps = findMemberByName(poObjSrs, "properties");
+			if (poObjSrsProps)
 			{
-				json_object* poNameURL = findMemberByName( poObjSrsProps, "name" );
-				if ( poNameURL )
+				json_object *poNameURL = findMemberByName(poObjSrsProps, "name");
+				if (poNameURL)
 				{
-					const char* pszName = json_object_get_string( poNameURL );
-					if ( pszName )
+					const char *pszName = json_object_get_string(poNameURL);
+					if (pszName)
 					{
 						*srs = lwalloc(strlen(pszName) + 1);
 						strcpy(*srs, pszName);
@@ -587,22 +416,17 @@
 		}
 	}
 
-	lwgeom = parse_geojson(poObj, &hasz, 0);
+	int hasz = LW_FALSE;
+	LWGEOM *lwgeom = parse_geojson(poObj, &hasz);
 	json_object_put(poObj);
 
-	lwgeom_add_bbox(lwgeom);
-
 	if (!hasz)
 	{
 		LWGEOM *tmp = lwgeom_force_2d(lwgeom);
 		lwgeom_free(lwgeom);
 		lwgeom = tmp;
-
-		LWDEBUG(2, "geom_from_geojson called.");
 	}
-
+	lwgeom_add_bbox(lwgeom);
 	return lwgeom;
 #endif /* HAVE_LIBJSON } */
 }
-
-

Modified: trunk/regress/core/in_geojson.sql
===================================================================
--- trunk/regress/core/in_geojson.sql	2019-08-04 07:42:45 UTC (rev 17671)
+++ trunk/regress/core/in_geojson.sql	2019-08-04 07:45:16 UTC (rev 17672)
@@ -47,8 +47,10 @@
 SELECT 'geomfromgeojson_srs_3', ST_AsEWKT(ST_GeomFromGeoJSON('{"type":"GeometryCollection","geometries":[{"type":"Point","coordinates":[100.0,0.0]},{"type":"LineString","coordinates":[[101.0,0.0],[102.0,1.0]]}],"crs":{"type":"name","props":{"name":"urn:ogc:def:crs:EPSG::4326"}}}'));
 SELECT 'geomfromgeojson_srs_4', ST_AsEWKT(ST_GeomFromGeoJSON('{"type":"GeometryCollection","geometries":[{"type":"Point","coordinates":[100.0,0.0]},{"type":"LineString","coordinates":[[101.0,0.0],[102.0,1.0]]}],"crs":{"type":"name","properties":{"nm":"EPSG:4326"}}}'));
 
--- #3583
 SELECT '#3583', ST_AsText(ST_GeomFromGeoJSON('{"type":"MultiPolygon", "coordinates":[[[139.10030364990232,35.16777444430609],5842.4224490305424]]}'));
+SELECT '#4164', ST_AsText(ST_GeomFromGeoJSON('{"type": "Polygon", "coordinates": [[0,0],[0,5],[5, 5],[5,0],[0,0]]}'));
 
--- #4164
-SELECT ST_AsText(ST_GeomFromGeoJSON('{"type": "Polygon", "coordinates": [[0,0],[0,5],[5, 5],[5,0],[0,0]]}'));
+SELECT '#4470.a', ST_AsText(ST_GeomFromGeoJSON('{"type":"Polygon","coordinates":[[[0,0]],[]]}'));
+SELECT '#4470.b', ST_AsText(ST_GeomFromGeoJSON('{"type":"Polygon","coordinates":[[],[0,0]]}'));
+SELECT '#4470.c', ST_AsText(ST_GeomFromGeoJSON('{"type":"MultiPolygon","coordinates":[[[[0,0]],[]]]}'));
+SELECT '#4470.d', ST_AsText(ST_GeomFromGeoJSON('{"type":"MultiPolygon","coordinates":[[[],[0,0]]]}'));

Modified: trunk/regress/core/in_geojson_expected
===================================================================
--- trunk/regress/core/in_geojson_expected	2019-08-04 07:42:45 UTC (rev 17671)
+++ trunk/regress/core/in_geojson_expected	2019-08-04 07:45:16 UTC (rev 17672)
@@ -18,7 +18,7 @@
 #2130|50
 #2216|30
 #2619|POLYGON EMPTY
-#2619|MULTIPOLYGON Z (EMPTY)
+#2619|MULTIPOLYGON EMPTY
 ERROR:  The 'coordinates' in GeoJSON ring are not an array
 ERROR:  The 'coordinates' in GeoJSON ring are not an array
 geomfromgeojson_z_01|POINT(1 2 3)
@@ -29,5 +29,9 @@
 geomfromgeojson_srs_2|GEOMETRYCOLLECTION(POINT(100 0),LINESTRING(101 0,102 1))
 geomfromgeojson_srs_3|GEOMETRYCOLLECTION(POINT(100 0),LINESTRING(101 0,102 1))
 geomfromgeojson_srs_4|GEOMETRYCOLLECTION(POINT(100 0),LINESTRING(101 0,102 1))
-#3583|MULTIPOLYGON Z (EMPTY)
-ERROR:  The 'coordinates' in GeoJSON polygon are not sufficiently nested
+ERROR:  The 'coordinates' in GeoJSON are not sufficiently nested
+ERROR:  The 'coordinates' in GeoJSON are not sufficiently nested
+#4470.a|POLYGON((0 0))
+#4470.b|POLYGON EMPTY
+#4470.c|MULTIPOLYGON(((0 0)))
+#4470.d|MULTIPOLYGON EMPTY



More information about the postgis-tickets mailing list