Skip to content
Permalink
Browse files

Some very ugly ports away from deprecated Qt methods

There's no straightforward way to avoid the deprecated methods here, so we have to
copy Qt5's compatibility helpers. Ugly, but unavoidable.
  • Loading branch information
nyalldawson committed Feb 6, 2020
1 parent ff839a4 commit 104a590592f986374b142c3008181622ba834e56
Showing with 188 additions and 25 deletions.
  1. +98 −15 src/core/qgsvirtuallayerdefinition.cpp
  2. +90 −10 src/gui/qgsnewhttpconnection.cpp
@@ -168,59 +168,142 @@ QgsVirtualLayerDefinition QgsVirtualLayerDefinition::fromUrl( const QUrl &url )
return def;
}

// Mega ewwww. all this is taken from Qt's QUrl::addEncodedQueryItem compatibility helper.
// (I can't see any way to port the below code to NOT require this without breaking
// existing projects.)

inline char toHexUpper( uint value ) noexcept
{
return "0123456789ABCDEF"[value & 0xF];
}

static inline ushort encodeNibble( ushort c )
{
return ushort( toHexUpper( c ) );
}

bool qt_is_ascii( const char *&ptr, const char *end ) noexcept
{
while ( ptr + 4 <= end )
{
quint32 data = qFromUnaligned<quint32>( ptr );
if ( data &= 0x80808080U )
{
#if Q_BYTE_ORDER == Q_BIG_ENDIAN
uint idx = qCountLeadingZeroBits( data );
#else
uint idx = qCountTrailingZeroBits( data );
#endif
ptr += idx / 8;
return false;
}
ptr += 4;
}
while ( ptr != end )
{
if ( quint8( *ptr ) & 0x80 )
return false;
++ptr;
}
return true;
}

QString fromEncodedComponent_helper( const QByteArray &ba )
{
if ( ba.isNull() )
return QString();
// scan ba for anything above or equal to 0x80
// control points below 0x20 are fine in QString
const char *in = ba.constData();
const char *const end = ba.constEnd();
if ( qt_is_ascii( in, end ) )
{
// no non-ASCII found, we're safe to convert to QString
return QString::fromLatin1( ba, ba.size() );
}
// we found something that we need to encode
QByteArray intermediate = ba;
intermediate.resize( ba.size() * 3 - ( in - ba.constData() ) );
uchar *out = reinterpret_cast<uchar *>( intermediate.data() + ( in - ba.constData() ) );
for ( ; in < end; ++in )
{
if ( *in & 0x80 )
{
// encode
*out++ = '%';
*out++ = encodeNibble( uchar( *in ) >> 4 );
*out++ = encodeNibble( uchar( *in ) & 0xf );
}
else
{
// keep
*out++ = uchar( *in );
}
}
// now it's safe to call fromLatin1
return QString::fromLatin1( intermediate, out - reinterpret_cast<uchar *>( intermediate.data() ) );
}

QUrl QgsVirtualLayerDefinition::toUrl() const
{
QUrl url;
if ( !filePath().isEmpty() )
url = QUrl::fromLocalFile( filePath() );

QUrlQuery urlQuery( url );

const auto constSourceLayers = sourceLayers();
for ( const QgsVirtualLayerDefinition::SourceLayer &l : constSourceLayers )
{
if ( l.isReferenced() )
url.addQueryItem( QStringLiteral( "layer_ref" ), QStringLiteral( "%1:%2" ).arg( l.reference(), l.name() ) );
urlQuery.addQueryItem( QStringLiteral( "layer_ref" ), QStringLiteral( "%1:%2" ).arg( l.reference(), l.name() ) );
else
url.addEncodedQueryItem( "layer", QStringLiteral( "%1:%4:%2:%3" ) // the order is important, since the 4th argument may contain '%2' as well
.arg( l.provider(),
QString( QUrl::toPercentEncoding( l.name() ) ),
l.encoding(),
QString( QUrl::toPercentEncoding( l.source() ) ) ).toUtf8() );
// if you can find a way to port this away from fromEncodedComponent_helper without breaking existing projects,
// please do so... this is GROSS!
urlQuery.addQueryItem( fromEncodedComponent_helper( "layer" ),
fromEncodedComponent_helper( QStringLiteral( "%1:%4:%2:%3" ) // the order is important, since the 4th argument may contain '%2' as well
.arg( l.provider(),
QString( QUrl::toPercentEncoding( l.name() ) ),
l.encoding(),
QString( QUrl::toPercentEncoding( l.source() ) ) ).toUtf8() ) );
}

if ( !query().isEmpty() )
{
url.addQueryItem( QStringLiteral( "query" ), query() );
urlQuery.addQueryItem( QStringLiteral( "query" ), query() );
}

if ( !uid().isEmpty() )
url.addQueryItem( QStringLiteral( "uid" ), uid() );
urlQuery.addQueryItem( QStringLiteral( "uid" ), uid() );

if ( geometryWkbType() == QgsWkbTypes::NoGeometry )
url.addQueryItem( QStringLiteral( "nogeometry" ), QString() );
urlQuery.addQueryItem( QStringLiteral( "nogeometry" ), QString() );
else if ( !geometryField().isEmpty() )
{
if ( hasDefinedGeometry() )
url.addQueryItem( QStringLiteral( "geometry" ), QStringLiteral( "%1:%2:%3" ).arg( geometryField() ). arg( geometryWkbType() ).arg( geometrySrid() ).toUtf8() );
urlQuery.addQueryItem( QStringLiteral( "geometry" ), QStringLiteral( "%1:%2:%3" ).arg( geometryField() ). arg( geometryWkbType() ).arg( geometrySrid() ).toUtf8() );
else
url.addQueryItem( QStringLiteral( "geometry" ), geometryField() );
urlQuery.addQueryItem( QStringLiteral( "geometry" ), geometryField() );
}

const auto constFields = fields();
for ( const QgsField &f : constFields )
{
if ( f.type() == QVariant::Int )
url.addQueryItem( QStringLiteral( "field" ), f.name() + ":int" );
urlQuery.addQueryItem( QStringLiteral( "field" ), f.name() + ":int" );
else if ( f.type() == QVariant::Double )
url.addQueryItem( QStringLiteral( "field" ), f.name() + ":real" );
urlQuery.addQueryItem( QStringLiteral( "field" ), f.name() + ":real" );
else if ( f.type() == QVariant::String )
url.addQueryItem( QStringLiteral( "field" ), f.name() + ":text" );
urlQuery.addQueryItem( QStringLiteral( "field" ), f.name() + ":text" );
}

if ( isLazy() )
{
url.addQueryItem( QStringLiteral( "lazy" ), QString() );
urlQuery.addQueryItem( QStringLiteral( "lazy" ), QString() );
}

url.setQuery( urlQuery );

return url;
}

