提交 9e9d4238 authored 作者: Evgenij Ryazanov's avatar Evgenij Ryazanov

Forbid non-finite values in GEOMETRY, they are illegal in WKT

上级 78018191
......@@ -15,6 +15,8 @@ import static org.h2.util.geometry.GeometryUtils.MULTI_POINT;
import static org.h2.util.geometry.GeometryUtils.MULTI_POLYGON;
import static org.h2.util.geometry.GeometryUtils.POINT;
import static org.h2.util.geometry.GeometryUtils.POLYGON;
import static org.h2.util.geometry.GeometryUtils.checkFinite;
import static org.h2.util.geometry.GeometryUtils.toCanonicalDouble;
import java.io.ByteArrayOutputStream;
......@@ -39,6 +41,8 @@ public final class EWKBUtils {
private final byte[] buf = new byte[8];
private int type;
private int level;
/**
......@@ -84,6 +88,7 @@ public final class EWKBUtils {
}
private void writeHeader(int type, int srid) {
this.type = type;
switch (dimensionSystem) {
case DIMENSION_SYSTEM_XYZ:
type |= EWKB_Z;
......@@ -120,13 +125,19 @@ public final class EWKBUtils {
@Override
protected void addCoordinate(double x, double y, double z, double m, int index, int total) {
boolean check = type != POINT || !Double.isNaN(x) || !Double.isNaN(y) || !Double.isNaN(z)
|| !Double.isNaN(m);
if (check) {
checkFinite(x);
checkFinite(y);
}
writeDouble(x);
writeDouble(y);
if ((dimensionSystem & DIMENSION_SYSTEM_XYZ) != 0) {
writeDouble(z);
writeDouble(check ? checkFinite(z) : z);
}
if ((dimensionSystem & DIMENSION_SYSTEM_XYM) != 0) {
writeDouble(m);
writeDouble(check ? checkFinite(m) : m);
}
}
......@@ -434,18 +445,6 @@ public final class EWKBUtils {
index, total);
}
/**
* Normalizes all NaNs into single type on NaN and negative zero to positive
* zero.
*
* @param d
* double value
* @return normalized value
*/
static double toCanonicalDouble(double d) {
return Double.isNaN(d) ? Double.NaN : d == 0d ? 0d : d;
}
private EWKBUtils() {
}
......
......@@ -206,7 +206,7 @@ public final class EWKTUtils {
}
private void writeDouble(double v) {
String s = Double.toString(v);
String s = Double.toString(GeometryUtils.checkFinite(v));
if (s.endsWith(".0")) {
output.append(s, 0, s.length() - 2);
} else {
......@@ -354,8 +354,6 @@ public final class EWKTUtils {
case '+':
case '-':
case '.':
case 'N':
case 'n':
return true;
default:
return false;
......@@ -370,12 +368,8 @@ public final class EWKTUtils {
case '+':
case '-':
case '.':
case 'A':
case 'E':
case 'N':
case 'a':
case 'e':
case 'n':
return true;
default:
return false;
......
......@@ -191,6 +191,7 @@ public final class GeometryUtils {
@Override
protected void addCoordinate(double x, double y, double z, double m, int index, int total) {
// POINT EMPTY has NaNs
if (enabled && !Double.isNaN(x) && !Double.isNaN(y)) {
if (!set) {
minX = maxX = x;
......@@ -318,6 +319,7 @@ public final class GeometryUtils {
if (!hasM && !Double.isNaN(m)) {
hasM = true;
}
// POINT EMPTY has NaNs
if (enabled && !Double.isNaN(x) && !Double.isNaN(y)) {
if (!set) {
minX = maxX = x;
......@@ -584,6 +586,14 @@ public final class GeometryUtils {
return Double.isNaN(d) ? Double.NaN : d == 0d ? 0d : d;
}
static double checkFinite(double d) {
// Do not push this negation down, it will break NaN rejection
if (!(Math.abs(d) <= Double.MAX_VALUE)) {
throw new IllegalArgumentException();
}
return d;
}
private GeometryUtils() {
}
......
......@@ -6,6 +6,7 @@
package org.h2.util.geometry;
import static org.h2.util.geometry.GeometryUtils.DIMENSION_SYSTEM_XYM;
import static org.h2.util.geometry.GeometryUtils.DIMENSION_SYSTEM_XYZ;
import static org.h2.util.geometry.GeometryUtils.GEOMETRY_COLLECTION;
import static org.h2.util.geometry.GeometryUtils.LINE_STRING;
import static org.h2.util.geometry.GeometryUtils.M;
......@@ -17,6 +18,7 @@ import static org.h2.util.geometry.GeometryUtils.POLYGON;
import static org.h2.util.geometry.GeometryUtils.X;
import static org.h2.util.geometry.GeometryUtils.Y;
import static org.h2.util.geometry.GeometryUtils.Z;
import static org.h2.util.geometry.GeometryUtils.checkFinite;
import static org.h2.util.geometry.GeometryUtils.toCanonicalDouble;
import java.io.ByteArrayOutputStream;
......@@ -154,11 +156,12 @@ public final class JTSUtils {
return;
}
CoordinateSequence coordinates = innerOffset < 0 ? this.coordinates : innerCoordinates[innerOffset];
coordinates.setOrdinate(index, X, x);
coordinates.setOrdinate(index, Y, y);
coordinates.setOrdinate(index, Z, z);
coordinates.setOrdinate(index, X, checkFinite(x));
coordinates.setOrdinate(index, Y, checkFinite(y));
coordinates.setOrdinate(index, Z,
(dimensionSystem & DIMENSION_SYSTEM_XYZ) != 0 ? checkFinite(z) : Double.NaN);
if ((dimensionSystem & DIMENSION_SYSTEM_XYM) != 0) {
coordinates.setOrdinate(index, M, m);
coordinates.setOrdinate(index, M, checkFinite(m));
}
}
......
......@@ -5,6 +5,9 @@
*/
package org.h2.test.unit;
import static org.h2.util.geometry.GeometryUtils.DIMENSION_SYSTEM_XY;
import static org.h2.util.geometry.GeometryUtils.DIMENSION_SYSTEM_XYM;
import static org.h2.util.geometry.GeometryUtils.DIMENSION_SYSTEM_XYZ;
import static org.h2.util.geometry.GeometryUtils.M;
import static org.h2.util.geometry.GeometryUtils.MAX_X;
import static org.h2.util.geometry.GeometryUtils.MAX_Y;
......@@ -14,16 +17,21 @@ import static org.h2.util.geometry.GeometryUtils.X;
import static org.h2.util.geometry.GeometryUtils.Y;
import static org.h2.util.geometry.GeometryUtils.Z;
import java.io.ByteArrayOutputStream;
import java.util.Random;
import org.h2.test.TestBase;
import org.h2.util.StringUtils;
import org.h2.util.geometry.EWKBUtils;
import org.h2.util.geometry.EWKBUtils.EWKBTarget;
import org.h2.util.geometry.EWKTUtils;
import org.h2.util.geometry.EWKTUtils.EWKTTarget;
import org.h2.util.geometry.GeometryUtils;
import org.h2.util.geometry.GeometryUtils.DimensionSystemTarget;
import org.h2.util.geometry.GeometryUtils.EnvelopeAndDimensionSystemTarget;
import org.h2.util.geometry.GeometryUtils.Target;
import org.h2.util.geometry.JTSUtils;
import org.h2.util.geometry.JTSUtils.GeometryTarget;
import org.locationtech.jts.geom.CoordinateSequence;
import org.locationtech.jts.geom.Envelope;
import org.locationtech.jts.geom.Geometry;
......@@ -39,6 +47,29 @@ import org.locationtech.jts.io.WKTWriter;
*/
public class TestGeometryUtils extends TestBase {
private static final byte[][] NON_FINITE = { //
// XY
StringUtils.convertHexToBytes("0000000001" //
+ "0000000000000000" //
+ "7ff8000000000000"), //
// XY
StringUtils.convertHexToBytes("0000000001" //
+ "7ff8000000000000" //
+ "0000000000000000"), //
// XYZ
StringUtils.convertHexToBytes("0080000001" //
+ "0000000000000000" //
+ "0000000000000000" //
+ "7ff8000000000000"), //
// XYM
StringUtils.convertHexToBytes("0040000001" //
+ "0000000000000000" //
+ "0000000000000000" //
+ "7ff8000000000000") };
private static final int[] NON_FINITE_DIMENSIONS = { DIMENSION_SYSTEM_XY, DIMENSION_SYSTEM_XY, DIMENSION_SYSTEM_XYZ,
DIMENSION_SYSTEM_XYM };
/**
* Run just this test.
*
......@@ -61,14 +92,16 @@ public class TestGeometryUtils extends TestBase {
testEmptyPoint();
testDimensionM();
testDimensionZM();
testFiniteOnly();
testSRID();
testIntersectionAndUnion();
}
private void testPoint() throws Exception {
testGeometry("POINT (1 2)", 2);
testGeometry("POINT (-1.3 NaN)", 2);
testGeometry("POINT (-1E32 NaN)", "POINT (-1E32 NaN)", "POINT (-100000000000000000000000000000000 NaN)", 2);
testGeometry("POINT (-1.3 15)", 2);
testGeometry("POINT (-1E32 1.000001)", "POINT (-1E32 1.000001)",
"POINT (-100000000000000000000000000000000 1.000001)", 2);
testGeometry("POINT Z (2.7 -3 34)", 3);
}
......@@ -76,7 +109,6 @@ public class TestGeometryUtils extends TestBase {
testGeometry("LINESTRING (-1 -2, 10 1, 2 20)", 2);
testGeometry("LINESTRING (1 2, 1 3)", 2);
testGeometry("LINESTRING (1 2, 2 2)", 2);
testGeometry("LINESTRING (1 NaN, 2 NaN)", 2);
testGeometry("LINESTRING EMPTY", 2);
testGeometry("LINESTRING Z (-1 -2 -3, 10 15.7 3)", 3);
}
......@@ -227,6 +259,27 @@ public class TestGeometryUtils extends TestBase {
testDimensions(GeometryUtils.DIMENSION_SYSTEM_XYZM, ewkb);
}
private void testFiniteOnly() {
for (int i = 0; i < NON_FINITE.length; i++) {
testFiniteOnly(NON_FINITE[i], new EWKBTarget(new ByteArrayOutputStream(), NON_FINITE_DIMENSIONS[i]));
}
for (int i = 0; i < NON_FINITE.length; i++) {
testFiniteOnly(NON_FINITE[i], new EWKTTarget(new StringBuilder(), NON_FINITE_DIMENSIONS[i]));
}
for (int i = 0; i < NON_FINITE.length; i++) {
testFiniteOnly(NON_FINITE[i], new GeometryTarget(NON_FINITE_DIMENSIONS[i]));
}
}
private void testFiniteOnly(byte[] ewkb, Target target) {
try {
EWKBUtils.parseEWKB(ewkb, target);
fail(target.getClass().getName() + ' ' + StringUtils.convertBytesToHex(ewkb));
} catch (IllegalArgumentException e) {
// Expected
}
}
private void testSRID() throws Exception {
byte[] ewkb = EWKTUtils.ewkt2ewkb("SRID=10;GEOMETRYCOLLECTION (POINT (1 2))");
assertEquals(StringUtils.convertHexToBytes(""
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论