summaryrefslogtreecommitdiff
path: root/xfa/fde/css/cfde_cssselector.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'xfa/fde/css/cfde_cssselector.cpp')
-rw-r--r--xfa/fde/css/cfde_cssselector.cpp162
1 files changed, 162 insertions, 0 deletions
diff --git a/xfa/fde/css/cfde_cssselector.cpp b/xfa/fde/css/cfde_cssselector.cpp
new file mode 100644
index 0000000000..4d32bd1cfa
--- /dev/null
+++ b/xfa/fde/css/cfde_cssselector.cpp
@@ -0,0 +1,162 @@
+// Copyright 2017 PDFium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
+
+#include "xfa/fde/css/cfde_cssselector.h"
+
+#include <utility>
+
+#include "third_party/base/ptr_util.h"
+
+namespace {
+
+bool IsCSSChar(FX_WCHAR wch) {
+ return (wch >= 'a' && wch <= 'z') || (wch >= 'A' && wch <= 'Z');
+}
+
+int32_t GetCSSPseudoLen(const FX_WCHAR* psz, const FX_WCHAR* pEnd) {
+ ASSERT(*psz == ':');
+ const FX_WCHAR* pStart = psz;
+ while (psz < pEnd) {
+ FX_WCHAR wch = *psz;
+ if (IsCSSChar(wch) || wch == ':')
+ ++psz;
+ else
+ break;
+ }
+ return psz - pStart;
+}
+
+int32_t GetCSSNameLen(const FX_WCHAR* psz, const FX_WCHAR* pEnd) {
+ const FX_WCHAR* pStart = psz;
+ while (psz < pEnd) {
+ FX_WCHAR wch = *psz;
+ if (IsCSSChar(wch) || (wch >= '0' && wch <= '9') || wch == '_' ||
+ wch == '-') {
+ ++psz;
+ } else {
+ break;
+ }
+ }
+ return psz - pStart;
+}
+
+} // namespace
+
+CFDE_CSSSelector::CFDE_CSSSelector(FDE_CSSSelectorType eType,
+ const FX_WCHAR* psz,
+ int32_t iLen,
+ bool bIgnoreCase)
+ : m_eType(eType),
+ m_dwHash(FX_HashCode_GetW(CFX_WideStringC(psz, iLen), bIgnoreCase)) {}
+
+CFDE_CSSSelector::~CFDE_CSSSelector() {}
+
+FDE_CSSSelectorType CFDE_CSSSelector::GetType() const {
+ return m_eType;
+}
+
+uint32_t CFDE_CSSSelector::GetNameHash() const {
+ return m_dwHash;
+}
+
+CFDE_CSSSelector* CFDE_CSSSelector::GetNextSelector() const {
+ return m_pNext.get();
+}
+
+std::unique_ptr<CFDE_CSSSelector> CFDE_CSSSelector::ReleaseNextSelector() {
+ return std::move(m_pNext);
+}
+
+std::unique_ptr<CFDE_CSSSelector> CFDE_CSSSelector::FromString(
+ const FX_WCHAR* psz,
+ int32_t iLen) {
+ ASSERT(psz && iLen > 0);
+
+ const FX_WCHAR* pStart = psz;
+ const FX_WCHAR* pEnd = psz + iLen;
+ for (; psz < pEnd; ++psz) {
+ switch (*psz) {
+ case '>':
+ case '[':
+ case '+':
+ return nullptr;
+ }
+ }
+
+ std::unique_ptr<CFDE_CSSSelector> pFirst = nullptr;
+ CFDE_CSSSelector* pLast = nullptr;
+ std::unique_ptr<CFDE_CSSSelector> pPseudoFirst = nullptr;
+ CFDE_CSSSelector* pPseudoLast = nullptr;
+
+ for (psz = pStart; psz < pEnd;) {
+ FX_WCHAR wch = *psz;
+ if (wch == '.' || wch == '#') {
+ if (psz == pStart || psz[-1] == ' ') {
+ auto p = pdfium::MakeUnique<CFDE_CSSSelector>(
+ FDE_CSSSelectorType::Element, L"*", 1, true);
+
+ if (pFirst) {
+ pFirst->SetType(FDE_CSSSelectorType::Descendant);
+ p->SetNext(std::move(pFirst));
+ }
+ pFirst = std::move(p);
+ pLast = pFirst.get();
+ }
+ ASSERT(pLast);
+
+ int32_t iNameLen = GetCSSNameLen(++psz, pEnd);
+ if (iNameLen == 0)
+ return nullptr;
+
+ FDE_CSSSelectorType eType =
+ wch == '.' ? FDE_CSSSelectorType::Class : FDE_CSSSelectorType::ID;
+ auto p =
+ pdfium::MakeUnique<CFDE_CSSSelector>(eType, psz, iNameLen, false);
+
+ p->SetNext(pLast->ReleaseNextSelector());
+ pLast->SetNext(std::move(p));
+ pLast = pLast->GetNextSelector();
+ psz += iNameLen;
+ } else if (IsCSSChar(wch) || wch == '*') {
+ int32_t iNameLen = wch == '*' ? 1 : GetCSSNameLen(psz, pEnd);
+ if (iNameLen == 0)
+ return nullptr;
+
+ auto p = pdfium::MakeUnique<CFDE_CSSSelector>(
+ FDE_CSSSelectorType::Element, psz, iNameLen, true);
+ if (pFirst) {
+ pFirst->SetType(FDE_CSSSelectorType::Descendant);
+ p->SetNext(std::move(pFirst));
+ }
+ pFirst = std::move(p);
+ pLast = pFirst.get();
+ psz += iNameLen;
+ } else if (wch == ':') {
+ int32_t iNameLen = GetCSSPseudoLen(psz, pEnd);
+ if (iNameLen == 0)
+ return nullptr;
+
+ auto p = pdfium::MakeUnique<CFDE_CSSSelector>(FDE_CSSSelectorType::Pseudo,
+ psz, iNameLen, true);
+ CFDE_CSSSelector* ptr = p.get();
+ if (pPseudoFirst)
+ pPseudoLast->SetNext(std::move(p));
+ else
+ pPseudoFirst = std::move(p);
+ pPseudoLast = ptr;
+ psz += iNameLen;
+ } else if (wch == ' ') {
+ psz++;
+ } else {
+ return nullptr;
+ }
+ }
+ if (!pPseudoFirst)
+ return pFirst;
+
+ pPseudoLast->SetNext(std::move(pFirst));
+ return pPseudoFirst;
+}