Skip to content
Permalink
Browse files
avoid code duplication of fromEncodedComponent_helper(QGIS)/qt_urlRec…
…odeByteArray(Qt) (#43842)
  • Loading branch information
3nids committed Jun 23, 2021
1 parent f50dd99 commit 55e20eb8003ed3e5806c7774c8c74559631e3f9e
@@ -10,6 +10,7 @@




%ModuleHeaderCode
#include <qgis.h>
%End
@@ -267,6 +267,7 @@ set(QGIS_CORE_SRCS
textrenderer/qgstextrendererutils.cpp
textrenderer/qgstextshadowsettings.cpp

fromencodedcomponenthelper.cpp
qgis.cpp
qgsabstractcontentcache.cpp
qgsabstractgeopdfexporter.cpp
@@ -870,6 +871,7 @@ set(QGIS_CORE_HDRS

../plugins/qgisplugin.h

fromencodedcomponenthelper.h
qgis.h
qgis_sip.h
qgsabstractcontentcache.h
@@ -0,0 +1,95 @@
/***************************************************************************
fromencodedcomponenthelper.h
-------------------
begin : 22.06.2021
copyright : (C) 2021 by Denis Rouzaud
email : denis@opengis.ch
***************************************************************************/

/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/

#include "fromencodedcomponenthelper.h"

#include <QString>

static 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;
}

/*!
\a ba contains an 8-bit form of the component and it might be
percent-encoded already. We can't use QString::fromUtf8 because it might
contain non-UTF8 sequences. We can't use QByteArray::toPercentEncoding
because it might already contain percent-encoded sequences. We can't use
qt_urlRecode because it needs UTF-16 input.
This method is named qt_urlRecodeByteArray in Qt's internals
*/
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() ) );
}




@@ -0,0 +1,49 @@
/***************************************************************************
fromencodedcomponenthelper.h
-------------------
begin : 22.06.2021
copyright : (C) 2021 by Denis Rouzaud
email : denis@opengis.ch
***************************************************************************/

/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/

#define SIP_NO_FILE

#include "qgis_core.h"

#include <QtEndian>


// 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];
}

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

/*!
\a ba contains an 8-bit form of the component and it might be
percent-encoded already. We can't use QString::fromUtf8 because it might
contain non-UTF8 sequences. We can't use QByteArray::toPercentEncoding
because it might already contain percent-encoded sequences. We can't use
qt_urlRecode because it needs UTF-16 input.
This method is named qt_urlRecodeByteArray in Qt's internals
*/
QString CORE_EXPORT fromEncodedComponent_helper( const QByteArray &ba );

@@ -344,3 +344,4 @@ bool qMapLessThanKey<QVariantList>( const QVariantList &key1, const QVariantList
return qgsVariantGreaterThan( key1, key2 ) && key1 != key2;
}
#endif

@@ -18,6 +18,7 @@
#ifndef QGIS_H
#define QGIS_H


#include <QMetaEnum>
#include <cfloat>
#include <memory>
@@ -18,11 +18,12 @@ email : hugo dot mercier at oslandia dot com
#include <QRegExp>
#include <QStringList>
#include <QUrlQuery>
#include <QtEndian>

#include "qgsvirtuallayerdefinition.h"
#include "qgsvectorlayer.h"
#include "qgsvectordataprovider.h"
#include "fromencodedcomponenthelper.h"


QgsVirtualLayerDefinition::QgsVirtualLayerDefinition( const QString &filePath )
: mFilePath( filePath )
@@ -174,82 +175,6 @@ 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 ) );
}

static 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;
@@ -19,13 +19,13 @@
#include "qgssettings.h"
#include "qgshelp.h"
#include "qgsgui.h"
#include "fromencodedcomponenthelper.h"

#include <QMessageBox>
#include <QUrl>
#include <QPushButton>
#include <QRegExp>
#include <QRegExpValidator>
#include <QtEndian>
#include <QUrlQuery>

QgsNewHttpConnection::QgsNewHttpConnection( QWidget *parent, ConnectionTypes types, const QString &baseKey, const QString &connectionName, QgsNewHttpConnection::Flags flags, Qt::WindowFlags fl )
@@ -345,82 +345,6 @@ void QgsNewHttpConnection::updateServiceSpecificSettings()
cbxWfsFeaturePaging->setChecked( pagingEnabled );
}

// 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() );

0 comments on commit 55e20eb

Please sign in to comment.