| Index: src/plugin/PluginFilter.cpp |
| diff --git a/src/plugin/PluginFilter.cpp b/src/plugin/PluginFilter.cpp |
| index 269f3a2214728ba6cd1c8c9f7fae892bff21ea12..a4661e8a9425e9bf7f3020c78ac0fd5df27c8265 100644 |
| --- a/src/plugin/PluginFilter.cpp |
| +++ b/src/plugin/PluginFilter.cpp |
| @@ -15,750 +15,731 @@ |
| * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. |
| */ |
| -#include "PluginStdAfx.h" |
| - |
| -#include "PluginFilter.h" |
| -#include "PluginSettings.h" |
| -#include "PluginClient.h" |
| -#include "PluginClientFactory.h" |
| -#include "PluginMutex.h" |
| -#include "PluginSettings.h" |
| -#include "PluginSystem.h" |
| -#include "PluginClass.h" |
| -#include "mlang.h" |
| - |
| -#include "..\shared\CriticalSection.h" |
| -#include "..\shared\Utils.h" |
| - |
| - |
| -// The filters are described at http://adblockplus.org/en/filters |
| - |
| -static CriticalSection s_criticalSectionFilterMap; |
| - |
| -namespace |
| -{ |
| - struct GetHtmlElementAttributeResult |
| - { |
| - GetHtmlElementAttributeResult() : isAttributeFound(false) |
| - { |
| - } |
| - std::wstring attributeValue; |
| - bool isAttributeFound; |
| - }; |
| - |
| - GetHtmlElementAttributeResult GetHtmlElementAttribute(IHTMLElement& htmlElement, |
| - const ATL::CComBSTR& attributeName) |
| - { |
| - GetHtmlElementAttributeResult retValue; |
| - ATL::CComVariant vAttr; |
| - ATL::CComPtr<IHTMLElement4> htmlElement4; |
| - if (FAILED(htmlElement.QueryInterface(&htmlElement4)) || !htmlElement4) |
| - { |
| - return retValue; |
| - } |
| - ATL::CComPtr<IHTMLDOMAttribute> attributeNode; |
| - if (FAILED(htmlElement4->getAttributeNode(attributeName, &attributeNode)) || !attributeNode) |
| - { |
| - return retValue; |
| - } |
| - // we set that attribute found but it's not necessary that we can retrieve its value |
| - retValue.isAttributeFound = true; |
| - if (FAILED(attributeNode->get_nodeValue(&vAttr))) |
| - { |
| - return retValue; |
| - } |
| - if (vAttr.vt == VT_BSTR && vAttr.bstrVal) |
| - { |
| - retValue.attributeValue = vAttr.bstrVal; |
| - } |
| - else if (vAttr.vt == VT_I4) |
| - { |
| - retValue.attributeValue = std::to_wstring(vAttr.iVal); |
| - } |
| - return retValue; |
| - } |
| -} |
| - |
| -// ============================================================================ |
| -// CFilterElementHideAttrSelector |
| -// ============================================================================ |
| - |
| -CFilterElementHideAttrSelector::CFilterElementHideAttrSelector() : m_type(TYPE_NONE), m_pos(POS_NONE), m_bstrAttr(NULL) |
| -{ |
| -} |
| - |
| -CFilterElementHideAttrSelector::CFilterElementHideAttrSelector(const CFilterElementHideAttrSelector& filter) |
| -{ |
| - m_type = filter.m_type; |
| - m_pos = filter.m_pos; |
| - m_bstrAttr = filter.m_bstrAttr; |
| - |
| - m_value = filter.m_value; |
| -} |
| - |
| -CFilterElementHideAttrSelector::~CFilterElementHideAttrSelector() |
| -{ |
| -} |
| - |
| - |
| -// ============================================================================ |
| -// CFilterElementHide |
| -// ============================================================================ |
| - |
| -CFilterElementHide::CFilterElementHide(const CString& filterText) : m_filterText(filterText), m_type(ETraverserComplexType::TRAVERSER_TYPE_ERROR) |
| -{ |
| - // Find tag name, class or any (*) |
| - CString filterString = filterText; |
| - |
| - wchar_t firstTag = filterString.GetAt(0); |
| - // Any tag |
| - if (firstTag == '*') |
| - { |
| - filterString = filterString.Mid(1); |
| - } |
| - // Any tag (implicitely) |
| - else if (firstTag == '[' || firstTag == '.' || firstTag == '#') |
| - { |
| - } |
| - // Real tag |
| - else if (isalnum(firstTag)) |
| - { |
| - //TODO: Add support for descendant selectors |
| - int pos = filterString.FindOneOf(L".#[("); |
| - |
| - if (pos < 0) |
| - pos = filterString.GetLength(); |
| - m_tag = filterString.Left(pos).MakeLower(); |
| - |
| - filterString = filterString.Mid(pos); |
| - } |
| - // Error |
| - else |
| - { |
| - DEBUG_FILTER("Filter::Error parsing selector:" + filterText + " (invalid tag)"); |
| - throw std::runtime_error(CStringA("Filter::Error parsing selector:" + filterText + " (invalid tag)").GetString()); |
| - } |
| - |
| - // Find Id and class name |
| - |
| - if (!filterString.IsEmpty()) |
| - { |
| - wchar_t firstId = filterString.GetAt(0); |
| - |
| - // Id |
| - if (firstId == '#') |
| - { |
| - int pos = filterString.Find('['); |
| - if (pos < 0) |
| - { |
| - pos = filterString.GetLength(); |
| - } |
| - m_tagId = filterString.Mid(1, pos - 1); |
| - filterString = filterString.Mid(pos); |
| - pos = m_tagId.Find(L"."); |
| - if (pos > 0) |
| - { |
| - m_tagClassName = m_tagId.Mid(pos + 1); |
| - m_tagId = m_tagId.Left(pos); |
| - } |
| - } |
| - // Class name |
| - else if (firstId == '.') |
| - { |
| - int pos = filterString.Find('['); |
| - if (pos < 0) |
| - { |
| - pos = filterString.GetLength(); |
| - } |
| - m_tagClassName = filterString.Mid(1, pos - 1); |
| - filterString = filterString.Mid(pos); |
| - } |
| - } |
| - |
| - char chAttrStart = '['; |
| - char chAttrEnd = ']'; |
| - |
| - while (!filterString.IsEmpty()) |
| - { |
| - if (filterString.GetAt(0) != chAttrStart) |
| - { |
| - DEBUG_FILTER("Filter::Error parsing selector:" + filterText + " (more data)"); |
| - throw std::runtime_error(CStringA("Filter::Error parsing selector:" + filterText + " (more data)").GetString()); |
| - } |
| - int endPos = filterString.Find(']') ; |
| - if (endPos < 0) |
| - { |
| - DEBUG_FILTER("Filter::Error parsing selector:" + filterText + " (more data)"); |
| - throw std::runtime_error(CStringA("Filter::Error parsing selector:" + filterText + " (more data)").GetString()); |
| - } |
| - |
| - CFilterElementHideAttrSelector attrSelector; |
| - |
| - CString arg = filterString.Mid(1, endPos - 1); |
| - filterString = filterString.Mid(endPos + 1); |
| - |
| - int delimiterPos = arg.Find('='); |
| - if (delimiterPos > 0) |
| - { |
| - attrSelector.m_value = arg.Mid(delimiterPos + 1); |
| - if (attrSelector.m_value.GetLength() >= 2 && attrSelector.m_value.GetAt(0) == '\"' && attrSelector.m_value.GetAt(attrSelector.m_value.GetLength() - 1) == '\"') |
| - { |
| - attrSelector.m_value = attrSelector.m_value.Mid(1, attrSelector.m_value.GetLength() - 2); |
| - } |
| - |
| - if (arg.GetAt(delimiterPos - 1) == '^') |
| - { |
| - attrSelector.m_bstrAttr = arg.Left(delimiterPos - 1); |
| - attrSelector.m_pos = CFilterElementHideAttrPos::STARTING; |
| - } |
| - else if (arg.GetAt(delimiterPos - 1) == '*') |
| - { |
| - attrSelector.m_bstrAttr = arg.Left(delimiterPos - 1); |
| - attrSelector.m_pos = CFilterElementHideAttrPos::ANYWHERE; |
| - } |
| - else if (arg.GetAt(delimiterPos - 1) == '$') |
| - { |
| - attrSelector.m_bstrAttr = arg.Left(delimiterPos - 1); |
| - attrSelector.m_pos = CFilterElementHideAttrPos::ENDING; |
| - } |
| - else |
| - { |
| - attrSelector.m_bstrAttr = arg.Left(delimiterPos); |
| - attrSelector.m_pos = CFilterElementHideAttrPos::EXACT; |
| - } |
| - } |
| - CString tag = attrSelector.m_bstrAttr; |
| - if (tag == "style") |
| - { |
| - attrSelector.m_type = CFilterElementHideAttrType::STYLE; |
| - attrSelector.m_value.MakeLower(); |
| - } |
| - else if (tag == "id") |
| - { |
| - attrSelector.m_type = CFilterElementHideAttrType::ID; |
| - } |
| - else if (tag == "class") |
| - { |
| - attrSelector.m_type = CFilterElementHideAttrType::CLASS; |
| - } |
| - m_attributeSelectors.push_back(attrSelector); |
| - |
| - } |
| - |
| - // End check |
| - if (!filterString.IsEmpty()) |
| - { |
| - DEBUG_FILTER("Filter::Error parsing selector:" + filterFile + "/" + filterText + " (more data)") |
| - throw new std::runtime_error(CStringA("Filter::Error parsing selector:" + filterText + " (more data)").GetString()); |
| - } |
| -} |
| - |
| -CFilterElementHide::CFilterElementHide(const CFilterElementHide& filter) |
| -{ |
| - m_filterText = filter.m_filterText; |
| - |
| - m_tagId = filter.m_tagId; |
| - m_tagClassName = filter.m_tagClassName; |
| - |
| - m_attributeSelectors = filter.m_attributeSelectors; |
| - |
| - m_predecessor = filter.m_predecessor; |
| -} |
| - |
| - |
| -// ============================================================================ |
| -// CFilter |
| -// ============================================================================ |
| - |
| -CFilter::CFilter(const CFilter& filter) |
| -{ |
| - m_contentType = filter.m_contentType; |
| - m_filterType = filter.m_filterType; |
| - |
| - m_isFirstParty = filter.m_isFirstParty; |
| - m_isThirdParty = filter.m_isThirdParty; |
| - |
| - m_isMatchCase = filter.m_isMatchCase; |
| - m_isFromStart = filter.m_isFromStart; |
| - m_isFromEnd = filter.m_isFromEnd; |
| - |
| - m_filterText = filter.m_filterText; |
| - |
| - m_hitCount = filter.m_hitCount; |
| -} |
| - |
| - |
| -CFilter::CFilter() : m_isMatchCase(false), m_isFirstParty(false), m_isThirdParty(false), m_contentType(CFilter::contentTypeAny), |
| - m_isFromStart(false), m_isFromEnd(false), m_hitCount(0) |
| -{ |
| -} |
| - |
| - |
| -bool CFilterElementHide::IsMatchFilterElementHide(IHTMLElement* pEl) const |
| -{ |
| - HRESULT hr; |
| - |
| - if (!m_tagId.IsEmpty()) |
| - { |
| - CComBSTR id; |
| - hr = pEl->get_id(&id); |
| - if ((hr != S_OK) || (id != CComBSTR(m_tagId))) |
| - { |
| - return false; |
| - } |
| - } |
| - if (!m_tagClassName.IsEmpty()) |
| - { |
| - CComBSTR classNameBSTR; |
| - hr = pEl->get_className(&classNameBSTR); |
| - if (hr == S_OK) |
| - { |
| - CString className = classNameBSTR; |
| - int start = 0; |
| - CString specificClass; |
| - bool foundMatch = false; |
| - while ((specificClass = className.Tokenize(L" ", start)) != L"") |
| - { |
| - // TODO: Consider case of multiple classes. (m_tagClassName can be something like "foo.bar") |
| - if (specificClass == m_tagClassName) |
| - { |
| - foundMatch = true; |
| - } |
| - } |
| - if (!foundMatch) |
| - { |
| - return false; |
| - } |
| - } |
| - } |
| - if (!m_tag.IsEmpty()) |
| - { |
| - CComBSTR tagName; |
| - hr = pEl->get_tagName(&tagName); |
| - tagName.ToLower(); |
| - if ((hr != S_OK) || (tagName != CComBSTR(m_tag))) |
| - { |
| - return false; |
| - } |
| - } |
| - |
| - // Check attributes |
| - for (std::vector<CFilterElementHideAttrSelector>::const_iterator attrIt = m_attributeSelectors.begin(); |
| - attrIt != m_attributeSelectors.end(); ++ attrIt) |
| - { |
| - ATL::CString value; |
| - bool attrFound = false; |
| - if (attrIt->m_type == CFilterElementHideAttrType::STYLE) |
| - { |
| - CComPtr<IHTMLStyle> pStyle; |
| - if (SUCCEEDED(pEl->get_style(&pStyle)) && pStyle) |
| - { |
| - CComBSTR bstrStyle; |
| - |
| - if (SUCCEEDED(pStyle->get_cssText(&bstrStyle)) && bstrStyle) |
| - { |
| - value = bstrStyle; |
| - value.MakeLower(); |
| - attrFound = true; |
| - } |
| - } |
| - } |
| - else if (attrIt->m_type == CFilterElementHideAttrType::CLASS) |
| - { |
| - CComBSTR bstrClassNames; |
| - if (SUCCEEDED(pEl->get_className(&bstrClassNames)) && bstrClassNames) |
| - { |
| - value = bstrClassNames; |
| - attrFound = true; |
| - } |
| - } |
| - else if (attrIt->m_type == CFilterElementHideAttrType::ID) |
| - { |
| - CComBSTR bstrId; |
| - if (SUCCEEDED(pEl->get_id(&bstrId)) && bstrId) |
| - { |
| - value = bstrId; |
| - attrFound = true; |
| - } |
| - } |
| - else |
| - { |
| - auto attributeValue = GetHtmlElementAttribute(*pEl, attrIt->m_bstrAttr); |
| - if (attrFound = attributeValue.isAttributeFound) |
| - { |
| - value = ToCString(attributeValue.attributeValue); |
| - } |
| - } |
| - |
| - if (attrFound) |
| - { |
| - if (attrIt->m_pos == CFilterElementHideAttrPos::EXACT) |
| - { |
| - // TODO: IE rearranges the style attribute completely. Figure out if anything can be done about it. |
| - if (value != attrIt->m_value) |
| - return false; |
| - } |
| - else if (attrIt->m_pos == CFilterElementHideAttrPos::STARTING) |
| - { |
| - if (value.Left(attrIt->m_value.GetLength()) != attrIt->m_value) |
| - return false; |
| - } |
| - else if (attrIt->m_pos == CFilterElementHideAttrPos::ENDING) |
| - { |
| - if (value.Right(attrIt->m_value.GetLength()) != attrIt->m_value) |
| - return false; |
| - } |
| - else if (attrIt->m_pos == CFilterElementHideAttrPos::ANYWHERE) |
| - { |
| - if (value.Find(attrIt->m_value) < 0) |
| - return false; |
| - } |
| - else if (attrIt->m_value.IsEmpty()) |
| - { |
| - return true; |
| - } |
| - } |
| - else |
| - { |
| - return false; |
| - } |
| - } |
| - |
| - if (m_predecessor) |
| - { |
| - CComPtr<IHTMLElement> pDomPredecessor; |
| - HRESULT hr = S_FALSE; |
| - switch (m_predecessor->m_type) |
| - { |
| - case ETraverserComplexType::TRAVERSER_TYPE_PARENT: |
| - hr = pEl->get_parentElement(&pDomPredecessor); |
| - break; |
| - case ETraverserComplexType::TRAVERSER_TYPE_IMMEDIATE: |
| - hr = S_FALSE; |
| - CComQIPtr<IHTMLDOMNode> pPrevSiblingNode = pEl; |
| - long type = 0; |
| - while (pPrevSiblingNode && type != 1) |
| - { |
| - IHTMLDOMNode* tmpNode; |
| - pPrevSiblingNode->get_previousSibling(&tmpNode); |
| - pPrevSiblingNode.Attach(tmpNode); |
| - if (pPrevSiblingNode) |
| - { |
| - hr = pPrevSiblingNode->get_nodeType(&type); |
| - if (hr != S_OK) |
| - pPrevSiblingNode.Release(); |
| - } |
| - } |
| - |
| - if (pPrevSiblingNode) |
| - hr = pPrevSiblingNode.QueryInterface(&pDomPredecessor); |
| - else |
| - return false; |
| - break; |
| - } |
| - if (hr != S_OK) |
| - return false; |
| - return m_predecessor->IsMatchFilterElementHide(pDomPredecessor); |
| - } |
| - |
| - return true; |
| -} |
| - |
| - |
| - |
| -// ============================================================================ |
| -// CPluginFilter |
| -// ============================================================================ |
| - |
| -CPluginFilter::CPluginFilter(const CString& dataPath) : m_dataPath(dataPath) |
| -{ |
| - m_contentMapText[CFilter::contentTypeDocument] = "DOCUMENT"; |
| - m_contentMapText[CFilter::contentTypeObject] = "OBJECT"; |
| - m_contentMapText[CFilter::contentTypeObjectSubrequest] = "OBJECT_SUBREQUEST"; |
| - m_contentMapText[CFilter::contentTypeImage] = "IMAGE"; |
| - m_contentMapText[CFilter::contentTypeScript] = "SCRIPT"; |
| - m_contentMapText[CFilter::contentTypeOther] = "OTHER"; |
| - m_contentMapText[CFilter::contentTypeUnknown] = "OTHER"; |
| - m_contentMapText[CFilter::contentTypeSubdocument] = "SUBDOCUMENT"; |
| - m_contentMapText[CFilter::contentTypeStyleSheet] = "STYLESHEET"; |
| - m_contentMapText[CFilter::contentTypeXmlHttpRequest] = "XMLHTTPREQUEST"; |
| - |
| - ClearFilters(); |
| -} |
| - |
| - |
| -bool CPluginFilter::AddFilterElementHide(CString filterText) |
| -{ |
| - DEBUG_FILTER("Input: " + filterText + " filterFile" + filterFile); |
| - CriticalSection::Lock filterEngineLock(s_criticalSectionFilterMap); |
| - { |
| - CString filterString = filterText; |
| - // Create filter descriptor |
| - std::auto_ptr<CFilterElementHide> filter; |
| - |
| - CString wholeFilterString = filterString; |
| - wchar_t separatorChar; |
| - do |
| - { |
| - int chunkEnd = filterText.FindOneOf(L"+>"); |
| - if (chunkEnd > 0) |
| - { |
| - separatorChar = filterText.GetAt(chunkEnd); |
| - } |
| - else |
| - { |
| - chunkEnd = filterText.GetLength(); |
| - separatorChar = L'\0'; |
| - } |
| - |
| - CString filterChunk = filterText.Left(chunkEnd).TrimRight(); |
| - std::auto_ptr<CFilterElementHide> filterParent(filter); |
| - |
| - filter.reset(new CFilterElementHide(filterChunk)); |
| - |
| - if (filterParent.get() != 0) |
| - { |
| - filter->m_predecessor.reset(filterParent.release()); |
| - } |
| - |
| - if (separatorChar != L'\0') // complex selector |
| - { |
| - filterText = filterText.Mid(chunkEnd + 1).TrimLeft(); |
| - if (separatorChar == '+') |
| - filter->m_type = CFilterElementHide::TRAVERSER_TYPE_IMMEDIATE; |
| - else if (separatorChar == '>') |
| - filter->m_type = CFilterElementHide::TRAVERSER_TYPE_PARENT; |
| - } |
| - else // Terminating element (simple selector) |
| - { |
| - if (!filter->m_tagId.IsEmpty()) |
| - { |
| - m_elementHideTagsId.insert(std::make_pair(std::make_pair(filter->m_tag, filter->m_tagId), *filter)); |
| - } |
| - else if (!filter->m_tagClassName.IsEmpty()) |
| - { |
| - m_elementHideTagsClass.insert(std::make_pair(std::make_pair(filter->m_tag, filter->m_tagClassName), *filter)); |
| - } |
| - else |
| - { |
| - std::pair<CString, CFilterElementHide> pair = std::make_pair(filter->m_tag, *filter); |
| - m_elementHideTags.insert(pair); |
| - } |
| - } |
| - } while (separatorChar != '\0'); |
| - } |
| - |
| - return true; |
| -} |
| - |
| -bool CPluginFilter::IsElementHidden(const std::wstring& tag, IHTMLElement* pEl, const std::wstring& domain, const std::wstring& indent) const |
| -{ |
| - CString tagCString = ToCString(tag); |
| - |
| - CString id; |
| - CComBSTR bstrId; |
| - if (SUCCEEDED(pEl->get_id(&bstrId)) && bstrId) |
| - { |
| - id = bstrId; |
| - } |
| - |
| - CString classNames; |
| - CComBSTR bstrClassNames; |
| - if (SUCCEEDED(pEl->get_className(&bstrClassNames)) && bstrClassNames) |
| - { |
| - classNames = bstrClassNames; |
| - } |
| - |
| - CriticalSection::Lock filterEngineLock(s_criticalSectionFilterMap); |
| - { |
| - // Search tag/id filters |
| - if (!id.IsEmpty()) |
| - { |
| - std::pair<TFilterElementHideTagsNamed::const_iterator, TFilterElementHideTagsNamed::const_iterator> idItEnum = |
| - m_elementHideTagsId.equal_range(std::make_pair(tagCString, id)); |
| - for (TFilterElementHideTagsNamed::const_iterator idIt = idItEnum.first; idIt != idItEnum.second; idIt ++) |
| - { |
| - if (idIt->second.IsMatchFilterElementHide(pEl)) |
| - { |
| -#ifdef ENABLE_DEBUG_RESULT |
| - DEBUG_HIDE_EL(indent + "HideEl::Found (tag/id) filter:" + idIt->second.m_filterText) |
| - CPluginDebug::DebugResultHiding(tagCString, L"id:" + id, idIt->second.m_filterText); |
| -#endif |
| - return true; |
| - } |
| - } |
| - |
| - // Search general id |
| - idItEnum = m_elementHideTagsId.equal_range(std::make_pair("", id)); |
| - for (TFilterElementHideTagsNamed::const_iterator idIt = idItEnum.first; idIt != idItEnum.second; idIt ++) |
| - { |
| - if (idIt->second.IsMatchFilterElementHide(pEl)) |
| - { |
| -#ifdef ENABLE_DEBUG_RESULT |
| - DEBUG_HIDE_EL(indent + "HideEl::Found (?/id) filter:" + idIt->second.m_filterText) |
| - CPluginDebug::DebugResultHiding(tagCString, L"id:" + id, idIt->second.m_filterText); |
| -#endif |
| - return true; |
| - } |
| - } |
| - } |
| - |
| - // Search tag/className filters |
| - if (!classNames.IsEmpty()) |
| - { |
| - int pos = 0; |
| - CString className = classNames.Tokenize(L" \t\n\r", pos); |
| - while (pos >= 0) |
| - { |
| - std::pair<TFilterElementHideTagsNamed::const_iterator, TFilterElementHideTagsNamed::const_iterator> classItEnum = |
| - m_elementHideTagsClass.equal_range(std::make_pair(tagCString, className)); |
| - |
| - for (TFilterElementHideTagsNamed::const_iterator classIt = classItEnum.first; classIt != classItEnum.second; ++classIt) |
| - { |
| - if (classIt->second.IsMatchFilterElementHide(pEl)) |
| - { |
| -#ifdef ENABLE_DEBUG_RESULT |
| - DEBUG_HIDE_EL(indent + "HideEl::Found (tag/class) filter:" + classIt->second.m_filterText) |
| - CPluginDebug::DebugResultHiding(tagCString, L"class:" + className, classIt->second.m_filterText); |
| -#endif |
| - return true; |
| - } |
| - } |
| - |
| - // Search general class name |
| - classItEnum = m_elementHideTagsClass.equal_range(std::make_pair("", className)); |
| - for (TFilterElementHideTagsNamed::const_iterator classIt = classItEnum.first; classIt != classItEnum.second; ++ classIt) |
| - { |
| - if (classIt->second.IsMatchFilterElementHide(pEl)) |
| - { |
| -#ifdef ENABLE_DEBUG_RESULT |
| - DEBUG_HIDE_EL(indent + "HideEl::Found (?/class) filter:" + classIt->second.m_filterText) |
| - CPluginDebug::DebugResultHiding(tagCString, "class:" + className, classIt->second.m_filterText); |
| -#endif |
| - return true; |
| - } |
| - } |
| - |
| - // Next class name |
| - className = classNames.Tokenize(L" \t\n\r", pos); |
| - } |
| - } |
| - |
| - // Search tag filters |
| - std::pair<TFilterElementHideTags::const_iterator, TFilterElementHideTags::const_iterator> tagItEnum |
| - = m_elementHideTags.equal_range(tagCString); |
| - for (TFilterElementHideTags::const_iterator tagIt = tagItEnum.first; tagIt != tagItEnum.second; ++ tagIt) |
| - { |
| - if (tagIt->second.IsMatchFilterElementHide(pEl)) |
| - { |
| -#ifdef ENABLE_DEBUG_RESULT |
| - DEBUG_HIDE_EL(indent + "HideEl::Found (tag) filter:" + tagIt->second.m_filterText) |
| - CPluginDebug::DebugResultHiding(tagCString, "-", tagIt->second.m_filterText); |
| -#endif |
| - return true; |
| - } |
| - } |
| - } |
| - |
| - return false; |
| -} |
| - |
| -bool CPluginFilter::LoadHideFilters(std::vector<std::wstring> filters) |
| -{ |
| - ClearFilters(); |
| - bool isRead = false; |
| - CPluginClient* client = CPluginClient::GetInstance(); |
| - |
| - // Parse hide string |
| - int pos = 0; |
| - CriticalSection::Lock filterEngineLock(s_criticalSectionFilterMap); |
| - { |
| - for (std::vector<std::wstring>::iterator it = filters.begin(); it < filters.end(); ++it) |
| - { |
| - CString filter((*it).c_str()); |
| - // If the line is not commented out |
| - if (!filter.Trim().IsEmpty() && filter.GetAt(0) != '!' && filter.GetAt(0) != '[') |
| - { |
| - int filterType = 0; |
| - |
| - // See http://adblockplus.org/en/filters for further documentation |
| - |
| - try |
| - { |
| - AddFilterElementHide(filter); |
| - } |
| - catch(...) |
| - { |
| -#ifdef ENABLE_DEBUG_RESULT |
| - CPluginDebug::DebugResult(L"Error loading hide filter: " + filter); |
| -#endif |
| - } |
| - } |
| - } |
| - } |
| - |
| - return isRead; |
| -} |
| - |
| -void CPluginFilter::ClearFilters() |
| -{ |
| - // Clear filter maps |
| - CriticalSection::Lock filterEngineLock(s_criticalSectionFilterMap); |
| - { |
| - for (int i = 0; i < 2; i++) |
| - { |
| - for (int j = 0; j < 2; j++) |
| - { |
| - m_filterMap[i][j].clear(); |
| - } |
| - m_filterMapDefault[i].clear(); |
| - } |
| - |
| - m_elementHideTags.clear(); |
| - m_elementHideTagsId.clear(); |
| - m_elementHideTagsClass.clear(); |
| - } |
| -} |
| - |
| -bool CPluginFilter::ShouldBlock(const std::wstring& src, int contentType, const std::wstring& domain, bool addDebug) const |
| -{ |
| - std::wstring srcTrimmed = TrimString(src); |
| - |
| - // We should not block the empty string, so all filtering does not make sense |
| - // Therefore we just return |
| - if (srcTrimmed.empty()) |
| - { |
| - return false; |
| - } |
| - CPluginSettings* settings = CPluginSettings::GetInstance(); |
| - |
| - CString type; |
| - if (addDebug) |
| - { |
| - type = "OTHER"; |
| - |
| - std::map<int,CString>::const_iterator it = m_contentMapText.find(contentType); |
| - if (it != m_contentMapText.end()) |
| - { |
| - type = it->second; |
| - } |
| - } |
| - |
| - CPluginClient* client = CPluginClient::GetInstance(); |
| - if (client->Matches(srcTrimmed, ToWstring(type), domain)) |
| - { |
| - if (addDebug) |
| - { |
| - DEBUG_FILTER("Filter::ShouldBlock " + type + " YES") |
| - |
| -#ifdef ENABLE_DEBUG_RESULT |
| - CPluginDebug::DebugResultBlocking(type, srcTrimmed, domain); |
| -#endif |
| - } |
| - return true; |
| - } |
| -#ifdef ENABLE_DEBUG_RESULT |
| - CPluginDebug::DebugResultIgnoring(type, srcTrimmed, domain); |
| -#endif |
| - return false; |
| -} |
| +#include "PluginStdAfx.h" |
| + |
| +#include "PluginFilter.h" |
| +#include "PluginSettings.h" |
| +#include "PluginClient.h" |
| +#include "PluginClientFactory.h" |
| +#include "PluginMutex.h" |
| +#include "PluginSettings.h" |
| +#include "PluginSystem.h" |
| +#include "PluginClass.h" |
| +#include "mlang.h" |
| + |
| +#include "..\shared\CriticalSection.h" |
| +#include "..\shared\Utils.h" |
| +#include "..\shared\ContentType.h" |
| + |
| + |
| +// The filters are described at http://adblockplus.org/en/filters |
| + |
| +static CriticalSection s_criticalSectionFilterMap; |
| + |
| +namespace |
| +{ |
| + struct GetHtmlElementAttributeResult |
| + { |
| + GetHtmlElementAttributeResult() : isAttributeFound(false) |
| + { |
| + } |
| + std::wstring attributeValue; |
| + bool isAttributeFound; |
| + }; |
| + |
| + GetHtmlElementAttributeResult GetHtmlElementAttribute(IHTMLElement& htmlElement, |
| + const ATL::CComBSTR& attributeName) |
| + { |
| + GetHtmlElementAttributeResult retValue; |
| + ATL::CComVariant vAttr; |
| + ATL::CComPtr<IHTMLElement4> htmlElement4; |
| + if (FAILED(htmlElement.QueryInterface(&htmlElement4)) || !htmlElement4) |
| + { |
| + return retValue; |
| + } |
| + ATL::CComPtr<IHTMLDOMAttribute> attributeNode; |
| + if (FAILED(htmlElement4->getAttributeNode(attributeName, &attributeNode)) || !attributeNode) |
| + { |
| + return retValue; |
| + } |
| + // we set that attribute found but it's not necessary that we can retrieve its value |
| + retValue.isAttributeFound = true; |
| + if (FAILED(attributeNode->get_nodeValue(&vAttr))) |
| + { |
| + return retValue; |
| + } |
| + if (vAttr.vt == VT_BSTR && vAttr.bstrVal) |
| + { |
| + retValue.attributeValue = vAttr.bstrVal; |
| + } |
| + else if (vAttr.vt == VT_I4) |
| + { |
| + retValue.attributeValue = std::to_wstring(vAttr.iVal); |
| + } |
| + return retValue; |
| + } |
| +} |
| + |
| +// ============================================================================ |
| +// CFilterElementHideAttrSelector |
| +// ============================================================================ |
| + |
| +CFilterElementHideAttrSelector::CFilterElementHideAttrSelector() : m_type(TYPE_NONE), m_pos(POS_NONE), m_bstrAttr(NULL) |
| +{ |
| +} |
| + |
| +CFilterElementHideAttrSelector::CFilterElementHideAttrSelector(const CFilterElementHideAttrSelector& filter) |
| +{ |
| + m_type = filter.m_type; |
| + m_pos = filter.m_pos; |
| + m_bstrAttr = filter.m_bstrAttr; |
| + |
| + m_value = filter.m_value; |
| +} |
| + |
| +CFilterElementHideAttrSelector::~CFilterElementHideAttrSelector() |
| +{ |
| +} |
| + |
| + |
| +// ============================================================================ |
| +// CFilterElementHide |
| +// ============================================================================ |
| + |
| +CFilterElementHide::CFilterElementHide(const CString& filterText) : m_filterText(filterText), m_type(ETraverserComplexType::TRAVERSER_TYPE_ERROR) |
| +{ |
| + // Find tag name, class or any (*) |
| + CString filterString = filterText; |
| + |
| + wchar_t firstTag = filterString.GetAt(0); |
| + // Any tag |
| + if (firstTag == '*') |
| + { |
| + filterString = filterString.Mid(1); |
| + } |
| + // Any tag (implicitely) |
| + else if (firstTag == '[' || firstTag == '.' || firstTag == '#') |
| + { |
| + } |
| + // Real tag |
| + else if (isalnum(firstTag)) |
| + { |
| + //TODO: Add support for descendant selectors |
| + int pos = filterString.FindOneOf(L".#[("); |
| + |
| + if (pos < 0) |
| + pos = filterString.GetLength(); |
| + m_tag = filterString.Left(pos).MakeLower(); |
| + |
| + filterString = filterString.Mid(pos); |
| + } |
| + // Error |
| + else |
| + { |
| + DEBUG_FILTER("Filter::Error parsing selector:" + filterText + " (invalid tag)"); |
| + throw std::runtime_error(CStringA("Filter::Error parsing selector:" + filterText + " (invalid tag)").GetString()); |
| + } |
| + |
| + // Find Id and class name |
| + |
| + if (!filterString.IsEmpty()) |
| + { |
| + wchar_t firstId = filterString.GetAt(0); |
| + |
| + // Id |
| + if (firstId == '#') |
| + { |
| + int pos = filterString.Find('['); |
| + if (pos < 0) |
| + { |
| + pos = filterString.GetLength(); |
| + } |
| + m_tagId = filterString.Mid(1, pos - 1); |
| + filterString = filterString.Mid(pos); |
| + pos = m_tagId.Find(L"."); |
| + if (pos > 0) |
| + { |
| + m_tagClassName = m_tagId.Mid(pos + 1); |
| + m_tagId = m_tagId.Left(pos); |
| + } |
| + } |
| + // Class name |
| + else if (firstId == '.') |
| + { |
| + int pos = filterString.Find('['); |
| + if (pos < 0) |
| + { |
| + pos = filterString.GetLength(); |
| + } |
| + m_tagClassName = filterString.Mid(1, pos - 1); |
| + filterString = filterString.Mid(pos); |
| + } |
| + } |
| + |
| + char chAttrStart = '['; |
| + char chAttrEnd = ']'; |
| + |
| + while (!filterString.IsEmpty()) |
| + { |
| + if (filterString.GetAt(0) != chAttrStart) |
| + { |
| + DEBUG_FILTER("Filter::Error parsing selector:" + filterText + " (more data)"); |
| + throw std::runtime_error(CStringA("Filter::Error parsing selector:" + filterText + " (more data)").GetString()); |
| + } |
| + int endPos = filterString.Find(']') ; |
| + if (endPos < 0) |
| + { |
| + DEBUG_FILTER("Filter::Error parsing selector:" + filterText + " (more data)"); |
| + throw std::runtime_error(CStringA("Filter::Error parsing selector:" + filterText + " (more data)").GetString()); |
| + } |
| + |
| + CFilterElementHideAttrSelector attrSelector; |
| + |
| + CString arg = filterString.Mid(1, endPos - 1); |
| + filterString = filterString.Mid(endPos + 1); |
| + |
| + int delimiterPos = arg.Find('='); |
| + if (delimiterPos > 0) |
| + { |
| + attrSelector.m_value = arg.Mid(delimiterPos + 1); |
| + if (attrSelector.m_value.GetLength() >= 2 && attrSelector.m_value.GetAt(0) == '\"' && attrSelector.m_value.GetAt(attrSelector.m_value.GetLength() - 1) == '\"') |
| + { |
| + attrSelector.m_value = attrSelector.m_value.Mid(1, attrSelector.m_value.GetLength() - 2); |
| + } |
| + |
| + if (arg.GetAt(delimiterPos - 1) == '^') |
| + { |
| + attrSelector.m_bstrAttr = arg.Left(delimiterPos - 1); |
| + attrSelector.m_pos = CFilterElementHideAttrPos::STARTING; |
| + } |
| + else if (arg.GetAt(delimiterPos - 1) == '*') |
| + { |
| + attrSelector.m_bstrAttr = arg.Left(delimiterPos - 1); |
| + attrSelector.m_pos = CFilterElementHideAttrPos::ANYWHERE; |
| + } |
| + else if (arg.GetAt(delimiterPos - 1) == '$') |
| + { |
| + attrSelector.m_bstrAttr = arg.Left(delimiterPos - 1); |
| + attrSelector.m_pos = CFilterElementHideAttrPos::ENDING; |
| + } |
| + else |
| + { |
| + attrSelector.m_bstrAttr = arg.Left(delimiterPos); |
| + attrSelector.m_pos = CFilterElementHideAttrPos::EXACT; |
| + } |
| + } |
| + CString tag = attrSelector.m_bstrAttr; |
| + if (tag == "style") |
| + { |
| + attrSelector.m_type = CFilterElementHideAttrType::STYLE; |
| + attrSelector.m_value.MakeLower(); |
| + } |
| + else if (tag == "id") |
| + { |
| + attrSelector.m_type = CFilterElementHideAttrType::ID; |
| + } |
| + else if (tag == "class") |
| + { |
| + attrSelector.m_type = CFilterElementHideAttrType::CLASS; |
| + } |
| + m_attributeSelectors.push_back(attrSelector); |
| + |
| + } |
| + |
| + // End check |
| + if (!filterString.IsEmpty()) |
| + { |
| + DEBUG_FILTER("Filter::Error parsing selector:" + filterFile + "/" + filterText + " (more data)") |
| + throw new std::runtime_error(CStringA("Filter::Error parsing selector:" + filterText + " (more data)").GetString()); |
| + } |
| +} |
| + |
| +CFilterElementHide::CFilterElementHide(const CFilterElementHide& filter) |
| +{ |
| + m_filterText = filter.m_filterText; |
| + |
| + m_tagId = filter.m_tagId; |
| + m_tagClassName = filter.m_tagClassName; |
| + |
| + m_attributeSelectors = filter.m_attributeSelectors; |
| + |
| + m_predecessor = filter.m_predecessor; |
| +} |
| + |
| + |
| +// ============================================================================ |
| +// CFilter |
| +// ============================================================================ |
| + |
| +CFilter::CFilter(const CFilter& filter) |
| +{ |
| + m_contentType = filter.m_contentType; |
| + m_filterType = filter.m_filterType; |
| + |
| + m_isFirstParty = filter.m_isFirstParty; |
| + m_isThirdParty = filter.m_isThirdParty; |
| + |
| + m_isMatchCase = filter.m_isMatchCase; |
| + m_isFromStart = filter.m_isFromStart; |
| + m_isFromEnd = filter.m_isFromEnd; |
| + |
| + m_filterText = filter.m_filterText; |
| + |
| + m_hitCount = filter.m_hitCount; |
| +} |
| + |
| + |
| +CFilter::CFilter() : m_isMatchCase(false), m_isFirstParty(false), |
| + m_isThirdParty(false), m_contentType(AdblockPlus::FilterEngine::ContentType::CONTENT_TYPE_OTHER), |
| + m_isFromStart(false), m_isFromEnd(false), m_hitCount(0) |
| +{ |
| +} |
| + |
| + |
| +bool CFilterElementHide::IsMatchFilterElementHide(IHTMLElement* pEl) const |
| +{ |
| + HRESULT hr; |
| + |
| + if (!m_tagId.IsEmpty()) |
| + { |
| + CComBSTR id; |
| + hr = pEl->get_id(&id); |
| + if ((hr != S_OK) || (id != CComBSTR(m_tagId))) |
| + { |
| + return false; |
| + } |
| + } |
| + if (!m_tagClassName.IsEmpty()) |
| + { |
| + CComBSTR classNameBSTR; |
| + hr = pEl->get_className(&classNameBSTR); |
| + if (hr == S_OK) |
| + { |
| + CString className = classNameBSTR; |
| + int start = 0; |
| + CString specificClass; |
| + bool foundMatch = false; |
| + while ((specificClass = className.Tokenize(L" ", start)) != L"") |
| + { |
| + // TODO: Consider case of multiple classes. (m_tagClassName can be something like "foo.bar") |
| + if (specificClass == m_tagClassName) |
| + { |
| + foundMatch = true; |
| + } |
| + } |
| + if (!foundMatch) |
| + { |
| + return false; |
| + } |
| + } |
| + } |
| + if (!m_tag.IsEmpty()) |
| + { |
| + CComBSTR tagName; |
| + hr = pEl->get_tagName(&tagName); |
| + tagName.ToLower(); |
| + if ((hr != S_OK) || (tagName != CComBSTR(m_tag))) |
| + { |
| + return false; |
| + } |
| + } |
| + |
| + // Check attributes |
| + for (std::vector<CFilterElementHideAttrSelector>::const_iterator attrIt = m_attributeSelectors.begin(); |
| + attrIt != m_attributeSelectors.end(); ++ attrIt) |
| + { |
| + ATL::CString value; |
| + bool attrFound = false; |
| + if (attrIt->m_type == CFilterElementHideAttrType::STYLE) |
| + { |
| + CComPtr<IHTMLStyle> pStyle; |
| + if (SUCCEEDED(pEl->get_style(&pStyle)) && pStyle) |
| + { |
| + CComBSTR bstrStyle; |
| + |
| + if (SUCCEEDED(pStyle->get_cssText(&bstrStyle)) && bstrStyle) |
| + { |
| + value = bstrStyle; |
| + value.MakeLower(); |
| + attrFound = true; |
| + } |
| + } |
| + } |
| + else if (attrIt->m_type == CFilterElementHideAttrType::CLASS) |
| + { |
| + CComBSTR bstrClassNames; |
| + if (SUCCEEDED(pEl->get_className(&bstrClassNames)) && bstrClassNames) |
| + { |
| + value = bstrClassNames; |
| + attrFound = true; |
| + } |
| + } |
| + else if (attrIt->m_type == CFilterElementHideAttrType::ID) |
| + { |
| + CComBSTR bstrId; |
| + if (SUCCEEDED(pEl->get_id(&bstrId)) && bstrId) |
| + { |
| + value = bstrId; |
| + attrFound = true; |
| + } |
| + } |
| + else |
| + { |
| + auto attributeValue = GetHtmlElementAttribute(*pEl, attrIt->m_bstrAttr); |
| + if (attrFound = attributeValue.isAttributeFound) |
| + { |
| + value = ToCString(attributeValue.attributeValue); |
| + } |
| + } |
| + |
| + if (attrFound) |
| + { |
| + if (attrIt->m_pos == CFilterElementHideAttrPos::EXACT) |
| + { |
| + // TODO: IE rearranges the style attribute completely. Figure out if anything can be done about it. |
| + if (value != attrIt->m_value) |
| + return false; |
| + } |
| + else if (attrIt->m_pos == CFilterElementHideAttrPos::STARTING) |
| + { |
| + if (value.Left(attrIt->m_value.GetLength()) != attrIt->m_value) |
| + return false; |
| + } |
| + else if (attrIt->m_pos == CFilterElementHideAttrPos::ENDING) |
| + { |
| + if (value.Right(attrIt->m_value.GetLength()) != attrIt->m_value) |
| + return false; |
| + } |
| + else if (attrIt->m_pos == CFilterElementHideAttrPos::ANYWHERE) |
| + { |
| + if (value.Find(attrIt->m_value) < 0) |
| + return false; |
| + } |
| + else if (attrIt->m_value.IsEmpty()) |
| + { |
| + return true; |
| + } |
| + } |
| + else |
| + { |
| + return false; |
| + } |
| + } |
| + |
| + if (m_predecessor) |
| + { |
| + CComPtr<IHTMLElement> pDomPredecessor; |
| + HRESULT hr = S_FALSE; |
| + switch (m_predecessor->m_type) |
| + { |
| + case ETraverserComplexType::TRAVERSER_TYPE_PARENT: |
| + hr = pEl->get_parentElement(&pDomPredecessor); |
| + break; |
| + case ETraverserComplexType::TRAVERSER_TYPE_IMMEDIATE: |
| + hr = S_FALSE; |
| + CComQIPtr<IHTMLDOMNode> pPrevSiblingNode = pEl; |
| + long type = 0; |
| + while (pPrevSiblingNode && type != 1) |
| + { |
| + IHTMLDOMNode* tmpNode; |
| + pPrevSiblingNode->get_previousSibling(&tmpNode); |
| + pPrevSiblingNode.Attach(tmpNode); |
| + if (pPrevSiblingNode) |
| + { |
| + hr = pPrevSiblingNode->get_nodeType(&type); |
| + if (hr != S_OK) |
| + pPrevSiblingNode.Release(); |
| + } |
| + } |
| + |
| + if (pPrevSiblingNode) |
| + hr = pPrevSiblingNode.QueryInterface(&pDomPredecessor); |
| + else |
| + return false; |
| + break; |
| + } |
| + if (hr != S_OK) |
| + return false; |
| + return m_predecessor->IsMatchFilterElementHide(pDomPredecessor); |
| + } |
| + |
| + return true; |
| +} |
| + |
| + |
| + |
| +// ============================================================================ |
| +// CPluginFilter |
| +// ============================================================================ |
| + |
| +CPluginFilter::CPluginFilter(const CString& dataPath) : m_dataPath(dataPath) |
| +{ |
| + ClearFilters(); |
| +} |
| + |
| + |
| +bool CPluginFilter::AddFilterElementHide(CString filterText) |
| +{ |
| + DEBUG_FILTER("Input: " + filterText + " filterFile" + filterFile); |
| + CriticalSection::Lock filterEngineLock(s_criticalSectionFilterMap); |
| + { |
| + CString filterString = filterText; |
| + // Create filter descriptor |
| + std::auto_ptr<CFilterElementHide> filter; |
| + |
| + CString wholeFilterString = filterString; |
| + wchar_t separatorChar; |
| + do |
| + { |
| + int chunkEnd = filterText.FindOneOf(L"+>"); |
| + if (chunkEnd > 0) |
| + { |
| + separatorChar = filterText.GetAt(chunkEnd); |
| + } |
| + else |
| + { |
| + chunkEnd = filterText.GetLength(); |
| + separatorChar = L'\0'; |
| + } |
| + |
| + CString filterChunk = filterText.Left(chunkEnd).TrimRight(); |
| + std::auto_ptr<CFilterElementHide> filterParent(filter); |
| + |
| + filter.reset(new CFilterElementHide(filterChunk)); |
| + |
| + if (filterParent.get() != 0) |
| + { |
| + filter->m_predecessor.reset(filterParent.release()); |
| + } |
| + |
| + if (separatorChar != L'\0') // complex selector |
| + { |
| + filterText = filterText.Mid(chunkEnd + 1).TrimLeft(); |
| + if (separatorChar == '+') |
| + filter->m_type = CFilterElementHide::TRAVERSER_TYPE_IMMEDIATE; |
| + else if (separatorChar == '>') |
| + filter->m_type = CFilterElementHide::TRAVERSER_TYPE_PARENT; |
| + } |
| + else // Terminating element (simple selector) |
| + { |
| + if (!filter->m_tagId.IsEmpty()) |
| + { |
| + m_elementHideTagsId.insert(std::make_pair(std::make_pair(filter->m_tag, filter->m_tagId), *filter)); |
| + } |
| + else if (!filter->m_tagClassName.IsEmpty()) |
| + { |
| + m_elementHideTagsClass.insert(std::make_pair(std::make_pair(filter->m_tag, filter->m_tagClassName), *filter)); |
| + } |
| + else |
| + { |
| + std::pair<CString, CFilterElementHide> pair = std::make_pair(filter->m_tag, *filter); |
| + m_elementHideTags.insert(pair); |
| + } |
| + } |
| + } while (separatorChar != '\0'); |
| + } |
| + |
| + return true; |
| +} |
| + |
| +bool CPluginFilter::IsElementHidden(const std::wstring& tag, IHTMLElement* pEl, const std::wstring& domain, const std::wstring& indent) const |
| +{ |
| + CString tagCString = ToCString(tag); |
| + |
| + CString id; |
| + CComBSTR bstrId; |
| + if (SUCCEEDED(pEl->get_id(&bstrId)) && bstrId) |
| + { |
| + id = bstrId; |
| + } |
| + |
| + CString classNames; |
| + CComBSTR bstrClassNames; |
| + if (SUCCEEDED(pEl->get_className(&bstrClassNames)) && bstrClassNames) |
| + { |
| + classNames = bstrClassNames; |
| + } |
| + |
| + CriticalSection::Lock filterEngineLock(s_criticalSectionFilterMap); |
| + { |
| + // Search tag/id filters |
| + if (!id.IsEmpty()) |
| + { |
| + std::pair<TFilterElementHideTagsNamed::const_iterator, TFilterElementHideTagsNamed::const_iterator> idItEnum = |
| + m_elementHideTagsId.equal_range(std::make_pair(tagCString, id)); |
| + for (TFilterElementHideTagsNamed::const_iterator idIt = idItEnum.first; idIt != idItEnum.second; idIt ++) |
| + { |
| + if (idIt->second.IsMatchFilterElementHide(pEl)) |
| + { |
| +#ifdef ENABLE_DEBUG_RESULT |
| + DEBUG_HIDE_EL(indent + "HideEl::Found (tag/id) filter:" + idIt->second.m_filterText) |
| + CPluginDebug::DebugResultHiding(tagCString, L"id:" + id, idIt->second.m_filterText); |
| +#endif |
| + return true; |
| + } |
| + } |
| + |
| + // Search general id |
| + idItEnum = m_elementHideTagsId.equal_range(std::make_pair("", id)); |
| + for (TFilterElementHideTagsNamed::const_iterator idIt = idItEnum.first; idIt != idItEnum.second; idIt ++) |
| + { |
| + if (idIt->second.IsMatchFilterElementHide(pEl)) |
| + { |
| +#ifdef ENABLE_DEBUG_RESULT |
| + DEBUG_HIDE_EL(indent + "HideEl::Found (?/id) filter:" + idIt->second.m_filterText) |
| + CPluginDebug::DebugResultHiding(tagCString, L"id:" + id, idIt->second.m_filterText); |
| +#endif |
| + return true; |
| + } |
| + } |
| + } |
| + |
| + // Search tag/className filters |
| + if (!classNames.IsEmpty()) |
| + { |
| + int pos = 0; |
| + CString className = classNames.Tokenize(L" \t\n\r", pos); |
| + while (pos >= 0) |
| + { |
| + std::pair<TFilterElementHideTagsNamed::const_iterator, TFilterElementHideTagsNamed::const_iterator> classItEnum = |
| + m_elementHideTagsClass.equal_range(std::make_pair(tagCString, className)); |
| + |
| + for (TFilterElementHideTagsNamed::const_iterator classIt = classItEnum.first; classIt != classItEnum.second; ++classIt) |
| + { |
| + if (classIt->second.IsMatchFilterElementHide(pEl)) |
| + { |
| +#ifdef ENABLE_DEBUG_RESULT |
| + DEBUG_HIDE_EL(indent + "HideEl::Found (tag/class) filter:" + classIt->second.m_filterText) |
| + CPluginDebug::DebugResultHiding(tagCString, L"class:" + className, classIt->second.m_filterText); |
| +#endif |
| + return true; |
| + } |
| + } |
| + |
| + // Search general class name |
| + classItEnum = m_elementHideTagsClass.equal_range(std::make_pair("", className)); |
| + for (TFilterElementHideTagsNamed::const_iterator classIt = classItEnum.first; classIt != classItEnum.second; ++ classIt) |
| + { |
| + if (classIt->second.IsMatchFilterElementHide(pEl)) |
| + { |
| +#ifdef ENABLE_DEBUG_RESULT |
| + DEBUG_HIDE_EL(indent + "HideEl::Found (?/class) filter:" + classIt->second.m_filterText) |
| + CPluginDebug::DebugResultHiding(tagCString, "class:" + className, classIt->second.m_filterText); |
| +#endif |
| + return true; |
| + } |
| + } |
| + |
| + // Next class name |
| + className = classNames.Tokenize(L" \t\n\r", pos); |
| + } |
| + } |
| + |
| + // Search tag filters |
| + std::pair<TFilterElementHideTags::const_iterator, TFilterElementHideTags::const_iterator> tagItEnum |
| + = m_elementHideTags.equal_range(tagCString); |
| + for (TFilterElementHideTags::const_iterator tagIt = tagItEnum.first; tagIt != tagItEnum.second; ++ tagIt) |
| + { |
| + if (tagIt->second.IsMatchFilterElementHide(pEl)) |
| + { |
| +#ifdef ENABLE_DEBUG_RESULT |
| + DEBUG_HIDE_EL(indent + "HideEl::Found (tag) filter:" + tagIt->second.m_filterText) |
| + CPluginDebug::DebugResultHiding(tagCString, "-", tagIt->second.m_filterText); |
| +#endif |
| + return true; |
| + } |
| + } |
| + } |
| + |
| + return false; |
| +} |
| + |
| +bool CPluginFilter::LoadHideFilters(std::vector<std::wstring> filters) |
| +{ |
| + ClearFilters(); |
| + bool isRead = false; |
| + CPluginClient* client = CPluginClient::GetInstance(); |
| + |
| + // Parse hide string |
| + int pos = 0; |
| + CriticalSection::Lock filterEngineLock(s_criticalSectionFilterMap); |
| + { |
| + for (std::vector<std::wstring>::iterator it = filters.begin(); it < filters.end(); ++it) |
| + { |
| + CString filter((*it).c_str()); |
| + // If the line is not commented out |
| + if (!filter.Trim().IsEmpty() && filter.GetAt(0) != '!' && filter.GetAt(0) != '[') |
| + { |
| + int filterType = 0; |
| + |
| + // See http://adblockplus.org/en/filters for further documentation |
| + |
| + try |
| + { |
| + AddFilterElementHide(filter); |
| + } |
| + catch(...) |
| + { |
| +#ifdef ENABLE_DEBUG_RESULT |
| + CPluginDebug::DebugResult(L"Error loading hide filter: " + filter); |
| +#endif |
| + } |
| + } |
| + } |
| + } |
| + |
| + return isRead; |
| +} |
| + |
| +void CPluginFilter::ClearFilters() |
| +{ |
| + // Clear filter maps |
| + CriticalSection::Lock filterEngineLock(s_criticalSectionFilterMap); |
| + { |
| + for (int i = 0; i < 2; i++) |
| + { |
| + for (int j = 0; j < 2; j++) |
| + { |
| + m_filterMap[i][j].clear(); |
| + } |
| + m_filterMapDefault[i].clear(); |
| + } |
| + |
| + m_elementHideTags.clear(); |
| + m_elementHideTagsId.clear(); |
| + m_elementHideTagsClass.clear(); |
| + } |
| +} |
| + |
| +bool CPluginFilter::ShouldBlock(const std::wstring& src, AdblockPlus::FilterEngine::ContentType contentType, const std::wstring& domain, bool addDebug) const |
| +{ |
| + std::wstring srcTrimmed = TrimString(src); |
| + |
| + // We should not block the empty string, so all filtering does not make sense |
| + // Therefore we just return |
| + if (srcTrimmed.empty()) |
| + { |
| + return false; |
| + } |
| + |
| + CPluginSettings* settings = CPluginSettings::GetInstance(); |
| + |
| + CPluginClient* client = CPluginClient::GetInstance(); |
| + bool result = client->Matches(srcTrimmed, contentType, domain); |
| + |
| +#ifdef ENABLE_DEBUG_RESULT |
| + if (addDebug) |
| + { |
| + std::wstring type = ToUtf16String(ContentTypeToString(contentType)); |
| + if (result) |
| + { |
| + CPluginDebug::DebugResultBlocking(ToCString(type), srcTrimmed, domain); |
| + } |
| + else |
| + { |
| + CPluginDebug::DebugResultIgnoring(ToCString(type), srcTrimmed, domain); |
| + } |
| + } |
| +#endif |
| + return result; |
| +} |