| // 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_cssstylesheet.h" | 
 |  | 
 | #include <utility> | 
 |  | 
 | #include "core/fxcrt/fx_codepage.h" | 
 | #include "third_party/base/ptr_util.h" | 
 | #include "third_party/base/stl_util.h" | 
 | #include "xfa/fde/css/cfde_cssdeclaration.h" | 
 | #include "xfa/fde/css/cfde_cssstylerule.h" | 
 | #include "xfa/fde/css/fde_cssdatatable.h" | 
 |  | 
 | CFDE_CSSStyleSheet::CFDE_CSSStyleSheet() {} | 
 |  | 
 | CFDE_CSSStyleSheet::~CFDE_CSSStyleSheet() { | 
 |   Reset(); | 
 | } | 
 |  | 
 | void CFDE_CSSStyleSheet::Reset() { | 
 |   m_RuleArray.clear(); | 
 |   m_StringCache.clear(); | 
 | } | 
 |  | 
 | int32_t CFDE_CSSStyleSheet::CountRules() const { | 
 |   return pdfium::CollectionSize<int32_t>(m_RuleArray); | 
 | } | 
 |  | 
 | CFDE_CSSStyleRule* CFDE_CSSStyleSheet::GetRule(int32_t index) const { | 
 |   return m_RuleArray[index].get(); | 
 | } | 
 |  | 
 | bool CFDE_CSSStyleSheet::LoadBuffer(const wchar_t* pBuffer, int32_t iBufSize) { | 
 |   ASSERT(pBuffer && iBufSize > 0); | 
 |  | 
 |   auto pSyntax = pdfium::MakeUnique<CFDE_CSSSyntaxParser>(); | 
 |   if (!pSyntax->Init(pBuffer, iBufSize)) | 
 |     return false; | 
 |  | 
 |   Reset(); | 
 |   FDE_CSSSyntaxStatus eStatus; | 
 |   do { | 
 |     switch (eStatus = pSyntax->DoSyntaxParse()) { | 
 |       case FDE_CSSSyntaxStatus::StyleRule: | 
 |         eStatus = LoadStyleRule(pSyntax.get(), &m_RuleArray); | 
 |         break; | 
 |       default: | 
 |         break; | 
 |     } | 
 |   } while (eStatus >= FDE_CSSSyntaxStatus::None); | 
 |  | 
 |   m_StringCache.clear(); | 
 |   return eStatus != FDE_CSSSyntaxStatus::Error; | 
 | } | 
 |  | 
 | FDE_CSSSyntaxStatus CFDE_CSSStyleSheet::LoadStyleRule( | 
 |     CFDE_CSSSyntaxParser* pSyntax, | 
 |     std::vector<std::unique_ptr<CFDE_CSSStyleRule>>* ruleArray) { | 
 |   std::vector<std::unique_ptr<CFDE_CSSSelector>> selectors; | 
 |  | 
 |   CFDE_CSSStyleRule* pStyleRule = nullptr; | 
 |   int32_t iValueLen = 0; | 
 |   const FDE_CSSPropertyTable* propertyTable = nullptr; | 
 |   CFX_WideString wsName; | 
 |   while (1) { | 
 |     switch (pSyntax->DoSyntaxParse()) { | 
 |       case FDE_CSSSyntaxStatus::Selector: { | 
 |         CFX_WideStringC strValue = pSyntax->GetCurrentString(); | 
 |         auto pSelector = CFDE_CSSSelector::FromString(strValue); | 
 |         if (pSelector) | 
 |           selectors.push_back(std::move(pSelector)); | 
 |         break; | 
 |       } | 
 |       case FDE_CSSSyntaxStatus::PropertyName: { | 
 |         CFX_WideStringC strValue = pSyntax->GetCurrentString(); | 
 |         propertyTable = FDE_GetCSSPropertyByName(strValue); | 
 |         if (!propertyTable) | 
 |           wsName = CFX_WideString(strValue); | 
 |         break; | 
 |       } | 
 |       case FDE_CSSSyntaxStatus::PropertyValue: { | 
 |         if (propertyTable || iValueLen > 0) { | 
 |           CFX_WideStringC strValue = pSyntax->GetCurrentString(); | 
 |           auto* decl = pStyleRule->GetDeclaration(); | 
 |           if (!strValue.IsEmpty()) { | 
 |             if (propertyTable) { | 
 |               decl->AddProperty(propertyTable, strValue); | 
 |             } else { | 
 |               decl->AddProperty(wsName, CFX_WideString(strValue)); | 
 |             } | 
 |           } | 
 |         } | 
 |         break; | 
 |       } | 
 |       case FDE_CSSSyntaxStatus::DeclOpen: { | 
 |         if (!pStyleRule && !selectors.empty()) { | 
 |           auto rule = pdfium::MakeUnique<CFDE_CSSStyleRule>(); | 
 |           pStyleRule = rule.get(); | 
 |           pStyleRule->SetSelector(&selectors); | 
 |           ruleArray->push_back(std::move(rule)); | 
 |         } else { | 
 |           SkipRuleSet(pSyntax); | 
 |           return FDE_CSSSyntaxStatus::None; | 
 |         } | 
 |         break; | 
 |       } | 
 |       case FDE_CSSSyntaxStatus::DeclClose: { | 
 |         if (pStyleRule && pStyleRule->GetDeclaration()->empty()) { | 
 |           ruleArray->pop_back(); | 
 |           pStyleRule = nullptr; | 
 |         } | 
 |         return FDE_CSSSyntaxStatus::None; | 
 |       } | 
 |       case FDE_CSSSyntaxStatus::EOS: | 
 |         return FDE_CSSSyntaxStatus::EOS; | 
 |       case FDE_CSSSyntaxStatus::Error: | 
 |       default: | 
 |         return FDE_CSSSyntaxStatus::Error; | 
 |     } | 
 |   } | 
 | } | 
 |  | 
 | void CFDE_CSSStyleSheet::SkipRuleSet(CFDE_CSSSyntaxParser* pSyntax) { | 
 |   while (1) { | 
 |     switch (pSyntax->DoSyntaxParse()) { | 
 |       case FDE_CSSSyntaxStatus::Selector: | 
 |       case FDE_CSSSyntaxStatus::DeclOpen: | 
 |       case FDE_CSSSyntaxStatus::PropertyName: | 
 |       case FDE_CSSSyntaxStatus::PropertyValue: | 
 |         break; | 
 |       case FDE_CSSSyntaxStatus::DeclClose: | 
 |       case FDE_CSSSyntaxStatus::EOS: | 
 |       case FDE_CSSSyntaxStatus::Error: | 
 |       default: | 
 |         return; | 
 |     } | 
 |   } | 
 | } |