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; }
bool CFilterElementHide::IsMatchFilterElementHide(IHTMLElement* pEl) const { HRESULT hr; /* * If a tag id is specified, it must match */ if (!m_tagId.empty()) { CComBSTR idBstr; if (FAILED(pEl->get_id(&idBstr)) || !idBstr || m_tagId != ToWstring(idBstr)) { return false; } } /* * If a class name is specified, it must match */ if (!m_tagClassName.empty()) { CComBSTR classNameListBstr; hr = pEl->get_className(&classNameListBstr); if (FAILED(hr) || !classNameListBstr) { return false; // We can't match a class name if there's no class name } std::wstring classNameList(ToWstring(classNameListBstr)); if (classNameList.empty()) { return false; } // TODO: Consider case of multiple classes. (m_tagClassName can be something like "foo.bar") /* * Match when 'm_tagClassName' appears as a token within classNameList */ bool foundMatch = false; wchar_t* nextToken = nullptr; const wchar_t* token = wcstok_s(&classNameList[0], L" ", &nextToken); while (token != nullptr) { if (std::wstring(token) == m_tagClassName) { foundMatch = true; break; } token = wcstok_s(nullptr, L" ", &nextToken); } if (!foundMatch) { return false; } } /* * If a tag name is specified, it must match */ if (!m_tag.empty()) { CComBSTR tagNameBstr; if (FAILED(pEl->get_tagName(&tagNameBstr)) || !tagNameBstr) { return false; } if (m_tag != ToLowerString(ToWstring(tagNameBstr))) { return false; } } /* * Match each attribute */ for (auto attrIt = m_attributeSelectors.begin(); attrIt != m_attributeSelectors.end(); ++attrIt) { std::wstring value; bool attrFound = false; if (attrIt->m_type == CFilterElementHideAttrType::STYLE) { CComPtr<IHTMLStyle> pStyle; if (SUCCEEDED(pEl->get_style(&pStyle)) && pStyle) { CComBSTR styleBstr; if (SUCCEEDED(pStyle->get_cssText(&styleBstr)) && styleBstr) { value = ToLowerString(ToWstring(styleBstr)); attrFound = true; } } } else if (attrIt->m_type == CFilterElementHideAttrType::CLASS) { CComBSTR classNamesBstr; if (SUCCEEDED(pEl->get_className(&classNamesBstr)) && classNamesBstr) { value = ToWstring(classNamesBstr); attrFound = true; } } else if (attrIt->m_type == CFilterElementHideAttrType::ID) { CComBSTR idBstr; if (SUCCEEDED(pEl->get_id(&idBstr)) && idBstr) { value = ToWstring(idBstr); attrFound = true; } } else { CComBSTR attrArgument(attrIt->m_attr.length(), attrIt->m_attr.c_str()); auto x = GetHtmlElementAttribute(*pEl, attrArgument); attrFound = x.isAttributeFound; if (attrFound) { value = x.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.compare(0, attrIt->m_value.length(), attrIt->m_value) != 0) return false; } else if (attrIt->m_pos == CFilterElementHideAttrPos::ENDING) { size_t valueLength = value.length(); size_t attrLength = attrIt->m_value.length(); if (valueLength < attrLength) return false; if (value.compare(valueLength - attrLength, attrLength, attrIt->m_value) != 0) return false; } else if (attrIt->m_pos == CFilterElementHideAttrPos::ANYWHERE) { if (value.find(attrIt->m_value) == std::wstring::npos) return false; } else if (attrIt->m_value.empty()) { 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; }