// 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 "xfa/fde/css/cfde_csssyntaxparser.h" #include #include "core/fxcrt/fx_codepage.h" #include "core/fxcrt/fx_extension.h" #include "third_party/base/logging.h" #include "xfa/fde/css/cfde_cssdeclaration.h" #include "xfa/fde/css/fde_cssdatatable.h" namespace { bool IsSelectorStart(wchar_t wch) { return wch == '.' || wch == '#' || wch == '*' || FXSYS_iswalpha(wch); } } // namespace CFDE_CSSSyntaxParser::CFDE_CSSSyntaxParser(const wchar_t* pBuffer, int32_t iBufferSize) : CFDE_CSSSyntaxParser(pBuffer, iBufferSize, 32, false) {} CFDE_CSSSyntaxParser::CFDE_CSSSyntaxParser(const wchar_t* pBuffer, int32_t iBufferSize, int32_t iTextDatSize, bool bOnlyDeclaration) : m_iTextDataLen(0), m_dwCheck(0xFFFFFFFF), m_eStatus(FDE_CSSSyntaxStatus::None) { ASSERT(pBuffer && iBufferSize > 0 && iTextDatSize > 0); m_eMode = bOnlyDeclaration ? FDE_CSSSyntaxMode::PropertyName : FDE_CSSSyntaxMode::RuleSet; m_TextData.InitWithSize(iTextDatSize); m_TextPlane.AttachBuffer(pBuffer, iBufferSize); } CFDE_CSSSyntaxParser::~CFDE_CSSSyntaxParser() {} FDE_CSSSyntaxStatus CFDE_CSSSyntaxParser::DoSyntaxParse() { while (m_eStatus >= FDE_CSSSyntaxStatus::None) { if (m_TextPlane.IsEOF()) { if (m_eMode == FDE_CSSSyntaxMode::PropertyValue && m_TextData.GetLength() > 0) { SaveTextData(); m_eStatus = FDE_CSSSyntaxStatus::PropertyValue; return m_eStatus; } m_eStatus = FDE_CSSSyntaxStatus::EOS; return m_eStatus; } wchar_t wch; while (!m_TextPlane.IsEOF()) { wch = m_TextPlane.GetChar(); switch (m_eMode) { case FDE_CSSSyntaxMode::RuleSet: switch (wch) { case '}': m_TextPlane.MoveNext(); if (RestoreMode()) return FDE_CSSSyntaxStatus::DeclClose; m_eStatus = FDE_CSSSyntaxStatus::Error; return m_eStatus; case '/': if (m_TextPlane.GetNextChar() == '*') { m_ModeStack.push(m_eMode); SwitchMode(FDE_CSSSyntaxMode::Comment); break; } default: if (wch <= ' ') { m_TextPlane.MoveNext(); } else if (IsSelectorStart(wch)) { SwitchMode(FDE_CSSSyntaxMode::Selector); return FDE_CSSSyntaxStatus::StyleRule; } else { m_eStatus = FDE_CSSSyntaxStatus::Error; return m_eStatus; } break; } break; case FDE_CSSSyntaxMode::Selector: switch (wch) { case ',': m_TextPlane.MoveNext(); SwitchMode(FDE_CSSSyntaxMode::Selector); if (m_iTextDataLen > 0) return FDE_CSSSyntaxStatus::Selector; break; case '{': if (m_TextData.GetLength() > 0) { SaveTextData(); return FDE_CSSSyntaxStatus::Selector; } m_TextPlane.MoveNext(); m_ModeStack.push(FDE_CSSSyntaxMode::RuleSet); SwitchMode(FDE_CSSSyntaxMode::PropertyName); return FDE_CSSSyntaxStatus::DeclOpen; case '/': if (m_TextPlane.GetNextChar() == '*') { if (SwitchToComment() > 0) return FDE_CSSSyntaxStatus::Selector; break; } default: AppendChar(wch); break; } break; case FDE_CSSSyntaxMode::PropertyName: switch (wch) { case ':': m_TextPlane.MoveNext(); SwitchMode(FDE_CSSSyntaxMode::PropertyValue); return FDE_CSSSyntaxStatus::PropertyName; case '}': m_TextPlane.MoveNext(); if (RestoreMode()) return FDE_CSSSyntaxStatus::DeclClose; m_eStatus = FDE_CSSSyntaxStatus::Error; return m_eStatus; case '/': if (m_TextPlane.GetNextChar() == '*') { if (SwitchToComment() > 0) return FDE_CSSSyntaxStatus::PropertyName; break; } default: AppendChar(wch); break; } break; case FDE_CSSSyntaxMode::PropertyValue: switch (wch) { case ';': m_TextPlane.MoveNext(); case '}': SwitchMode(FDE_CSSSyntaxMode::PropertyName); return FDE_CSSSyntaxStatus::PropertyValue; case '/': if (m_TextPlane.GetNextChar() == '*') { if (SwitchToComment() > 0) return FDE_CSSSyntaxStatus::PropertyValue; break; } default: AppendChar(wch); break; } break; case FDE_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 FDE_CSSSyntaxMode::UnknownRule: if (wch == ';') SwitchMode(FDE_CSSSyntaxMode::RuleSet); m_TextPlane.MoveNext(); break; default: NOTREACHED(); break; } } } return m_eStatus; } bool CFDE_CSSSyntaxParser::IsImportEnabled() const { if ((m_dwCheck & FDE_CSSSYNTAXCHECK_AllowImport) == 0) return false; if (m_ModeStack.size() > 1) return false; return true; } bool CFDE_CSSSyntaxParser::AppendChar(wchar_t wch) { m_TextPlane.MoveNext(); if (m_TextData.GetLength() > 0 || wch > ' ') { m_TextData.AppendChar(wch); return true; } return false; } int32_t CFDE_CSSSyntaxParser::SaveTextData() { m_iTextDataLen = m_TextData.TrimEnd(); m_TextData.Clear(); return m_iTextDataLen; } void CFDE_CSSSyntaxParser::SwitchMode(FDE_CSSSyntaxMode eMode) { m_eMode = eMode; SaveTextData(); } int32_t CFDE_CSSSyntaxParser::SwitchToComment() { int32_t iLength = m_TextData.GetLength(); m_ModeStack.push(m_eMode); SwitchMode(FDE_CSSSyntaxMode::Comment); return iLength; } bool CFDE_CSSSyntaxParser::RestoreMode() { if (m_ModeStack.empty()) return false; SwitchMode(m_ModeStack.top()); m_ModeStack.pop(); return true; } CFX_WideStringC CFDE_CSSSyntaxParser::GetCurrentString() const { return CFX_WideStringC(m_TextData.GetBuffer(), m_iTextDataLen); }