aboutsummaryrefslogtreecommitdiff
path: root/lib/util.cpp
diff options
context:
space:
mode:
authorAndres Salomon <dilinger@queued.net>2021-01-18 04:00:14 -0500
committerAndres Salomon <dilinger@queued.net>2021-01-18 04:00:14 -0500
commit09eb39236666e81d5da014acea011dcd74d0999b (patch)
tree52876d96be71be1a39d5d935c1295a51995e8949 /lib/util.cpp
parentf1788ee27f33e9339334e0d79bde9a27d9ce2e44 (diff)
parenta4e78956f105875625b572d8b98459ffa86fafe5 (diff)
downloadlibquotient-09eb39236666e81d5da014acea011dcd74d0999b.tar.gz
libquotient-09eb39236666e81d5da014acea011dcd74d0999b.zip
Update upstream source from tag 'upstream/0.6.4'
Update to upstream version '0.6.4' with Debian dir aa8705fd74743e79c043bc9e3e425d5064404cfe
Diffstat (limited to 'lib/util.cpp')
-rw-r--r--lib/util.cpp177
1 files changed, 89 insertions, 88 deletions
diff --git a/lib/util.cpp b/lib/util.cpp
index 81862ab6..875d7522 100644
--- a/lib/util.cpp
+++ b/lib/util.cpp
@@ -13,153 +13,154 @@
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "util.h"
+#include <QtCore/QCryptographicHash>
+#include <QtCore/QDataStream>
+#include <QtCore/QDir>
#include <QtCore/QRegularExpression>
#include <QtCore/QStandardPaths>
-#include <QtCore/QDir>
#include <QtCore/QStringBuilder>
+#include <QtCore/QtEndian>
static const auto RegExpOptions =
QRegularExpression::CaseInsensitiveOption
- | QRegularExpression::OptimizeOnFirstUsageOption
+#if QT_VERSION < QT_VERSION_CHECK(5, 12, 0)
+ | QRegularExpression::OptimizeOnFirstUsageOption // Default since 5.12
+#endif
| QRegularExpression::UseUnicodePropertiesOption;
// Converts all that looks like a URL into HTML links
-static void linkifyUrls(QString& htmlEscapedText)
+void Quotient::linkifyUrls(QString& htmlEscapedText)
{
+ // Note: outer parentheses are a part of C++ raw string delimiters, not of
+ // the regex (see http://en.cppreference.com/w/cpp/language/string_literal).
+ // Note2: the next-outer parentheses are \N in the replacement.
+
+ // generic url:
// regexp is originally taken from Konsole (https://github.com/KDE/konsole)
- // full url:
// protocolname:// or www. followed by anything other than whitespaces,
// <, >, ' or ", and ends before whitespaces, <, >, ', ", ], !, ), :,
// comma or dot
- // Note: outer parentheses are a part of C++ raw string delimiters, not of
- // the regex (see http://en.cppreference.com/w/cpp/language/string_literal).
- // Note2: the next-outer parentheses are \N in the replacement.
- static const QRegularExpression FullUrlRegExp(QStringLiteral(
- R"(\b((www\.(?!\.)(?!(\w|\.|-)+@)|(https?|ftp|magnet)://)(&(?![lg]t;)|[^&\s<>'"])+(&(?![lg]t;)|[^&!,.\s<>'"\]):])))"
- ), RegExpOptions);
+ static const QRegularExpression FullUrlRegExp(
+ QStringLiteral(
+ R"(\b((www\.(?!\.)(?!(\w|\.|-)+@)|(https?|ftp|magnet|matrix):(//)?)(&(?![lg]t;)|[^&\s<>'"])+(&(?![lg]t;)|[^&!,.\s<>'"\]):])))"),
+ RegExpOptions);
// email address:
// [word chars, dots or dashes]@[word chars, dots or dashes].[word chars]
- static const QRegularExpression EmailAddressRegExp(QStringLiteral(
- R"(\b(mailto:)?((\w|\.|-)+@(\w|\.|-)+\.\w+\b))"
- ), RegExpOptions);
+ static const QRegularExpression EmailAddressRegExp(
+ QStringLiteral(R"(\b(mailto:)?((\w|\.|-)+@(\w|\.|-)+\.\w+\b))"),
+ RegExpOptions);
// An interim liberal implementation of
// https://matrix.org/docs/spec/appendices.html#identifier-grammar
- static const QRegularExpression MxIdRegExp(QStringLiteral(
- R"((^|[^<>/])([!#@][-a-z0-9_=#/.]{1,252}:(?:\w|\.|-)+\.\w+(?::\d{1,5})?))"
- ), RegExpOptions);
+ static const QRegularExpression MxIdRegExp(
+ QStringLiteral(
+ R"((^|[^<>/])([!#@][-a-z0-9_=#/.]{1,252}:(?:\w|\.|-)+\.\w+(?::\d{1,5})?))"),
+ RegExpOptions);
+ Q_ASSERT(FullUrlRegExp.isValid() && EmailAddressRegExp.isValid()
+ && MxIdRegExp.isValid());
// NOTE: htmlEscapedText is already HTML-escaped! No literal <,>,&,"
htmlEscapedText.replace(EmailAddressRegExp,
- QStringLiteral(R"(<a href="mailto:\2">\1\2</a>)"));
+ QStringLiteral(R"(<a href="mailto:\2">\1\2</a>)"));
htmlEscapedText.replace(FullUrlRegExp,
- QStringLiteral(R"(<a href="\1">\1</a>)"));
- htmlEscapedText.replace(MxIdRegExp,
- QStringLiteral(R"(\1<a href="https://matrix.to/#/\2">\2</a>)"));
+ QStringLiteral(R"(<a href="\1">\1</a>)"));
+ htmlEscapedText.replace(
+ MxIdRegExp,
+ QStringLiteral(R"(\1<a href="https://matrix.to/#/\2">\2</a>)"));
}
-QString QMatrixClient::sanitized(const QString& plainText)
+QString Quotient::sanitized(const QString& plainText)
{
auto text = plainText;
- text.remove(QChar(0x202e));
- text.remove(QChar(0x202d));
+ text.remove(QChar(0x202e)); // RLO
+ text.remove(QChar(0x202d)); // LRO
+ text.remove(QChar(0xfffc)); // Object replacement character
return text;
}
-QString QMatrixClient::prettyPrint(const QString& plainText)
+QString Quotient::prettyPrint(const QString& plainText)
{
- auto pt = QStringLiteral("<span style='white-space:pre-wrap'>") +
- plainText.toHtmlEscaped() + QStringLiteral("</span>");
- pt.replace('\n', QStringLiteral("<br/>"));
-
+ auto pt = plainText.toHtmlEscaped();
linkifyUrls(pt);
- return pt;
+ pt.replace('\n', QStringLiteral("<br/>"));
+ return QStringLiteral("<span style='white-space:pre-wrap'>") + pt
+ + QStringLiteral("</span>");
}
-QString QMatrixClient::cacheLocation(const QString& dirName)
+QString Quotient::cacheLocation(const QString& dirName)
{
const QString cachePath =
- QStandardPaths::writableLocation(QStandardPaths::CacheLocation)
- % '/' % dirName % '/';
+ QStandardPaths::writableLocation(QStandardPaths::CacheLocation) % '/'
+ % dirName % '/';
QDir dir;
if (!dir.exists(cachePath))
dir.mkpath(cachePath);
return cachePath;
}
+qreal Quotient::stringToHueF(const QString& s)
+{
+ Q_ASSERT(!s.isEmpty());
+ QByteArray hash = QCryptographicHash::hash(s.toUtf8(),
+ QCryptographicHash::Sha1);
+ QDataStream dataStream(hash.left(2));
+ dataStream.setByteOrder(QDataStream::LittleEndian);
+ quint16 hashValue;
+ dataStream >> hashValue;
+ const auto hueF = qreal(hashValue) / std::numeric_limits<quint16>::max();
+ Q_ASSERT((0 <= hueF) && (hueF <= 1));
+ return hueF;
+}
+
+static const auto ServerPartRegEx = QStringLiteral(
+ "(\\[[^][:blank:]]+\\]|[-[:alnum:].]+)" // Either IPv6 address or hostname/IPv4 address
+ "(?::(\\d{1,5}))?" // Optional port
+);
+
+QString Quotient::serverPart(const QString& mxId)
+{
+ static QString re = "^[@!#$+].*?:(" // Localpart and colon
+ % ServerPartRegEx % ")$";
+ static QRegularExpression parser(
+ re,
+ QRegularExpression::UseUnicodePropertiesOption); // Because Asian digits
+ Q_ASSERT(parser.isValid());
+ return parser.match(mxId).captured(1);
+}
+
// Tests for function_traits<>
-#ifdef Q_CC_CLANG
-#pragma clang diagnostic push
-#pragma ide diagnostic ignored "OCSimplifyInspection"
-#endif
-using namespace QMatrixClient;
+using namespace Quotient;
-int f();
-static_assert(std::is_same<fn_return_t<decltype(f)>, int>::value,
+int f_();
+static_assert(std::is_same<fn_return_t<decltype(f_)>, int>::value,
"Test fn_return_t<>");
-void f1(int);
-static_assert(function_traits<decltype(f1)>::arg_number == 1,
- "Test fn_arg_number");
-
-void f2(int, QString);
-static_assert(std::is_same<fn_arg_t<decltype(f2), 1>, QString>::value,
+void f1_(int, QString);
+static_assert(std::is_same<fn_arg_t<decltype(f1_), 1>, QString>::value,
"Test fn_arg_t<>");
-struct S { int mf(); };
-static_assert(is_callable_v<decltype(&S::mf)>, "Test member function");
-static_assert(returns<int, decltype(&S::mf)>(), "Test returns<> with member function");
-
-struct Fo { int operator()(); };
-static_assert(is_callable_v<Fo>, "Test is_callable<> with function object");
-static_assert(function_traits<Fo>::arg_number == 0, "Test function object");
+struct Fo {
+ int operator()();
+ static constexpr auto l = [] { return 0.0f; };
+};
static_assert(std::is_same<fn_return_t<Fo>, int>::value,
"Test return type of function object");
+static_assert(std::is_same<fn_return_t<decltype(Fo::l)>, float>::value,
+ "Test return type of lambda");
-struct Fo1 { void operator()(int); };
-static_assert(function_traits<Fo1>::arg_number == 1, "Test function object 1");
-static_assert(is_callable_v<Fo1>, "Test is_callable<> with function object 1");
+struct Fo1 {
+ void operator()(int);
+};
static_assert(std::is_same<fn_arg_t<Fo1>, int>(),
"Test fn_arg_t defaulting to first argument");
-#if (!defined(_MSC_VER) || _MSC_VER >= 1910)
-static auto l = [] { return 1; };
-static_assert(is_callable_v<decltype(l)>, "Test is_callable_v<> with lambda");
-static_assert(std::is_same<fn_return_t<decltype(l)>, int>::value,
- "Test fn_return_t<> with lambda");
-#endif
-
template <typename T>
-struct fn_object
-{
- static int smf(double) { return 0; }
-};
-template <>
-struct fn_object<QString>
-{
- void operator()(QString);
-};
-static_assert(is_callable_v<fn_object<QString>>, "Test function object");
-static_assert(returns<void, fn_object<QString>>(),
- "Test returns<> with function object");
-static_assert(!is_callable_v<fn_object<int>>, "Test non-function object");
-// FIXME: These two don't work
-//static_assert(is_callable_v<decltype(&fn_object<int>::smf)>,
-// "Test static member function");
-//static_assert(returns<int, decltype(&fn_object<int>::smf)>(),
-// "Test returns<> with static member function");
-
-template <typename T>
-QString ft(T&&) { return {}; }
+static QString ft(T&&);
static_assert(std::is_same<fn_arg_t<decltype(ft<QString>)>, QString&&>(),
"Test function templates");
-
-#ifdef Q_CC_CLANG
-#pragma clang diagnostic pop
-#endif