• 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 "xfa/fde/css/cfde_csssyntaxparser.h"
8 
9 #include <algorithm>
10 
11 #include "xfa/fde/css/cfde_cssdeclaration.h"
12 #include "xfa/fde/css/fde_cssdatatable.h"
13 #include "xfa/fgas/crt/fgas_codepage.h"
14 
15 namespace {
16 
IsSelectorStart(FX_WCHAR wch)17 bool IsSelectorStart(FX_WCHAR wch) {
18   return wch == '.' || wch == '#' || wch == '*' || (wch >= 'a' && wch <= 'z') ||
19          (wch >= 'A' && wch <= 'Z');
20 }
21 
22 }  // namespace
23 
CFDE_CSSSyntaxParser()24 CFDE_CSSSyntaxParser::CFDE_CSSSyntaxParser()
25     : m_iTextDataLen(0),
26       m_dwCheck((uint32_t)-1),
27       m_eMode(FDE_CSSSyntaxMode::RuleSet),
28       m_eStatus(FDE_CSSSyntaxStatus::None) {}
29 
~CFDE_CSSSyntaxParser()30 CFDE_CSSSyntaxParser::~CFDE_CSSSyntaxParser() {
31   m_TextData.Reset();
32   m_TextPlane.Reset();
33 }
34 
Init(const FX_WCHAR * pBuffer,int32_t iBufferSize,int32_t iTextDatSize,bool bOnlyDeclaration)35 bool CFDE_CSSSyntaxParser::Init(const FX_WCHAR* pBuffer,
36                                 int32_t iBufferSize,
37                                 int32_t iTextDatSize,
38                                 bool bOnlyDeclaration) {
39   ASSERT(pBuffer && iBufferSize > 0 && iTextDatSize > 0);
40   Reset(bOnlyDeclaration);
41   if (!m_TextData.EstimateSize(iTextDatSize))
42     return false;
43   return m_TextPlane.AttachBuffer(pBuffer, iBufferSize);
44 }
45 
Reset(bool bOnlyDeclaration)46 void CFDE_CSSSyntaxParser::Reset(bool bOnlyDeclaration) {
47   m_TextPlane.Reset();
48   m_TextData.Reset();
49   m_iTextDataLen = 0;
50   m_dwCheck = (uint32_t)-1;
51   m_eStatus = FDE_CSSSyntaxStatus::None;
52   m_eMode = bOnlyDeclaration ? FDE_CSSSyntaxMode::PropertyName
53                              : FDE_CSSSyntaxMode::RuleSet;
54 }
55 
DoSyntaxParse()56 FDE_CSSSyntaxStatus CFDE_CSSSyntaxParser::DoSyntaxParse() {
57   while (m_eStatus >= FDE_CSSSyntaxStatus::None) {
58     if (m_TextPlane.IsEOF()) {
59       if (m_eMode == FDE_CSSSyntaxMode::PropertyValue &&
60           m_TextData.GetLength() > 0) {
61         SaveTextData();
62         m_eStatus = FDE_CSSSyntaxStatus::PropertyValue;
63         return m_eStatus;
64       }
65       m_eStatus = FDE_CSSSyntaxStatus::EOS;
66       return m_eStatus;
67     }
68     FX_WCHAR wch;
69     while (!m_TextPlane.IsEOF()) {
70       wch = m_TextPlane.GetChar();
71       switch (m_eMode) {
72         case FDE_CSSSyntaxMode::RuleSet:
73           switch (wch) {
74             case '}':
75               m_TextPlane.MoveNext();
76               if (RestoreMode())
77                 return FDE_CSSSyntaxStatus::DeclClose;
78 
79               m_eStatus = FDE_CSSSyntaxStatus::Error;
80               return m_eStatus;
81             case '/':
82               if (m_TextPlane.GetNextChar() == '*') {
83                 m_ModeStack.push(m_eMode);
84                 SwitchMode(FDE_CSSSyntaxMode::Comment);
85                 break;
86               }
87             default:
88               if (wch <= ' ') {
89                 m_TextPlane.MoveNext();
90               } else if (IsSelectorStart(wch)) {
91                 SwitchMode(FDE_CSSSyntaxMode::Selector);
92                 return FDE_CSSSyntaxStatus::StyleRule;
93               } else {
94                 m_eStatus = FDE_CSSSyntaxStatus::Error;
95                 return m_eStatus;
96               }
97               break;
98           }
99           break;
100         case FDE_CSSSyntaxMode::Selector:
101           switch (wch) {
102             case ',':
103               m_TextPlane.MoveNext();
104               SwitchMode(FDE_CSSSyntaxMode::Selector);
105               if (m_iTextDataLen > 0)
106                 return FDE_CSSSyntaxStatus::Selector;
107               break;
108             case '{':
109               if (m_TextData.GetLength() > 0) {
110                 SaveTextData();
111                 return FDE_CSSSyntaxStatus::Selector;
112               }
113               m_TextPlane.MoveNext();
114               m_ModeStack.push(FDE_CSSSyntaxMode::RuleSet);
115               SwitchMode(FDE_CSSSyntaxMode::PropertyName);
116               return FDE_CSSSyntaxStatus::DeclOpen;
117             case '/':
118               if (m_TextPlane.GetNextChar() == '*') {
119                 if (SwitchToComment() > 0)
120                   return FDE_CSSSyntaxStatus::Selector;
121                 break;
122               }
123             default:
124               AppendChar(wch);
125               break;
126           }
127           break;
128         case FDE_CSSSyntaxMode::PropertyName:
129           switch (wch) {
130             case ':':
131               m_TextPlane.MoveNext();
132               SwitchMode(FDE_CSSSyntaxMode::PropertyValue);
133               return FDE_CSSSyntaxStatus::PropertyName;
134             case '}':
135               m_TextPlane.MoveNext();
136               if (RestoreMode())
137                 return FDE_CSSSyntaxStatus::DeclClose;
138 
139               m_eStatus = FDE_CSSSyntaxStatus::Error;
140               return m_eStatus;
141             case '/':
142               if (m_TextPlane.GetNextChar() == '*') {
143                 if (SwitchToComment() > 0)
144                   return FDE_CSSSyntaxStatus::PropertyName;
145                 break;
146               }
147             default:
148               AppendChar(wch);
149               break;
150           }
151           break;
152         case FDE_CSSSyntaxMode::PropertyValue:
153           switch (wch) {
154             case ';':
155               m_TextPlane.MoveNext();
156             case '}':
157               SwitchMode(FDE_CSSSyntaxMode::PropertyName);
158               return FDE_CSSSyntaxStatus::PropertyValue;
159             case '/':
160               if (m_TextPlane.GetNextChar() == '*') {
161                 if (SwitchToComment() > 0)
162                   return FDE_CSSSyntaxStatus::PropertyValue;
163                 break;
164               }
165             default:
166               AppendChar(wch);
167               break;
168           }
169           break;
170         case FDE_CSSSyntaxMode::Comment:
171           if (wch == '/' && m_TextData.GetLength() > 0 &&
172               m_TextData.GetAt(m_TextData.GetLength() - 1) == '*') {
173             RestoreMode();
174           } else {
175             m_TextData.AppendChar(wch);
176           }
177           m_TextPlane.MoveNext();
178           break;
179         case FDE_CSSSyntaxMode::UnknownRule:
180           if (wch == ';')
181             SwitchMode(FDE_CSSSyntaxMode::RuleSet);
182           m_TextPlane.MoveNext();
183           break;
184         default:
185           ASSERT(false);
186           break;
187       }
188     }
189   }
190   return m_eStatus;
191 }
192 
IsImportEnabled() const193 bool CFDE_CSSSyntaxParser::IsImportEnabled() const {
194   if ((m_dwCheck & FDE_CSSSYNTAXCHECK_AllowImport) == 0)
195     return false;
196   if (m_ModeStack.size() > 1)
197     return false;
198   return true;
199 }
200 
AppendChar(FX_WCHAR wch)201 bool CFDE_CSSSyntaxParser::AppendChar(FX_WCHAR wch) {
202   m_TextPlane.MoveNext();
203   if (m_TextData.GetLength() > 0 || wch > ' ') {
204     m_TextData.AppendChar(wch);
205     return true;
206   }
207   return false;
208 }
209 
SaveTextData()210 int32_t CFDE_CSSSyntaxParser::SaveTextData() {
211   m_iTextDataLen = m_TextData.TrimEnd();
212   m_TextData.Clear();
213   return m_iTextDataLen;
214 }
215 
SwitchMode(FDE_CSSSyntaxMode eMode)216 void CFDE_CSSSyntaxParser::SwitchMode(FDE_CSSSyntaxMode eMode) {
217   m_eMode = eMode;
218   SaveTextData();
219 }
220 
SwitchToComment()221 int32_t CFDE_CSSSyntaxParser::SwitchToComment() {
222   int32_t iLength = m_TextData.GetLength();
223   m_ModeStack.push(m_eMode);
224   SwitchMode(FDE_CSSSyntaxMode::Comment);
225   return iLength;
226 }
227 
RestoreMode()228 bool CFDE_CSSSyntaxParser::RestoreMode() {
229   if (m_ModeStack.empty())
230     return false;
231 
232   SwitchMode(m_ModeStack.top());
233   m_ModeStack.pop();
234   return true;
235 }
236 
GetCurrentString() const237 CFX_WideStringC CFDE_CSSSyntaxParser::GetCurrentString() const {
238   return CFX_WideStringC(m_TextData.GetBuffer(), m_iTextDataLen);
239 }
240