• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6 
7 #include "core/fxcrt/css/cfx_csssyntaxparser.h"
8 
9 #include <algorithm>
10 
11 #include "core/fxcrt/css/cfx_cssdatatable.h"
12 #include "core/fxcrt/css/cfx_cssdeclaration.h"
13 #include "core/fxcrt/fx_codepage.h"
14 #include "core/fxcrt/fx_extension.h"
15 #include "third_party/base/logging.h"
16 
17 namespace {
18 
IsSelectorStart(wchar_t wch)19 bool IsSelectorStart(wchar_t wch) {
20   return wch == '.' || wch == '#' || wch == '*' || FXSYS_iswalpha(wch);
21 }
22 
23 }  // namespace
24 
CFX_CSSSyntaxParser(const wchar_t * pBuffer,int32_t iBufferSize)25 CFX_CSSSyntaxParser::CFX_CSSSyntaxParser(const wchar_t* pBuffer,
26                                          int32_t iBufferSize)
27     : CFX_CSSSyntaxParser(pBuffer, iBufferSize, 32, false) {}
28 
CFX_CSSSyntaxParser(const wchar_t * pBuffer,int32_t iBufferSize,int32_t iTextDatSize,bool bOnlyDeclaration)29 CFX_CSSSyntaxParser::CFX_CSSSyntaxParser(const wchar_t* pBuffer,
30                                          int32_t iBufferSize,
31                                          int32_t iTextDatSize,
32                                          bool bOnlyDeclaration)
33     : m_iTextDataLen(0),
34       m_dwCheck(0xFFFFFFFF),
35       m_eStatus(CFX_CSSSyntaxStatus::None) {
36   ASSERT(pBuffer && iBufferSize > 0 && iTextDatSize > 0);
37   m_eMode = bOnlyDeclaration ? CFX_CSSSyntaxMode::PropertyName
38                              : CFX_CSSSyntaxMode::RuleSet;
39   m_TextData.InitWithSize(iTextDatSize);
40   m_TextPlane.AttachBuffer(pBuffer, iBufferSize);
41 }
42 
~CFX_CSSSyntaxParser()43 CFX_CSSSyntaxParser::~CFX_CSSSyntaxParser() {}
44 
DoSyntaxParse()45 CFX_CSSSyntaxStatus CFX_CSSSyntaxParser::DoSyntaxParse() {
46   while (m_eStatus >= CFX_CSSSyntaxStatus::None) {
47     if (m_TextPlane.IsEOF()) {
48       if (m_eMode == CFX_CSSSyntaxMode::PropertyValue &&
49           m_TextData.GetLength() > 0) {
50         SaveTextData();
51         m_eStatus = CFX_CSSSyntaxStatus::PropertyValue;
52         return m_eStatus;
53       }
54       m_eStatus = CFX_CSSSyntaxStatus::EOS;
55       return m_eStatus;
56     }
57     wchar_t wch;
58     while (!m_TextPlane.IsEOF()) {
59       wch = m_TextPlane.GetChar();
60       switch (m_eMode) {
61         case CFX_CSSSyntaxMode::RuleSet:
62           switch (wch) {
63             case '}':
64               m_TextPlane.MoveNext();
65               if (RestoreMode())
66                 return CFX_CSSSyntaxStatus::DeclClose;
67 
68               m_eStatus = CFX_CSSSyntaxStatus::Error;
69               return m_eStatus;
70             case '/':
71               if (m_TextPlane.GetNextChar() == '*') {
72                 m_ModeStack.push(m_eMode);
73                 SwitchMode(CFX_CSSSyntaxMode::Comment);
74                 break;
75               }
76             default:
77               if (wch <= ' ') {
78                 m_TextPlane.MoveNext();
79               } else if (IsSelectorStart(wch)) {
80                 SwitchMode(CFX_CSSSyntaxMode::Selector);
81                 return CFX_CSSSyntaxStatus::StyleRule;
82               } else {
83                 m_eStatus = CFX_CSSSyntaxStatus::Error;
84                 return m_eStatus;
85               }
86               break;
87           }
88           break;
89         case CFX_CSSSyntaxMode::Selector:
90           switch (wch) {
91             case ',':
92               m_TextPlane.MoveNext();
93               SwitchMode(CFX_CSSSyntaxMode::Selector);
94               if (m_iTextDataLen > 0)
95                 return CFX_CSSSyntaxStatus::Selector;
96               break;
97             case '{':
98               if (m_TextData.GetLength() > 0) {
99                 SaveTextData();
100                 return CFX_CSSSyntaxStatus::Selector;
101               }
102               m_TextPlane.MoveNext();
103               m_ModeStack.push(CFX_CSSSyntaxMode::RuleSet);
104               SwitchMode(CFX_CSSSyntaxMode::PropertyName);
105               return CFX_CSSSyntaxStatus::DeclOpen;
106             case '/':
107               if (m_TextPlane.GetNextChar() == '*') {
108                 if (SwitchToComment() > 0)
109                   return CFX_CSSSyntaxStatus::Selector;
110                 break;
111               }
112             default:
113               AppendChar(wch);
114               break;
115           }
116           break;
117         case CFX_CSSSyntaxMode::PropertyName:
118           switch (wch) {
119             case ':':
120               m_TextPlane.MoveNext();
121               SwitchMode(CFX_CSSSyntaxMode::PropertyValue);
122               return CFX_CSSSyntaxStatus::PropertyName;
123             case '}':
124               m_TextPlane.MoveNext();
125               if (RestoreMode())
126                 return CFX_CSSSyntaxStatus::DeclClose;
127 
128               m_eStatus = CFX_CSSSyntaxStatus::Error;
129               return m_eStatus;
130             case '/':
131               if (m_TextPlane.GetNextChar() == '*') {
132                 if (SwitchToComment() > 0)
133                   return CFX_CSSSyntaxStatus::PropertyName;
134                 break;
135               }
136             default:
137               AppendChar(wch);
138               break;
139           }
140           break;
141         case CFX_CSSSyntaxMode::PropertyValue:
142           switch (wch) {
143             case ';':
144               m_TextPlane.MoveNext();
145             case '}':
146               SwitchMode(CFX_CSSSyntaxMode::PropertyName);
147               return CFX_CSSSyntaxStatus::PropertyValue;
148             case '/':
149               if (m_TextPlane.GetNextChar() == '*') {
150                 if (SwitchToComment() > 0)
151                   return CFX_CSSSyntaxStatus::PropertyValue;
152                 break;
153               }
154             default:
155               AppendChar(wch);
156               break;
157           }
158           break;
159         case CFX_CSSSyntaxMode::Comment:
160           if (wch == '/' && m_TextData.GetLength() > 0 &&
161               m_TextData.GetBuffer()[m_TextData.GetLength() - 1] == '*') {
162             RestoreMode();
163           } else {
164             m_TextData.AppendChar(wch);
165           }
166           m_TextPlane.MoveNext();
167           break;
168         case CFX_CSSSyntaxMode::UnknownRule:
169           if (wch == ';')
170             SwitchMode(CFX_CSSSyntaxMode::RuleSet);
171           m_TextPlane.MoveNext();
172           break;
173         default:
174           NOTREACHED();
175           break;
176       }
177     }
178   }
179   return m_eStatus;
180 }
181 
IsImportEnabled() const182 bool CFX_CSSSyntaxParser::IsImportEnabled() const {
183   if ((m_dwCheck & CFX_CSSSYNTAXCHECK_AllowImport) == 0)
184     return false;
185   if (m_ModeStack.size() > 1)
186     return false;
187   return true;
188 }
189 
AppendChar(wchar_t wch)190 bool CFX_CSSSyntaxParser::AppendChar(wchar_t wch) {
191   m_TextPlane.MoveNext();
192   if (m_TextData.GetLength() > 0 || wch > ' ') {
193     m_TextData.AppendChar(wch);
194     return true;
195   }
196   return false;
197 }
198 
SaveTextData()199 int32_t CFX_CSSSyntaxParser::SaveTextData() {
200   m_iTextDataLen = m_TextData.TrimEnd();
201   m_TextData.Clear();
202   return m_iTextDataLen;
203 }
204 
SwitchMode(CFX_CSSSyntaxMode eMode)205 void CFX_CSSSyntaxParser::SwitchMode(CFX_CSSSyntaxMode eMode) {
206   m_eMode = eMode;
207   SaveTextData();
208 }
209 
SwitchToComment()210 int32_t CFX_CSSSyntaxParser::SwitchToComment() {
211   int32_t iLength = m_TextData.GetLength();
212   m_ModeStack.push(m_eMode);
213   SwitchMode(CFX_CSSSyntaxMode::Comment);
214   return iLength;
215 }
216 
RestoreMode()217 bool CFX_CSSSyntaxParser::RestoreMode() {
218   if (m_ModeStack.empty())
219     return false;
220 
221   SwitchMode(m_ModeStack.top());
222   m_ModeStack.pop();
223   return true;
224 }
225 
GetCurrentString() const226 WideStringView CFX_CSSSyntaxParser::GetCurrentString() const {
227   return WideStringView(m_TextData.GetBuffer(), m_iTextDataLen);
228 }
229