Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 21 additions & 14 deletions modules/core/src/main/java/org/locationtech/jts/io/WKBReader.java
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@
*/
public class WKBReader
{
private static final int MAXIMUM_NESTING_DEPTH = 1000;

/**
* Converts a hexadecimal string to a byte array.
* The hexadecimal digit symbols are case-insensitive.
Expand Down Expand Up @@ -189,7 +191,7 @@ private Geometry read(InStream is, int maxCoordNum)
*/
this.maxNumFieldValue = maxCoordNum;
dis.setInStream(is);
return readGeometry(0);
return readGeometry(0, 0);
}

private int readNumField(String fieldName) throws IOException, ParseException {
Expand All @@ -201,7 +203,7 @@ private int readNumField(String fieldName) throws IOException, ParseException {
return num;
}

private Geometry readGeometry(int SRID)
private Geometry readGeometry(int SRID, int nestingDepth)
throws IOException, ParseException
{

Expand Down Expand Up @@ -276,16 +278,16 @@ else if(isStrict)
geom = readPolygon(ordinateFlags);
break;
case WKBConstants.wkbMultiPoint :
geom = readMultiPoint(SRID);
geom = readMultiPoint(SRID, nestingDepth);
break;
case WKBConstants.wkbMultiLineString :
geom = readMultiLineString(SRID);
geom = readMultiLineString(SRID, nestingDepth);
break;
case WKBConstants.wkbMultiPolygon :
geom = readMultiPolygon(SRID);
geom = readMultiPolygon(SRID, nestingDepth);
break;
case WKBConstants.wkbGeometryCollection :
geom = readGeometryCollection(SRID);
geom = readGeometryCollection(SRID, nestingDepth);
break;
default:
throw new ParseException("Unknown WKB type " + geometryType);
Expand Down Expand Up @@ -349,52 +351,57 @@ private Polygon readPolygon(EnumSet<Ordinate> ordinateFlags) throws IOException,
return factory.createPolygon(shell, holes);
}

private MultiPoint readMultiPoint(int SRID) throws IOException, ParseException
private MultiPoint readMultiPoint(int SRID, int nestingDepth) throws IOException, ParseException
{
int numGeom = readNumField(FIELD_NUMELEMS);
Point[] geoms = new Point[numGeom];
for (int i = 0; i < numGeom; i++) {
Geometry g = readGeometry(SRID);
Geometry g = readGeometry(SRID, nestingDepth + 1);
if (! (g instanceof Point))
throw new ParseException(INVALID_GEOM_TYPE_MSG + "MultiPoint");
geoms[i] = (Point) g;
}
return factory.createMultiPoint(geoms);
}

private MultiLineString readMultiLineString(int SRID) throws IOException, ParseException
private MultiLineString readMultiLineString(int SRID, int nestingDepth) throws IOException, ParseException
{
int numGeom = readNumField(FIELD_NUMELEMS);
LineString[] geoms = new LineString[numGeom];
for (int i = 0; i < numGeom; i++) {
Geometry g = readGeometry(SRID);
Geometry g = readGeometry(SRID, nestingDepth + 1);
if (! (g instanceof LineString))
throw new ParseException(INVALID_GEOM_TYPE_MSG + "MultiLineString");
geoms[i] = (LineString) g;
}
return factory.createMultiLineString(geoms);
}

private MultiPolygon readMultiPolygon(int SRID) throws IOException, ParseException
private MultiPolygon readMultiPolygon(int SRID, int nestingDepth) throws IOException, ParseException
{
int numGeom = readNumField(FIELD_NUMELEMS);
Polygon[] geoms = new Polygon[numGeom];

for (int i = 0; i < numGeom; i++) {
Geometry g = readGeometry(SRID);
Geometry g = readGeometry(SRID, nestingDepth + 1);
if (! (g instanceof Polygon))
throw new ParseException(INVALID_GEOM_TYPE_MSG + "MultiPolygon");
geoms[i] = (Polygon) g;
}
return factory.createMultiPolygon(geoms);
}

private GeometryCollection readGeometryCollection(int SRID) throws IOException, ParseException
private GeometryCollection readGeometryCollection(int SRID, int nestingDepth)
throws IOException, ParseException
{
if (nestingDepth >= MAXIMUM_NESTING_DEPTH) {
throw new ParseException("GeometryCollection nesting depth exceeds maximum of "
+ MAXIMUM_NESTING_DEPTH);
}
int numGeom = readNumField(FIELD_NUMELEMS);
Geometry[] geoms = new Geometry[numGeom];
for (int i = 0; i < numGeom; i++) {
geoms[i] = readGeometry(SRID);
geoms[i] = readGeometry(SRID, nestingDepth + 1);
}
return factory.createGeometryCollection(geoms);
}
Expand Down
23 changes: 15 additions & 8 deletions modules/core/src/main/java/org/locationtech/jts/io/WKTReader.java
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,8 @@
*/
public class WKTReader
{
private static final int MAXIMUM_NESTING_DEPTH = 1000;

private static final String COMMA = ",";
private static final String L_PAREN = "(";
private static final String R_PAREN = ")";
Expand Down Expand Up @@ -284,7 +286,7 @@ public Geometry read(String wellKnownText) throws ParseException {
public Geometry read(Reader reader) throws ParseException {
StreamTokenizer tokenizer = createTokenizer(reader);
try {
return readGeometryTaggedText(tokenizer);
return readGeometryTaggedText(tokenizer, 0);
}
catch (IOException e) {
throw new ParseException(e.toString());
Expand Down Expand Up @@ -738,7 +740,7 @@ private static String tokenString(StreamTokenizer tokenizer)
*@throws IOException if an I/O error occurs
* @param tokenizer tokenizer over a stream of text in Well-known Text
*/
private Geometry readGeometryTaggedText(StreamTokenizer tokenizer) throws IOException, ParseException {
private Geometry readGeometryTaggedText(StreamTokenizer tokenizer, int nestingDepth) throws IOException, ParseException {
String type;

EnumSet<Ordinate> ordinateFlags = EnumSet.of(Ordinate.X, Ordinate.Y);
Expand All @@ -751,10 +753,11 @@ private Geometry readGeometryTaggedText(StreamTokenizer tokenizer) throws IOExce
} else if (type.endsWith(WKTConstants.M)) {
ordinateFlags.add(Ordinate.M);
}
return readGeometryTaggedText(tokenizer, type, ordinateFlags);
return readGeometryTaggedText(tokenizer, type, ordinateFlags, nestingDepth);
}

private Geometry readGeometryTaggedText(StreamTokenizer tokenizer, String type, EnumSet<Ordinate> ordinateFlags)
private Geometry readGeometryTaggedText(StreamTokenizer tokenizer, String type, EnumSet<Ordinate> ordinateFlags,
int nestingDepth)
throws IOException, ParseException {

if (ordinateFlags.size() == 2) {
Expand Down Expand Up @@ -796,7 +799,7 @@ else if (isTypeName(tokenizer, type, WKTConstants.MULTIPOLYGON)) {
return readMultiPolygonText(tokenizer, ordinateFlags);
}
else if (isTypeName(tokenizer, type, WKTConstants.GEOMETRYCOLLECTION)) {
return readGeometryCollectionText(tokenizer, ordinateFlags);
return readGeometryCollectionText(tokenizer, ordinateFlags, nestingDepth);
}
throw parseErrorWithLine(tokenizer, "Unknown geometry type: " + type);
}
Expand Down Expand Up @@ -1002,14 +1005,19 @@ private MultiPolygon readMultiPolygonText(StreamTokenizer tokenizer, EnumSet<Ord
* token was encountered
*@throws IOException if an I/O error occurs
*/
private GeometryCollection readGeometryCollectionText(StreamTokenizer tokenizer, EnumSet<Ordinate> ordinateFlags) throws IOException, ParseException {
private GeometryCollection readGeometryCollectionText(StreamTokenizer tokenizer, EnumSet<Ordinate> ordinateFlags,
int nestingDepth) throws IOException, ParseException {
if (nestingDepth >= MAXIMUM_NESTING_DEPTH) {
throw new ParseException("GeometryCollection nesting depth exceeds maximum of "
+ MAXIMUM_NESTING_DEPTH);
}
String nextToken = getNextEmptyOrOpener(tokenizer);
if (nextToken.equals(WKTConstants.EMPTY)) {
return geometryFactory.createGeometryCollection();
}
List<Geometry> geometries = new ArrayList<Geometry>();
do {
Geometry geometry = readGeometryTaggedText(tokenizer);
Geometry geometry = readGeometryTaggedText(tokenizer, nestingDepth + 1);
geometries.add(geometry);
nextToken = getNextCloserOrComma(tokenizer);
} while (nextToken.equals(COMMA));
Expand All @@ -1019,4 +1027,3 @@ private GeometryCollection readGeometryCollectionText(StreamTokenizer tokenizer,
}

}

Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
*/
public class WKBReaderTest extends TestCase
{
private static final int MAXIMUM_NESTING_DEPTH = 1000;

public static void main(String args[]) {
TestRunner.run(WKBReaderTest.class);
}
Expand Down Expand Up @@ -211,6 +213,15 @@ public void testInvalidWkbShouldBeReadable() throws ParseException {
assertEquals(2029, lastSubGeometry.getSRID());
}

public void testNestedGeometryCollection() throws ParseException
{
String wkb = "01010000000000000000000000000000000000000000";
for (int i = 0; i <= MAXIMUM_NESTING_DEPTH; i++) {
wkb = "010700000001000000" + wkb;
}
checkWKBParseException(wkb);
}

/**
* Tests WKB that requests a huge number of points.
* Not yet implemented satisfactorily.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
public class WKTReaderParseErrorTest
extends TestCase
{
private static final int MAXIMUM_NESTING_DEPTH = 1000;

public static void main(String args[]) {
TestRunner.run(WKTReaderParseErrorTest.class);
}
Expand Down Expand Up @@ -155,6 +157,15 @@ public void testMissingComponents() throws IOException
readWithParseException("GEOMETRYCOLLECTION ()");
readWithParseException("GEOMETRYCOLLECTION");
}

public void testNestedGeometryCollection() throws IOException
{
String wkt = "POINT (0 0)";
for (int i = 0; i <= MAXIMUM_NESTING_DEPTH; i++) {
wkt = "GEOMETRYCOLLECTION (" + wkt + ")";
}
readWithParseException(wkt);
}

public void testEmptyComponents() throws ParseException, IOException {
readWithInvalidException("POLYGON( EMPTY, (1 1,2 2,1 2,1 1))");
Expand Down Expand Up @@ -190,4 +201,3 @@ private void readWithInvalidException(String wkt)
fail();
}
}

Loading