blob: 9341798d81aeb19bdf03a30c086d900c08f067da [file] [log] [blame]
kumarashishg826308d2023-06-23 13:21:22 +00001// Copyright 2014 The PDFium Authors
Philip P. Moltmannd904c1e2018-03-19 09:26:45 -07002// 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
Haibo Huang49cc9302020-04-27 16:14:24 -07009#include "core/fxcrt/css/cfx_cssdata.h"
Philip P. Moltmannd904c1e2018-03-19 09:26:45 -070010#include "core/fxcrt/css/cfx_cssdeclaration.h"
11#include "core/fxcrt/fx_codepage.h"
12#include "core/fxcrt/fx_extension.h"
kumarashishg826308d2023-06-23 13:21:22 +000013#include "third_party/base/notreached.h"
Philip P. Moltmannd904c1e2018-03-19 09:26:45 -070014
15namespace {
16
17bool IsSelectorStart(wchar_t wch) {
Haibo Huang49cc9302020-04-27 16:14:24 -070018 return wch == '.' || wch == '#' || wch == '*' ||
19 (isascii(wch) && isalpha(wch));
Philip P. Moltmannd904c1e2018-03-19 09:26:45 -070020}
21
22} // namespace
23
kumarashishg826308d2023-06-23 13:21:22 +000024CFX_CSSSyntaxParser::CFX_CSSSyntaxParser(WideStringView str) : m_Input(str) {}
Philip P. Moltmannd904c1e2018-03-19 09:26:45 -070025
kumarashishg826308d2023-06-23 13:21:22 +000026CFX_CSSSyntaxParser::~CFX_CSSSyntaxParser() = default;
Haibo Huang49cc9302020-04-27 16:14:24 -070027
kumarashishg826308d2023-06-23 13:21:22 +000028void CFX_CSSSyntaxParser::SetParseOnlyDeclarations() {
29 m_eMode = Mode::kPropertyName;
Philip P. Moltmannd904c1e2018-03-19 09:26:45 -070030}
31
kumarashishg826308d2023-06-23 13:21:22 +000032CFX_CSSSyntaxParser::Status CFX_CSSSyntaxParser::DoSyntaxParse() {
33 m_Output.Clear();
34 if (m_bHasError)
35 return Status::kError;
Philip P. Moltmannd904c1e2018-03-19 09:26:45 -070036
kumarashishg826308d2023-06-23 13:21:22 +000037 while (!m_Input.IsEOF()) {
38 wchar_t wch = m_Input.GetChar();
39 switch (m_eMode) {
40 case Mode::kRuleSet:
41 switch (wch) {
42 case '}':
43 m_bHasError = true;
44 return Status::kError;
45 case '/':
46 if (m_Input.GetNextChar() == '*') {
47 SaveMode(Mode::kRuleSet);
48 m_eMode = Mode::kComment;
49 break;
50 }
51 [[fallthrough]];
52 default:
53 if (wch <= ' ') {
54 m_Input.MoveNext();
55 } else if (IsSelectorStart(wch)) {
56 m_eMode = Mode::kSelector;
57 return Status::kStyleRule;
58 } else {
59 m_bHasError = true;
60 return Status::kError;
61 }
62 break;
63 }
64 break;
65 case Mode::kSelector:
66 switch (wch) {
67 case ',':
68 m_Input.MoveNext();
69 if (!m_Output.IsEmpty())
70 return Status::kSelector;
71 break;
72 case '{':
73 if (!m_Output.IsEmpty())
74 return Status::kSelector;
75 m_Input.MoveNext();
76 SaveMode(Mode::kRuleSet); // Back to validate ruleset again.
77 m_eMode = Mode::kPropertyName;
78 return Status::kDeclOpen;
79 case '/':
80 if (m_Input.GetNextChar() == '*') {
81 SaveMode(Mode::kSelector);
82 m_eMode = Mode::kComment;
83 if (!m_Output.IsEmpty())
84 return Status::kSelector;
85 break;
86 }
87 [[fallthrough]];
88 default:
89 m_Output.AppendCharIfNotLeadingBlank(wch);
90 m_Input.MoveNext();
91 break;
92 }
93 break;
94 case Mode::kPropertyName:
95 switch (wch) {
96 case ':':
97 m_Input.MoveNext();
98 m_eMode = Mode::kPropertyValue;
99 return Status::kPropertyName;
100 case '}':
101 m_Input.MoveNext();
102 if (!RestoreMode())
103 return Status::kError;
Philip P. Moltmannd904c1e2018-03-19 09:26:45 -0700104
kumarashishg826308d2023-06-23 13:21:22 +0000105 return Status::kDeclClose;
106 case '/':
107 if (m_Input.GetNextChar() == '*') {
108 SaveMode(Mode::kPropertyName);
109 m_eMode = Mode::kComment;
110 if (!m_Output.IsEmpty())
111 return Status::kPropertyName;
Philip P. Moltmannd904c1e2018-03-19 09:26:45 -0700112 break;
kumarashishg826308d2023-06-23 13:21:22 +0000113 }
114 [[fallthrough]];
115 default:
116 m_Output.AppendCharIfNotLeadingBlank(wch);
117 m_Input.MoveNext();
118 break;
119 }
120 break;
121 case Mode::kPropertyValue:
122 switch (wch) {
123 case ';':
124 m_Input.MoveNext();
125 [[fallthrough]];
126 case '}':
127 m_eMode = Mode::kPropertyName;
128 return Status::kPropertyValue;
129 case '/':
130 if (m_Input.GetNextChar() == '*') {
131 SaveMode(Mode::kPropertyValue);
132 m_eMode = Mode::kComment;
133 if (!m_Output.IsEmpty())
134 return Status::kPropertyValue;
Philip P. Moltmannd904c1e2018-03-19 09:26:45 -0700135 break;
kumarashishg826308d2023-06-23 13:21:22 +0000136 }
137 [[fallthrough]];
138 default:
139 m_Output.AppendCharIfNotLeadingBlank(wch);
140 m_Input.MoveNext();
141 break;
142 }
143 break;
144 case Mode::kComment:
145 if (wch == '*' && m_Input.GetNextChar() == '/') {
146 if (!RestoreMode())
147 return Status::kError;
148 m_Input.MoveNext();
149 }
150 m_Input.MoveNext();
151 break;
152 default:
153 NOTREACHED();
154 break;
Philip P. Moltmannd904c1e2018-03-19 09:26:45 -0700155 }
156 }
kumarashishg826308d2023-06-23 13:21:22 +0000157 if (m_eMode == Mode::kPropertyValue && !m_Output.IsEmpty())
158 return Status::kPropertyValue;
159
160 return Status::kEOS;
Philip P. Moltmannd904c1e2018-03-19 09:26:45 -0700161}
162
kumarashishg826308d2023-06-23 13:21:22 +0000163void CFX_CSSSyntaxParser::SaveMode(Mode mode) {
164 m_ModeStack.push(mode);
Philip P. Moltmannd904c1e2018-03-19 09:26:45 -0700165}
166
167bool CFX_CSSSyntaxParser::RestoreMode() {
kumarashishg826308d2023-06-23 13:21:22 +0000168 if (m_ModeStack.empty()) {
169 m_bHasError = true;
Philip P. Moltmannd904c1e2018-03-19 09:26:45 -0700170 return false;
kumarashishg826308d2023-06-23 13:21:22 +0000171 }
172 m_eMode = m_ModeStack.top();
Philip P. Moltmannd904c1e2018-03-19 09:26:45 -0700173 m_ModeStack.pop();
174 return true;
175}
176
177WideStringView CFX_CSSSyntaxParser::GetCurrentString() const {
kumarashishg826308d2023-06-23 13:21:22 +0000178 return m_Output.GetTrailingBlankTrimmedString();
Philip P. Moltmannd904c1e2018-03-19 09:26:45 -0700179}