@@ -337,29 +337,109 @@ void QgsNewHttpConnection::updateServiceSpecificSettings()
cbxWfsFeaturePaging->setChecked( pagingEnabled );
}

QUrl QgsNewHttpConnection::urlTrimmed() const


// Mega ewwww. all this is taken from Qt's QUrl::setEncodedPath compatibility helper.
// (I can't see any way to port the below code to NOT require this).

inline char toHexUpper( uint value ) noexcept
{
return "0123456789ABCDEF"[value & 0xF];
}

static inline ushort encodeNibble( ushort c )
{
return ushort( toHexUpper( c ) );
}

bool qt_is_ascii( const char *&ptr, const char *end ) noexcept
{
while ( ptr + 4 <= end )
{
quint32 data = qFromUnaligned<quint32>( ptr );
if ( data &= 0x80808080U )
{
#if Q_BYTE_ORDER == Q_BIG_ENDIAN
uint idx = qCountLeadingZeroBits( data );
#else
uint idx = qCountTrailingZeroBits( data );
#endif
ptr += idx / 8;
return false;
}
ptr += 4;
}
while ( ptr != end )
{
if ( quint8( *ptr ) & 0x80 )
return false;
++ptr;
}
return true;
}

QString fromEncodedComponent_helper( const QByteArray &ba )
{
if ( ba.isNull() )
return QString();
// scan ba for anything above or equal to 0x80
// control points below 0x20 are fine in QString
const char *in = ba.constData();
const char *const end = ba.constEnd();
if ( qt_is_ascii( in, end ) )
{
// no non-ASCII found, we're safe to convert to QString
return QString::fromLatin1( ba, ba.size() );
}
// we found something that we need to encode
QByteArray intermediate = ba;
intermediate.resize( ba.size() * 3 - ( in - ba.constData() ) );
uchar *out = reinterpret_cast<uchar *>( intermediate.data() + ( in - ba.constData() ) );
for ( ; in < end; ++in )
{
if ( *in & 0x80 )
{
// encode
*out++ = '%';
*out++ = encodeNibble( uchar( *in ) >> 4 );
*out++ = encodeNibble( uchar( *in ) & 0xf );
}
else
{
// keep
*out++ = uchar( *in );
}
}
// now it's safe to call fromLatin1
return QString::fromLatin1( intermediate, out - reinterpret_cast<uchar *>( intermediate.data() ) );
}


QUrl QgsNewHttpConnection::urlTrimmed() const
{
QUrl url( txtUrl->text().trimmed() );
const QList< QPair<QByteArray, QByteArray> > &items = url.encodedQueryItems();
QHash< QString, QPair<QByteArray, QByteArray> > params;
for ( QList< QPair<QByteArray, QByteArray> >::const_iterator it = items.constBegin(); it != items.constEnd(); ++it )
QUrlQuery query( url );
const QList<QPair<QString, QString> > items = query.queryItems( QUrl::FullyEncoded );
QHash< QString, QPair<QString, QString> > params;
for ( const QPair<QString, QString> &it : items )
{
params.insert( QString( it->first ).toUpper(), *it );
params.insert( it.first.toUpper(), it );
}

if ( params[QStringLiteral( "SERVICE" )].second.toUpper() == "WMS" ||
params[QStringLiteral( "SERVICE" )].second.toUpper() == "WFS" ||
params[QStringLiteral( "SERVICE" )].second.toUpper() == "WCS" )
{
url.removeEncodedQueryItem( params[QStringLiteral( "SERVICE" )].first );
url.removeEncodedQueryItem( params[QStringLiteral( "REQUEST" )].first );
url.removeEncodedQueryItem( params[QStringLiteral( "FORMAT" )].first );
query.removeQueryItem( params.value( QStringLiteral( "SERVICE" ) ).first );
query.removeQueryItem( params.value( QStringLiteral( "REQUEST" ) ).first );
query.removeQueryItem( params.value( QStringLiteral( "FORMAT" ) ).first );
}

if ( url.encodedPath().isEmpty() )
url.setQuery( query );

if ( url.path( QUrl::FullyEncoded ).isEmpty() )
{
url.setEncodedPath( "/" );
url.setPath( fromEncodedComponent_helper( "/" ) );
}
return url;
}

0 comments on commit 104a590

Please sign in to comment.
You can’t perform that action at this time.