diff options
Diffstat (limited to 'plugins/AdblockFilter/filterlist.cpp')
-rw-r--r-- | plugins/AdblockFilter/filterlist.cpp | 128 |
1 files changed, 128 insertions, 0 deletions
diff --git a/plugins/AdblockFilter/filterlist.cpp b/plugins/AdblockFilter/filterlist.cpp new file mode 100644 index 0000000..76953fc --- /dev/null +++ b/plugins/AdblockFilter/filterlist.cpp @@ -0,0 +1,128 @@ +/* + * 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 <QByteArray> +#include <QIODevice> + +/** + * Documentation: + * + * https://adblockplus.org/filter-cheatsheet + * https://help.eyeo.com/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 + * + */ + +const QLatin1String comment_lastModified("! Last modified: "); +const QLatin1String comment_expires("! Expires: "); + +using namespace AdblockPlus; + +Filterlist::Filterlist(QIODevice &from) +{ + if(from.isReadable() && from.isTextModeEnabled()) { + while(from.bytesAvailable() > 0) { + const auto line = from.readLine(512); + + if(line[0] == '!') { + parseComment(line); + + } else if(line.contains("##") || line.contains("#@#")) { + // ## is element hiding rule + // #@# is element hiding exception rule + + } else { + parseRule(line); + } + } + } +} + +void Filterlist::parseComment(const QString &line) +{ + if(line.startsWith(comment_lastModified)) { + lastModified = QDateTime::fromString(line.mid(comment_lastModified.size()), "dd MMM yyyy HH:mm 'UTC'"); + expires = lastModified; + + } else if(line.startsWith(comment_expires)) { + const QRegularExpression time_re("(?:(\\d+) days)|(?:(\\d+) hours)"); + const auto match = time_re.match(line); + if(match.hasMatch()) { + expires = expires.addDays(match.captured(1).toInt()); + expires = expires.addSecs(match.captured(2).toInt() * 60 * 60); + } + } +} + +Rule *Filterlist::parseRule(const QByteArray &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); + + if(!opt.parseAbp(&options)) { + return nullptr; + } + } + + if(pattern.startsWith("||") && pattern.endsWith("^")) { + // domain match + pattern = pattern.mid(2, pattern.length() - 3); + return new MatcherRule(pattern, opt, MatcherRule::DomainMatch); + + } else if(pattern.startsWith("|") && pattern.endsWith("|")) { + // string equals + pattern = pattern.mid(1, pattern.length() - 2); + return new MatcherRule(pattern, opt, MatcherRule::UrlEquals); + + } else if(pattern.startsWith("|")) { + // string starts with + pattern = pattern.mid(1, pattern.length() - 1); + return new MatcherRule(pattern, opt, MatcherRule::UrlStartsWith); + + } else if(pattern.endsWith("|")) { + // string ends with + pattern = pattern.mid(0, pattern.length() - 1); + return new MatcherRule(pattern, opt, MatcherRule::UrlEndsWith); + + } else if(pattern.startsWith("/") && pattern.endsWith("/")) { + // regular expression + pattern = pattern.mid(1, pattern.length() - 2); + return new RegexRule(pattern, opt); + + } else if(!pattern.isEmpty()) { + if(pattern.contains('*')) { + // wildcard pattern + pattern = QRegularExpression::wildcardToRegularExpression(pattern); + return new RegexRule(pattern, opt); + } else { + // contains pattern + return new MatcherRule(pattern, opt); + } + } + + return nullptr; +} + +bool Filterlist::filter(QWebEngineUrlRequestInfo &info) const +{ + return false; +} |