summaryrefslogtreecommitdiff
path: root/core/fxcrt/css/cfx_csssyntaxparser.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'core/fxcrt/css/cfx_csssyntaxparser.cpp')
-rw-r--r--core/fxcrt/css/cfx_csssyntaxparser.cpp228
1 files changed, 228 insertions, 0 deletions
diff --git a/core/fxcrt/css/cfx_csssyntaxparser.cpp b/core/fxcrt/css/cfx_csssyntaxparser.cpp
new file mode 100644
index 0000000000..c8082e87fb
--- /dev/null
+++ b/core/fxcrt/css/cfx_csssyntaxparser.cpp
@@ -0,0 +1,228 @@
+// Copyright 2014 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 "core/fxcrt/css/cfx_csssyntaxparser.h"
+
+#include <algorithm>
+
+#include "core/fxcrt/css/cfx_cssdatatable.h"
+#include "core/fxcrt/css/cfx_cssdeclaration.h"
+#include "core/fxcrt/fx_codepage.h"
+#include "core/fxcrt/fx_extension.h"
+#include "third_party/base/logging.h"
+
+namespace {
+
+bool IsSelectorStart(wchar_t wch) {
+ return wch == '.' || wch == '#' || wch == '*' || FXSYS_iswalpha(wch);
+}
+
+} // namespace
+
+CFX_CSSSyntaxParser::CFX_CSSSyntaxParser(const wchar_t* pBuffer,
+ int32_t iBufferSize)
+ : CFX_CSSSyntaxParser(pBuffer, iBufferSize, 32, false) {}
+
+CFX_CSSSyntaxParser::CFX_CSSSyntaxParser(const wchar_t* pBuffer,
+ int32_t iBufferSize,
+ int32_t iTextDatSize,
+ bool bOnlyDeclaration)
+ : m_iTextDataLen(0),
+ m_dwCheck(0xFFFFFFFF),
+ m_eStatus(CFX_CSSSyntaxStatus::None) {
+ ASSERT(pBuffer && iBufferSize > 0 && iTextDatSize > 0);
+ m_eMode = bOnlyDeclaration ? CFX_CSSSyntaxMode::PropertyName
+ : CFX_CSSSyntaxMode::RuleSet;
+ m_TextData.InitWithSize(iTextDatSize);
+ m_TextPlane.AttachBuffer(pBuffer, iBufferSize);
+}
+
+CFX_CSSSyntaxParser::~CFX_CSSSyntaxParser() {}
+
+CFX_CSSSyntaxStatus CFX_CSSSyntaxParser::DoSyntaxParse() {
+ while (m_eStatus >= CFX_CSSSyntaxStatus::None) {
+ if (m_TextPlane.IsEOF()) {
+ if (m_eMode == CFX_CSSSyntaxMode::PropertyValue &&
+ m_TextData.GetLength() > 0) {
+ SaveTextData();
+ m_eStatus = CFX_CSSSyntaxStatus::PropertyValue;
+ return m_eStatus;
+ }
+ m_eStatus = CFX_CSSSyntaxStatus::EOS;
+ return m_eStatus;
+ }
+ wchar_t wch;
+ while (!m_TextPlane.IsEOF()) {
+ wch = m_TextPlane.GetChar();
+ switch (m_eMode) {
+ case CFX_CSSSyntaxMode::RuleSet:
+ switch (wch) {
+ case '}':
+ m_TextPlane.MoveNext();
+ if (RestoreMode())
+ return CFX_CSSSyntaxStatus::DeclClose;
+
+ m_eStatus = CFX_CSSSyntaxStatus::Error;
+ return m_eStatus;
+ case '/':
+ if (m_TextPlane.GetNextChar() == '*') {
+ m_ModeStack.push(m_eMode);
+ SwitchMode(CFX_CSSSyntaxMode::Comment);
+ break;
+ }
+ default:
+ if (wch <= ' ') {
+ m_TextPlane.MoveNext();
+ } else if (IsSelectorStart(wch)) {
+ SwitchMode(CFX_CSSSyntaxMode::Selector);
+ return CFX_CSSSyntaxStatus::StyleRule;
+ } else {
+ m_eStatus = CFX_CSSSyntaxStatus::Error;
+ return m_eStatus;
+ }
+ break;
+ }
+ break;
+ case CFX_CSSSyntaxMode::Selector:
+ switch (wch) {
+ case ',':
+ m_TextPlane.MoveNext();
+ SwitchMode(CFX_CSSSyntaxMode::Selector);
+ if (m_iTextDataLen > 0)
+ return CFX_CSSSyntaxStatus::Selector;
+ break;
+ case '{':
+ if (m_TextData.GetLength() > 0) {
+ SaveTextData();
+ return CFX_CSSSyntaxStatus::Selector;
+ }
+ m_TextPlane.MoveNext();
+ m_ModeStack.push(CFX_CSSSyntaxMode::RuleSet);
+ SwitchMode(CFX_CSSSyntaxMode::PropertyName);
+ return CFX_CSSSyntaxStatus::DeclOpen;
+ case '/':
+ if (m_TextPlane.GetNextChar() == '*') {
+ if (SwitchToComment() > 0)
+ return CFX_CSSSyntaxStatus::Selector;
+ break;
+ }
+ default:
+ AppendChar(wch);
+ break;
+ }
+ break;
+ case CFX_CSSSyntaxMode::PropertyName:
+ switch (wch) {
+ case ':':
+ m_TextPlane.MoveNext();
+ SwitchMode(CFX_CSSSyntaxMode::PropertyValue);
+ return CFX_CSSSyntaxStatus::PropertyName;
+ case '}':
+ m_TextPlane.MoveNext();
+ if (RestoreMode())
+ return CFX_CSSSyntaxStatus::DeclClose;
+
+ m_eStatus = CFX_CSSSyntaxStatus::Error;
+ return m_eStatus;
+ case '/':
+ if (m_TextPlane.GetNextChar() == '*') {
+ if (SwitchToComment() > 0)
+ return CFX_CSSSyntaxStatus::PropertyName;
+ break;
+ }
+ default:
+ AppendChar(wch);
+ break;
+ }
+ break;
+ case CFX_CSSSyntaxMode::PropertyValue:
+ switch (wch) {
+ case ';':
+ m_TextPlane.MoveNext();
+ case '}':
+ SwitchMode(CFX_CSSSyntaxMode::PropertyName);
+ return CFX_CSSSyntaxStatus::PropertyValue;
+ case '/':
+ if (m_TextPlane.GetNextChar() == '*') {
+ if (SwitchToComment() > 0)
+ return CFX_CSSSyntaxStatus::PropertyValue;
+ break;
+ }
+ default:
+ AppendChar(wch);
+ break;
+ }
+ break;
+ case CFX_CSSSyntaxMode::Comment:
+ if (wch == '/' && m_TextData.GetLength() > 0 &&
+ m_TextData.GetBuffer()[m_TextData.GetLength() - 1] == '*') {
+ RestoreMode();
+ } else {
+ m_TextData.AppendChar(wch);
+ }
+ m_TextPlane.MoveNext();
+ break;
+ case CFX_CSSSyntaxMode::UnknownRule:
+ if (wch == ';')
+ SwitchMode(CFX_CSSSyntaxMode::RuleSet);
+ m_TextPlane.MoveNext();
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+ }
+ }
+ return m_eStatus;
+}
+
+bool CFX_CSSSyntaxParser::IsImportEnabled() const {
+ if ((m_dwCheck & CFX_CSSSYNTAXCHECK_AllowImport) == 0)
+ return false;
+ if (m_ModeStack.size() > 1)
+ return false;
+ return true;
+}
+
+bool CFX_CSSSyntaxParser::AppendChar(wchar_t wch) {
+ m_TextPlane.MoveNext();
+ if (m_TextData.GetLength() > 0 || wch > ' ') {
+ m_TextData.AppendChar(wch);
+ return true;
+ }
+ return false;
+}
+
+int32_t CFX_CSSSyntaxParser::SaveTextData() {
+ m_iTextDataLen = m_TextData.TrimEnd();
+ m_TextData.Clear();
+ return m_iTextDataLen;
+}
+
+void CFX_CSSSyntaxParser::SwitchMode(CFX_CSSSyntaxMode eMode) {
+ m_eMode = eMode;
+ SaveTextData();
+}
+
+int32_t CFX_CSSSyntaxParser::SwitchToComment() {
+ int32_t iLength = m_TextData.GetLength();
+ m_ModeStack.push(m_eMode);
+ SwitchMode(CFX_CSSSyntaxMode::Comment);
+ return iLength;
+}
+
+bool CFX_CSSSyntaxParser::RestoreMode() {
+ if (m_ModeStack.empty())
+ return false;
+
+ SwitchMode(m_ModeStack.top());
+ m_ModeStack.pop();
+ return true;
+}
+
+CFX_WideStringC CFX_CSSSyntaxParser::GetCurrentString() const {
+ return CFX_WideStringC(m_TextData.GetBuffer(), m_iTextDataLen);
+}