21 #include "stringfilters.h"
25 #include <QtCore/QRegularExpression>
26 #include <QtCore/QVariant>
27 #include <QtCore/QJsonArray>
28 #include <QtCore/QJsonObject>
29 #include <QtCore/QJsonDocument>
33 bool autoescape)
const
39 .replace(QLatin1Char(
'\\'), QStringLiteral(
"\\\\"))
41 .replace(QLatin1Char(
'\"'), QStringLiteral(
"\\\""))
43 .replace(QLatin1Char(
'\''), QStringLiteral(
"\\\'"));
49 bool autoescape)
const
54 if (safeString.get().isEmpty())
57 return QVariant(safeString.get().at(0).toUpper()
59 safeString.get().right(safeString.get().size() - 1)));
62 EscapeJsFilter::EscapeJsFilter() {}
64 static QList<std::pair<QString, QString>> getJsEscapes()
66 QList<std::pair<QString, QString>> jsEscapes;
67 jsEscapes << std::pair<QString, QString>(QChar::fromLatin1(
'\\'),
68 QStringLiteral(
"\\u005C"))
69 << std::pair<QString, QString>(QChar::fromLatin1(
'\''),
70 QStringLiteral(
"\\u0027"))
71 << std::pair<QString, QString>(QChar::fromLatin1(
'\"'),
72 QStringLiteral(
"\\u0022"))
73 << std::pair<QString, QString>(QChar::fromLatin1(
'>'),
74 QStringLiteral(
"\\u003E"))
75 << std::pair<QString, QString>(QChar::fromLatin1(
'<'),
76 QStringLiteral(
"\\u003C"))
77 << std::pair<QString, QString>(QChar::fromLatin1(
'&'),
78 QStringLiteral(
"\\u0026"))
79 << std::pair<QString, QString>(QChar::fromLatin1(
'='),
80 QStringLiteral(
"\\u003D"))
81 << std::pair<QString, QString>(QChar::fromLatin1(
'-'),
82 QStringLiteral(
"\\u002D"))
83 << std::pair<QString, QString>(QChar::fromLatin1(
';'),
84 QStringLiteral(
"\\u003B"))
85 << std::pair<QString, QString>(QChar(0x2028), QStringLiteral(
"\\u2028"))
86 << std::pair<QString, QString>(QChar(0x2029),
87 QStringLiteral(
"\\u2029"));
89 for (
auto i = 0; i < 32; ++i) {
90 jsEscapes << std::pair<QString, QString>(
92 QStringLiteral(
"\\u00")
93 + QStringLiteral(
"%1").arg(i, 2, 16, QLatin1Char(
'0')).toUpper());
100 bool autoescape)
const
106 static const auto jsEscapes = getJsEscapes();
108 for (
auto &
escape : jsEscapes) {
109 retString = retString.replace(
escape.first,
escape.second);
116 bool autoescape)
const
122 const QRegularExpression fixAmpersandsRegexp(
123 QStringLiteral(
"&(?!(\\w+|#\\d+);)"));
125 safeString.get().replace(fixAmpersandsRegexp, QStringLiteral(
"&"));
131 bool autoescape)
const
137 auto inputSafe = retString.isSafe();
139 retString.get().remove(argString);
141 if (inputSafe && argString.get() != QChar::fromLatin1(
';'))
148 bool autoescape)
const
157 bool autoescape)
const
161 auto lines = safeString.get().split(QLatin1Char(
'\n'));
162 auto width = QString::number(lines.size()).size();
164 const auto shouldEscape = (autoescape && !safeString.isSafe());
165 for (
auto i = 0; i < lines.size(); ++i) {
167 = QStringLiteral(
"%1. %2")
169 .arg(shouldEscape ?
QString(
escape(lines.at(i))) : lines.at(i));
172 return SafeString(lines.join(QChar::fromLatin1(
'\n')),
true);
176 bool autoescape)
const
185 bool autoescape)
const
191 else if (input.userType() == qMetaTypeId<QVariantList>()) {
192 a = toString(input.value<QVariantList>());
200 bool autoescape)
const
207 auto it = str.begin();
208 const auto end = str.end();
211 for (; it != end; ++it) {
216 toUpper = it->isSpace();
224 bool autoescape)
const
230 auto numWords = s.get().toInt(&ok);
233 return input.toString();
237 #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
238 auto words = inputString.split(QLatin1Char(
' '), QString::SkipEmptyParts);
240 auto words = inputString.split(QLatin1Char(
' '), Qt::SkipEmptyParts);
243 if (words.size() > numWords) {
244 words = words.mid(0, numWords);
245 if (!words.at(words.size() - 1).endsWith(QStringLiteral(
"..."))) {
246 words << QStringLiteral(
"...");
249 return words.join(QChar::fromLatin1(
' '));
253 bool autoescape)
const
262 bool autoescape)
const
266 return QString::number(
271 bool autoescape)
const
279 bool autoescape)
const
287 bool autoescape)
const
291 const auto valueWidth = value.size();
293 const auto totalPadding = width - valueWidth;
294 const auto rightPadding = totalPadding >> 1;
296 return value.leftJustified(valueWidth + rightPadding).rightJustified(width);
300 bool autoescape)
const
309 bool autoescape)
const
318 bool autoescape)
const
323 = QStringLiteral(
"(%1)").arg(tags.join(QChar::fromLatin1(
'|')));
324 const QRegularExpression startTag(
325 QStringLiteral(
"<%1(/?>|(\\s+[^>]*>))").arg(tagRe));
326 const QRegularExpression endTag(QStringLiteral(
"</%1>").arg(tagRe));
329 const auto safeInput = value.isSafe();
330 value.get().remove(startTag);
331 value.get().remove(endTag);
339 bool autoescape)
const
343 static QRegularExpression tagRe(QStringLiteral(
"<[^>]*>"),
344 QRegularExpression::InvertedGreedinessOption);
353 bool autoescape)
const
357 auto width = argument.value<
int>();
358 #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
359 auto partList = _input.split(QLatin1Char(
' '), QString::SkipEmptyParts);
361 auto partList = _input.split(QLatin1Char(
' '), Qt::SkipEmptyParts);
363 if (partList.isEmpty())
365 auto output = partList.takeFirst();
366 auto pos = output.size() - output.lastIndexOf(QLatin1Char(
'\n')) - 1;
367 Q_FOREACH (
const QString &part, partList) {
369 if (part.contains(QLatin1Char(
'\n'))) {
370 lines = part.split(QLatin1Char(
'\n'));
374 pos += lines.first().size() + 1;
376 output.append(QLatin1Char(
'\n'));
377 pos += lines.last().size();
379 output.append(QLatin1Char(
' '));
380 if (lines.size() > 1)
381 pos += lines.last().size();
390 bool autoescape)
const
394 switch (input.userType()) {
396 case QMetaType::UInt:
397 case QMetaType::LongLong:
398 case QMetaType::ULongLong:
399 case QMetaType::Double:
400 inputDouble = input.toDouble();
407 if (argument.isValid())
412 return QString::number(inputDouble,
'f', precision);
417 bool autoescape)
const
422 if (input.userType() == qMetaTypeId<QVariantList>()) {
423 const auto inputList = input.value<QVariantList>();
424 for (
const auto &item : inputList) {
433 bool autoescape)
const
437 static const QRegularExpression re(QStringLiteral(
"\n{2,}"));
440 Q_FOREACH (
const QString &bit, inputString.get().split(re)) {
441 auto _bit =
SafeString(bit, inputString.isSafe());
444 _bit.get().replace(QLatin1Char(
'\n'), QStringLiteral(
"<br />"));
445 output.append(QStringLiteral(
"<p>%1</p>").arg(_bit));
447 return markSafe(output.join(QStringLiteral(
"\n\n")));
452 bool autoescape)
const
460 inputString.get().replace(QLatin1Char(
'\n'), QStringLiteral(
"<br />")));
466 output.reserve(input.size());
468 auto it = input.constBegin();
469 const auto end = input.constEnd();
470 static const QChar asciiEndPoint(128);
471 for (; it != end; ++it)
472 if (*it < asciiEndPoint)
480 bool autoescape)
const
485 inputString = inputString.normalized(QString::NormalizationForm_KD);
486 inputString = nofailStringToAscii(inputString);
487 inputString = inputString.trimmed()
489 .remove(QRegularExpression(QStringLiteral(
"[^\\w\\s-]")))
490 .replace(QRegularExpression(QStringLiteral(
"[-\\s]+")), QStringLiteral(
"-"));
496 bool autoescape)
const
502 bool numberConvert =
true;
505 if (input.canConvert<qreal>()) {
506 size = input.toReal(&numberConvert);
507 if (!numberConvert) {
508 qWarning(
"%s",
"Failed to convert input file size into floating point value.");
512 if (!numberConvert) {
513 qWarning(
"%s",
"Failed to convert input file size into floating point value.");
519 qreal multiplier = 1.0f;
521 if (!arg.get().isEmpty()) {
522 #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
523 const auto argList = arg.get().split(QLatin1Char(
','), QString::SkipEmptyParts);
525 const auto argList = arg.get().split(QLatin1Char(
','), Qt::SkipEmptyParts);
527 const auto numArgs = argList.size();
529 unitSystem = argList.at(0).toInt(&numberConvert);
530 if (!numberConvert) {
531 qWarning(
"%s",
"Failed to convert filse size format unit system into integer. Falling back to default 10.");
537 precision = argList.at(1).toInt(&numberConvert);
538 if (!numberConvert) {
539 qWarning(
"%s",
"Failed to convert file size format decimal precision into integer. Falling back to default 2.");
545 multiplier = argList.at(2).toDouble(&numberConvert);
546 if (!numberConvert) {
547 qWarning(
"%s",
"Failed to convert file size format multiplier into double value. Falling back to default 1.0");
550 if (multiplier == 0.0f) {
551 qWarning(
"%s",
"It makes no sense to multiply the file size by zero. Using default value 1.0.");
558 const double sizeMult = size * multiplier;
560 if (unitSystem == 10) {
561 if ((sizeMult > -1000) && (sizeMult < 1000)) {
564 }
else if (unitSystem == 2) {
565 if ((sizeMult > - 1024) && (sizeMult < 1024)) {
570 const std::pair<qreal,QString> sizePair =
calcFileSize(size, unitSystem, multiplier);
572 const QString retString = QString::number(sizePair.first,
'f', precision) + QLatin1Char(
' ') + sizePair.second;
574 ret.setValue(retString);
585 if(retString.length() < count)
return retString;
586 retString.truncate(count);
587 retString.append(QStringLiteral(
"..."));
594 const int len = input.length();
595 esc.reserve(
static_cast<int>(len * 1.2));
596 for (
int i = 0; i < len; ++i) {
597 const QChar ch = input.at(i);
598 if (ch == QLatin1Char(
'>')) {
599 esc += QStringLiteral(
"\\\\u003E");
600 }
else if (ch == QLatin1Char(
'<')) {
601 esc += QStringLiteral(
"\\\\u003C");
602 }
else if (ch == QLatin1Char(
'&')) {
603 esc += QStringLiteral(
"\\\\u0026");
615 if (input.isNull() || !input.isValid()) {
622 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
623 if (input.userType() == qMetaTypeId<QJsonDocument>()) {
624 json = input.toJsonDocument();
625 }
else if (input.userType() == qMetaTypeId<QJsonObject>()) {
626 json.setObject(input.toJsonObject());
627 }
else if (input.userType() == qMetaTypeId<QJsonArray>()) {
628 json.setArray(input.toJsonArray());
629 }
else if (input.userType() == qMetaTypeId<QVariantHash>()) {
630 json.setObject(QJsonObject::fromVariantHash(input.toHash()));
631 }
else if (input.userType() == qMetaTypeId<QVariantMap>()) {
632 json.setObject(QJsonObject::fromVariantMap(input.toMap()));
633 }
else if (input.userType() == qMetaTypeId<QVariantList>()) {
634 json.setArray(QJsonArray::fromVariantList(input.toList()));
635 }
else if (input.userType() == qMetaTypeId<QStringList>()) {
636 json.setArray(QJsonArray::fromStringList(input.toStringList()));
638 qWarning(
"%s",
"Can not convert input data into QJsonObject or QJSonArray.");
642 if (input.canConvert<QJsonDocument>()) {
643 json = input.toJsonDocument();
644 }
else if (input.canConvert<QJsonObject>()) {
645 json.setObject(input.toJsonObject());
646 }
else if (input.canConvert<QJsonArray>()) {
647 json.setArray(input.toJsonArray());
649 qWarning(
"%s",
"Can not convert input data into QJsonObject or QJSonArray.");
654 QString jsonString = QString::fromUtf8(json.toJson(QJsonDocument::Compact));
655 jsonString = escapeJson(jsonString);
657 const QString scriptString = u
"<script id=\"" + arg + u
"\" type=\"application/json\">" + jsonString + u
"</script>";
QVariant doFilter(const QVariant &input, const QVariant &argument={}, bool autoescape={}) const override
QVariant doFilter(const QVariant &input, const QVariant &argument={}, bool autoescape={}) const override
QVariant doFilter(const QVariant &input, const QVariant &argument={}, bool autoescape={}) const override
QVariant doFilter(const QVariant &input, const QVariant &argument={}, bool autoescape={}) const override
SafeString escape(const QString &input) const
SafeString conditionalEscape(const SafeString &input) const
A QString wrapper class for containing whether a string is safe or needs to be escaped.
const NestedString & get() const
QVariant doFilter(const QVariant &input, const QVariant &argument={}, bool autoescape={}) const override
QVariant doFilter(const QVariant &input, const QVariant &argument={}, bool autoescape={}) const override
QVariant doFilter(const QVariant &input, const QVariant &argument={}, bool autoescape={}) const override
QVariant doFilter(const QVariant &input, const QVariant &argument={}, bool autoescape={}) const override
QVariant doFilter(const QVariant &input, const QVariant &argument=QVariant(), bool autoescape={}) const override
QVariant doFilter(const QVariant &input, const QVariant &argument={}, bool autoescape={}) const override
QVariant doFilter(const QVariant &input, const QVariant &argument={}, bool autoescape={}) const override
QVariant doFilter(const QVariant &input, const QVariant &argument={}, bool autoescape={}) const override
QVariant doFilter(const QVariant &input, const QVariant &argument={}, bool autoescape={}) const override
QVariant doFilter(const QVariant &input, const QVariant &argument={}, bool autoescape={}) const override
QVariant doFilter(const QVariant &input, const QVariant &argument={}, bool autoescape={}) const override
QVariant doFilter(const QVariant &input, const QVariant &argument={}, bool autoescape={}) const override
QVariant doFilter(const QVariant &input, const QVariant &argument={}, bool autoescape={}) const override
QVariant doFilter(const QVariant &input, const QVariant &argument={}, bool autoescape={}) const override
QVariant doFilter(const QVariant &input, const QVariant &argument={}, bool autoescape={}) const override
QVariant doFilter(const QVariant &input, const QVariant &argument=QVariant(), bool autoescape={}) const override
QVariant doFilter(const QVariant &input, const QVariant &argument={}, bool autoescape={}) const override
QVariant doFilter(const QVariant &input, const QVariant &argument={}, bool autoescape={}) const override
QVariant doFilter(const QVariant &input, const QVariant &argument={}, bool autoescape={}) const override
QVariant doFilter(const QVariant &input, const QVariant &argument={}, bool autoescape={}) const override
std::pair< qreal, QString > calcFileSize(qreal size, int unitSystem=10, qreal multiplier=1.0)
bool isSafeString(const QVariant &input)
Cutelee::SafeString getSafeString(const QVariant &input)
Cutelee::SafeString markSafe(const Cutelee::SafeString &input)
Cutelee::SafeString markForEscaping(const Cutelee::SafeString &input)
Utility functions used throughout Cutelee.