Skip to content

Commit

Permalink
Accept any whitespace delimiters when parsing WKT (fix #16217)
Browse files Browse the repository at this point in the history
  • Loading branch information
nyalldawson committed Feb 23, 2017
1 parent b95eb07 commit b29a8d0
Show file tree
Hide file tree
Showing 6 changed files with 59 additions and 20 deletions.
2 changes: 1 addition & 1 deletion src/core/geometry/qgscompoundcurve.cpp
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ bool QgsCompoundCurve::fromWkt( const QString& wkt )
return false;
mWkbType = parts.first;

QString defaultChildWkbType = QStringLiteral( "LineString%1%2" ).arg( is3D() ? "Z" : "", isMeasure() ? "M" : "" );
QString defaultChildWkbType = QStringLiteral( "LineString%1%2" ).arg( is3D() ? "Z" : QString(), isMeasure() ? "M" : QString() );

Q_FOREACH ( const QString& childWkt, QgsGeometryUtils::wktGetChildBlocks( parts.second, defaultChildWkbType ) )
{
Expand Down
2 changes: 1 addition & 1 deletion src/core/geometry/qgscurvepolygon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ bool QgsCurvePolygon::fromWkt( const QString& wkt )

mWkbType = parts.first;

QString defaultChildWkbType = QStringLiteral( "LineString%1%2" ).arg( is3D() ? "Z" : "", isMeasure() ? "M" : "" );
QString defaultChildWkbType = QStringLiteral( "LineString%1%2" ).arg( is3D() ? "Z" : QString(), isMeasure() ? "M" : QString() );

Q_FOREACH ( const QString& childWkt, QgsGeometryUtils::wktGetChildBlocks( parts.second, defaultChildWkbType ) )
{
Expand Down
25 changes: 13 additions & 12 deletions src/core/geometry/qgsgeometryfactory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,52 +73,53 @@ QgsAbstractGeometry* QgsGeometryFactory::geomFromWkb( QgsConstWkbPtr& wkbPtr )

QgsAbstractGeometry* QgsGeometryFactory::geomFromWkt( const QString& text )
{
QString trimmed = text.trimmed();
QgsAbstractGeometry* geom = nullptr;
if ( text.startsWith( QLatin1String( "Point" ), Qt::CaseInsensitive ) )
if ( trimmed.startsWith( QLatin1String( "Point" ), Qt::CaseInsensitive ) )
{
geom = new QgsPointV2();
}
else if ( text.startsWith( QLatin1String( "LineString" ), Qt::CaseInsensitive ) )
else if ( trimmed.startsWith( QLatin1String( "LineString" ), Qt::CaseInsensitive ) )
{
geom = new QgsLineString();
}
else if ( text.startsWith( QLatin1String( "CircularString" ), Qt::CaseInsensitive ) )
else if ( trimmed.startsWith( QLatin1String( "CircularString" ), Qt::CaseInsensitive ) )
{
geom = new QgsCircularString();
}
else if ( text.startsWith( QLatin1String( "CompoundCurve" ) , Qt::CaseInsensitive ) )
else if ( trimmed.startsWith( QLatin1String( "CompoundCurve" ) , Qt::CaseInsensitive ) )
{
geom = new QgsCompoundCurve();
}
else if ( text.startsWith( QLatin1String( "Polygon" ), Qt::CaseInsensitive ) )
else if ( trimmed.startsWith( QLatin1String( "Polygon" ), Qt::CaseInsensitive ) )
{
geom = new QgsPolygonV2();
}
else if ( text.startsWith( QLatin1String( "CurvePolygon" ), Qt::CaseInsensitive ) )
else if ( trimmed.startsWith( QLatin1String( "CurvePolygon" ), Qt::CaseInsensitive ) )
{
geom = new QgsCurvePolygon();
}
else if ( text.startsWith( QLatin1String( "MultiPoint" ), Qt::CaseInsensitive ) )
else if ( trimmed.startsWith( QLatin1String( "MultiPoint" ), Qt::CaseInsensitive ) )
{
geom = new QgsMultiPointV2();
}
else if ( text.startsWith( QLatin1String( "MultiCurve" ), Qt::CaseInsensitive ) )
else if ( trimmed.startsWith( QLatin1String( "MultiCurve" ), Qt::CaseInsensitive ) )
{
geom = new QgsMultiCurve();
}
else if ( text.startsWith( QLatin1String( "MultiLineString" ), Qt::CaseInsensitive ) )
else if ( trimmed.startsWith( QLatin1String( "MultiLineString" ), Qt::CaseInsensitive ) )
{
geom = new QgsMultiLineString();
}
else if ( text.startsWith( QLatin1String( "MultiSurface" ), Qt::CaseInsensitive ) )
else if ( trimmed.startsWith( QLatin1String( "MultiSurface" ), Qt::CaseInsensitive ) )
{
geom = new QgsMultiSurface();
}
else if ( text.startsWith( QLatin1String( "MultiPolygon" ), Qt::CaseInsensitive ) )
else if ( trimmed.startsWith( QLatin1String( "MultiPolygon" ), Qt::CaseInsensitive ) )
{
geom = new QgsMultiPolygonV2();
}
else if ( text.startsWith( QLatin1String( "GeometryCollection" ), Qt::CaseInsensitive ) )
else if ( trimmed.startsWith( QLatin1String( "GeometryCollection" ), Qt::CaseInsensitive ) )
{
geom = new QgsGeometryCollection();
}
Expand Down
14 changes: 9 additions & 5 deletions src/core/geometry/qgsgeometryutils.cpp
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ email : marco.hugentobler at sourcepole dot com

#include <QStringList>
#include <QVector>
#include <QRegularExpression>

QList<QgsLineString*> QgsGeometryUtils::extractLineStrings( const QgsAbstractGeometry* geom )
{
Expand Down Expand Up @@ -602,9 +603,10 @@ QgsPointSequence QgsGeometryUtils::pointsFromWKT( const QString &wktCoordinateLi
//first scan through for extra unexpected dimensions
bool foundZ = false;
bool foundM = false;
QRegularExpression rx( "\\s" );
Q_FOREACH ( const QString& pointCoordinates, coordList )
{
QStringList coordinates = pointCoordinates.split( ' ', QString::SkipEmptyParts );
QStringList coordinates = pointCoordinates.split( rx, QString::SkipEmptyParts );
if ( coordinates.size() == 3 && !foundZ && !foundM && !is3D && !isMeasure )
{
// 3 dimensional coordinates, but not specifically marked as such. We allow this
Expand All @@ -622,7 +624,7 @@ QgsPointSequence QgsGeometryUtils::pointsFromWKT( const QString &wktCoordinateLi

Q_FOREACH ( const QString& pointCoordinates, coordList )
{
QStringList coordinates = pointCoordinates.split( ' ', QString::SkipEmptyParts );
QStringList coordinates = pointCoordinates.split( rx, QString::SkipEmptyParts );
if ( coordinates.size() < dim )
continue;

Expand Down Expand Up @@ -764,8 +766,10 @@ QPair<QgsWkbTypes::Type, QString> QgsGeometryUtils::wktReadBlock( const QString
{
QgsWkbTypes::Type wkbType = QgsWkbTypes::parseType( wkt );

QRegExp cooRegEx( "^[^\\(]*\\((.*)\\)[^\\)]*$" );
QString contents = cooRegEx.indexIn( wkt ) >= 0 ? cooRegEx.cap( 1 ) : QString();
QRegularExpression cooRegEx( "^[^\\(]*\\((.*)\\)[^\\)]*$" );
cooRegEx.setPatternOptions( QRegularExpression::DotMatchesEverythingOption );
QRegularExpressionMatch match = cooRegEx.match( wkt );
QString contents = match.hasMatch() ? match.captured( 1 ) : QString();
return qMakePair( wkbType, contents );
}

Expand All @@ -776,7 +780,7 @@ QStringList QgsGeometryUtils::wktGetChildBlocks( const QString &wkt, const QStri
QStringList blocks;
for ( int i = 0, n = wkt.length(); i < n; ++i )
{
if ( wkt[i].isSpace() && level == 0 )
if (( wkt[i].isSpace() || wkt[i] == '\n' || wkt[i] == '\t' ) && level == 0 )
continue;

if ( wkt[i] == ',' && level == 0 )
Expand Down
4 changes: 3 additions & 1 deletion src/core/geometry/qgspointv2.cpp
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "qgsmaptopixel.h"
#include "qgswkbptr.h"
#include <QPainter>
#include <QRegularExpression>

/***************************************************************************
* This class is considered CRITICAL and any change MUST be accompanied with
Expand Down Expand Up @@ -134,7 +135,8 @@ bool QgsPointV2::fromWkt( const QString& wkt )
return false;
mWkbType = parts.first;

QStringList coordinates = parts.second.split( ' ', QString::SkipEmptyParts );
QRegularExpression rx( "\\s" );
QStringList coordinates = parts.second.split( rx, QString::SkipEmptyParts );
if ( coordinates.size() < 2 )
{
clear();
Expand Down
32 changes: 32 additions & 0 deletions tests/src/core/testqgsgeometryimport.cpp
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ class TestQgsGeometryImport: public QObject
void linestringGeos_data();
void linestringGeos();

void delimiters_data();
void delimiters();

private:
bool compareLineStrings( const QgsPolyline& polyline, QVariantList& line );
};
Expand Down Expand Up @@ -222,6 +225,7 @@ void TestQgsGeometryImport::linestringGeos()
QVERIFY( compareLineStrings( polyline, line ) );
}


bool TestQgsGeometryImport::compareLineStrings( const QgsPolyline& polyline, QVariantList& line )
{
bool sizeEqual = ( polyline.size() == line.size() );
Expand All @@ -242,5 +246,33 @@ bool TestQgsGeometryImport::compareLineStrings( const QgsPolyline& polyline, QVa
return true;
}


void TestQgsGeometryImport::delimiters_data()
{
QTest::addColumn<QString>( "input" );
QTest::addColumn<QString>( "expected" );
QTest::newRow( "tab delimiter" ) << QString( "POINT (180398\t5459331)" ) << QString( "Point (180398 5459331)" );
QTest::newRow( "newline" ) << QString( "POINT\n(1\n3)" ) << QString( "Point (1 3)" );
QTest::newRow( "tab and newline" ) << QString( "POINT\t\n(1\t\n3)" ) << QString( "Point (1 3)" );
QTest::newRow( "tab, newline and space" ) << QString( "POINT\n (1\t\n 3)" ) << QString( "Point (1 3)" );

QTest::newRow( "tab delimiter" ) << QString( "LINESTRING\t(30\t10,\t10\t30,\t40\t40)" ) << QString( "LineString (30 10, 10 30, 40 40)" );
QTest::newRow( "newline delimiter" ) << QString( "LINESTRING\n(30\n10,\n10\n30,\n40\n40)" ) << QString( "LineString (30 10, 10 30, 40 40)" );
QTest::newRow( "mixed delimiter" ) << QString( "LINESTRING\n(30\t10, 10\t30,\n40\t40)" ) << QString( "LineString (30 10, 10 30, 40 40)" );

QTest::newRow( "tab delimiter" ) << QString( "Polygon\t(\t(30\t10,\t10\t30,\t40\t40,30\t10)\t)" ) << QString( "Polygon ((30 10, 10 30, 40 40, 30 10))" );
QTest::newRow( "newline delimiter" ) << QString( "\nPolygon\n(\n(30\n10,\n10\n30,\n40\n40,30\n10)\n)\n" ) << QString( "Polygon ((30 10, 10 30, 40 40, 30 10))" );
QTest::newRow( "mixed delimiter" ) << QString( " Polygon (\t(30\n10,\t10\n30,\t40 40,30\n10)\t)\n" ) << QString( "Polygon ((30 10, 10 30, 40 40, 30 10))" );
}

void TestQgsGeometryImport::delimiters()
{
QFETCH( QString, input );
QFETCH( QString, expected );

QgsGeometry gInput = QgsGeometry::fromWkt( input );
QCOMPARE( gInput.exportToWkt(), expected );
}

QGSTEST_MAIN( TestQgsGeometryImport )
#include "testqgsgeometryimport.moc"

0 comments on commit b29a8d0

Please sign in to comment.