aboutsummaryrefslogtreecommitdiff
path: root/staging/adblock/filterlist.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'staging/adblock/filterlist.cpp')
-rw-r--r--staging/adblock/filterlist.cpp137
1 files changed, 137 insertions, 0 deletions
diff --git a/staging/adblock/filterlist.cpp b/staging/adblock/filterlist.cpp
new file mode 100644
index 0000000..be2bd4e
--- /dev/null
+++ b/staging/adblock/filterlist.cpp
@@ -0,0 +1,137 @@
+/*
+ * This file is part of smolbote. It's copyrighted by the contributors recorded
+ * in the version control history of the file, available from its original
+ * location: https://library.iserlohn-fortress.net/aqua/smolbote.git
+ *
+ * SPDX-License-Identifier: GPL-3.0
+ */
+
+#include "filterlist.h"
+#include "rule.h"
+#include <QRegularExpression>
+#include <QTextStream>
+
+/**
+ * Documentation:
+ *
+ * https://help.eyeo.com/en/adblockplus/how-to-write-filters
+ *
+ * https://github.com/gorhill/uBlock/wiki/Introduction-to-basic-filtering-syntax
+ * https://github.com/gorhill/uBlock/wiki/Static-filter-syntax
+ *
+ */
+
+using namespace AdblockPlus;
+
+FilterList::FilterList(QObject *parent)
+ : QObject(parent)
+{
+}
+
+FilterList::~FilterList()
+{
+ qDeleteAll(m_rules);
+}
+
+FilterList::ParseResult FilterList::parse(QTextStream &stream)
+{
+ FilterList::ParseResult result;
+
+ if(stream.readLine().trimmed() != "[Adblock Plus 2.0]") {
+ result.state = FilterList::InvalidFormat;
+ return result;
+ }
+
+ QString line;
+ while(stream.readLineInto(&line)) {
+
+ if(!line.isEmpty()) {
+ ++result.lines_total;
+
+ if(line.startsWith('!')) {
+ ++result.lines_comments;
+ parseComment(line);
+
+ } else if(line.contains("##") || line.contains("#@#")) {
+ // ## is element hiding rule
+ // #@# is element hiding exception rule
+ if(qgetenv("PRINT_IGNORED") == "1")
+ qDebug("ignored: >%s<", qUtf8Printable(line));
+ ++result.lines_ignored;
+
+ } else {
+ if(parseRule(line))
+ ++result.lines_parsed;
+ else {
+ if(qgetenv("PRINT_FAILED") == "1")
+ qDebug("failed: >%s<", qUtf8Printable(line));
+ ++result.lines_failed;
+ }
+ }
+ }
+ }
+
+ result.state = FilterList::Ok;
+ return result;
+}
+
+void FilterList::parseComment(QString &line)
+{
+ m_comments.append(line);
+}
+
+bool FilterList::parseRule(const QString &line)
+{
+ QString pattern = line;
+ Options opt;
+
+ if(pattern.startsWith(QLatin1String("@@"))) {
+ pattern.remove(0, 2);
+ opt.exception = true;
+ }
+
+ // parse options
+ if(pattern.contains('$')) {
+ const auto list = pattern.split('$');
+ pattern = list.at(0);
+ const auto options = list.at(1).split(',');
+
+ for(const auto &option : options) {
+ if(!opt.set(option))
+ return false;
+ }
+ }
+
+ if(pattern.startsWith("||") && pattern.endsWith("^")) {
+ // domain match
+ pattern = pattern.mid(2, pattern.length() - 3);
+ m_rules.append(new MatcherRule(pattern, opt));
+
+ } else if(pattern.startsWith("|") && pattern.endsWith("|")) {
+ // string equals
+ pattern = pattern.mid(1, pattern.length() - 2);
+ m_rules.append(new MatcherRule(pattern, opt));
+
+ } else if(pattern.startsWith("||")) {
+ // string starts with
+ pattern = pattern.mid(2, pattern.length() - 2);
+ m_rules.append(new MatcherRule(pattern, opt));
+
+ } else if(pattern.endsWith("|")) {
+ // string ends with
+ pattern = pattern.mid(0, pattern.length() - 1);
+ m_rules.append(new MatcherRule(pattern, opt));
+
+ } else if(pattern.startsWith("/") && pattern.endsWith("/")) {
+ // regular expression
+ pattern = pattern.mid(1, pattern.length() - 2);
+ m_rules.append(new RegexRule(pattern, opt));
+
+ } else {
+ // wildcard pattern
+ pattern = QRegularExpression::wildcardToRegularExpression(pattern);
+ m_rules.append(new RegexRule(pattern, opt));
+ }
+
+ return true;
+}