| Index: compiled/Filter.cpp | 
| =================================================================== | 
| new file mode 100644 | 
| --- /dev/null | 
| +++ b/compiled/Filter.cpp | 
| @@ -0,0 +1,154 @@ | 
| +#include "Filter.h" | 
| +#include "CommentFilter.h" | 
| +#include "InvalidFilter.h" | 
| +#include "RegExpFilter.h" | 
| +#include "BlockingFilter.h" | 
| +#include "WhitelistFilter.h" | 
| +#include "ElemHideBase.h" | 
| +#include "ElemHideFilter.h" | 
| +#include "ElemHideException.h" | 
| +#include "CSSPropertyFilter.h" | 
| +#include "StringMap.h" | 
| + | 
| +namespace | 
| +{ | 
| + StringMap<Filter*> knownFilters(8192); | 
| + | 
| + void NormalizeWhitespace(DependentString& text) | 
| + { | 
| + String::size_type start = 0; | 
| + String::size_type end = text.length(); | 
| + | 
| + // Remove leading spaces and special characters like line breaks | 
| + for (; start < end; start++) | 
| + if (text[start] > ' ') | 
| + break; | 
| + | 
| + // Now look for invalid characters inside the string | 
| + String::size_type pos; | 
| + for (pos = start; pos < end; pos++) | 
| + if (text[pos] < ' ') | 
| + break; | 
| + | 
| + if (pos < end) | 
| + { | 
| + // Found invalid characters, copy all the valid characters while skipping | 
| + // the invalid ones. | 
| + String::size_type delta = 1; | 
| + for (pos = pos + 1; pos < end; pos++) | 
| + { | 
| + if (text[pos] < ' ') | 
| + delta++; | 
| + else | 
| + text[pos - delta] = text[pos]; | 
| + } | 
| + end -= delta; | 
| + } | 
| + | 
| + // Remove trailing spaces | 
| + for (; end > 0; end--) | 
| + if (text[end - 1] != ' ') | 
| + break; | 
| + | 
| + // Set new string boundaries | 
| + text.reset(text, start, end - start); | 
| + } | 
| +} | 
| + | 
| +Filter::Filter(const String& text) | 
| + : mText(text) | 
| +{ | 
| + annotate_address(this, "Filter"); | 
| +} | 
| + | 
| +Filter::~Filter() | 
| +{ | 
| + // TODO: This should be removing from knownFilters | 
| +} | 
| + | 
| +OwnedString Filter::Serialize() const | 
| +{ | 
| + OwnedString result(u"[Filter]\ntext="_str); | 
| + result.append(mText); | 
| + result.append(u'\n'); | 
| + return result; | 
| +} | 
| + | 
| +Filter* Filter::FromText(DependentString& text) | 
| +{ | 
| + NormalizeWhitespace(text); | 
| + if (text.empty()) | 
| + return nullptr; | 
| + | 
| + // Parsing also normalizes the filter text, so it has to be done before the | 
| + // lookup in knownFilters. | 
| + union | 
| + { | 
| + RegExpFilterData regexp; | 
| + ElemHideData elemhide; | 
| + } data; | 
| + DependentString error; | 
| + | 
| + Filter::Type type = CommentFilter::Parse(text); | 
| + if (type == Filter::Type::UNKNOWN) | 
| + type = ElemHideBase::Parse(text, data.elemhide); | 
| + if (type == Filter::Type::UNKNOWN) | 
| + type = RegExpFilter::Parse(text, error, data.regexp); | 
| + | 
| + auto knownFilter = knownFilters.find(text); | 
| + if (knownFilter) | 
| + return knownFilter->second; | 
| + | 
| + FilterPtr filter; | 
| + switch (type) | 
| + { | 
| + case Filter::Type::COMMENT: | 
| + filter = new CommentFilter(text); | 
| + break; | 
| + case Filter::Type::INVALID: | 
| + filter = new InvalidFilter(text, error); | 
| + break; | 
| + case Filter::Type::BLOCKING: | 
| + filter = new BlockingFilter(text, data.regexp); | 
| + break; | 
| + case Filter::Type::WHITELIST: | 
| + filter = new WhitelistFilter(text, data.regexp); | 
| + break; | 
| + case Filter::Type::ELEMHIDE: | 
| + filter = new ElemHideFilter(text, data.elemhide); | 
| + break; | 
| + case Filter::Type::ELEMHIDEEXCEPTION: | 
| + filter = new ElemHideException(text, data.elemhide); | 
| + break; | 
| + case Filter::Type::CSSPROPERTY: | 
| + filter = new CSSPropertyFilter(text, data.elemhide); | 
| + if (static_cast<CSSPropertyFilter*>(filter.get())->IsGeneric()) | 
| + filter = new InvalidFilter(text, u"filter_cssproperty_nodomain"_str); | 
| + break; | 
| + default: | 
| + // This should never happen but just in case | 
| + return nullptr; | 
| + } | 
| + | 
| + // This is a hack: we looked up the entry using text but create it using | 
| + // filter->mText. This works because both are equal at this point. However, | 
| + // text refers to a temporary buffer which will go away. | 
| + enter_context("Adding to known filters"); | 
| + knownFilter.assign(filter->mText, filter.get()); | 
| + exit_context(); | 
| + | 
| + // TODO: We intentionally leak the filter here - currently it won't be used | 
| + // for anything and would be deleted immediately. | 
| + filter->AddRef(); | 
| + | 
| + return filter; | 
| +} | 
| + | 
| +Filter* Filter::GetKnownFilter(const String& text) | 
| +{ | 
| + auto it = knownFilters.find(text); | 
| + if (it) | 
| + return it->second; | 
| + else | 
| + return nullptr; | 
| +} |