diff options
Diffstat (limited to 'core/fxcrt/css/cfx_csssyntaxparser.cpp')
-rw-r--r-- | core/fxcrt/css/cfx_csssyntaxparser.cpp | 228 |
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); +} |