run:R W Run
7.56 KB
2026-03-11 16:18:52
R W Run
error_log
📄Parser.php
1<?php
2
3// SPDX-FileCopyrightText: 2004-2023 Ryan Parman, Sam Sneddon, Ryan McCue
4// SPDX-License-Identifier: BSD-3-Clause
5
6declare(strict_types=1);
7
8namespace SimplePie\XML\Declaration;
9
10/**
11 * Parses the XML Declaration
12 */
13class Parser
14{
15 /**
16 * XML Version
17 *
18 * @access public
19 * @var string
20 */
21 public $version = '1.0';
22
23 /**
24 * Encoding
25 *
26 * @access public
27 * @var string
28 */
29 public $encoding = 'UTF-8';
30
31 /**
32 * Standalone
33 *
34 * @access public
35 * @var bool
36 */
37 public $standalone = false;
38
39 private const STATE_BEFORE_VERSION_NAME = 'before_version_name';
40
41 private const STATE_VERSION_NAME = 'version_name';
42
43 private const STATE_VERSION_EQUALS = 'version_equals';
44
45 private const STATE_VERSION_VALUE = 'version_value';
46
47 private const STATE_ENCODING_NAME = 'encoding_name';
48
49 private const STATE_EMIT = 'emit';
50
51 private const STATE_ENCODING_EQUALS = 'encoding_equals';
52
53 private const STATE_STANDALONE_NAME = 'standalone_name';
54
55 private const STATE_ENCODING_VALUE = 'encoding_value';
56
57 private const STATE_STANDALONE_EQUALS = 'standalone_equals';
58
59 private const STATE_STANDALONE_VALUE = 'standalone_value';
60
61 private const STATE_ERROR = false;
62
63 /**
64 * Current state of the state machine
65 *
66 * @access private
67 * @var self::STATE_*
68 */
69 public $state = self::STATE_BEFORE_VERSION_NAME;
70
71 /**
72 * Input data
73 *
74 * @access private
75 * @var string
76 */
77 public $data = '';
78
79 /**
80 * Input data length (to avoid calling strlen() everytime this is needed)
81 *
82 * @access private
83 * @var int
84 */
85 public $data_length = 0;
86
87 /**
88 * Current position of the pointer
89 *
90 * @var int
91 * @access private
92 */
93 public $position = 0;
94
95 /**
96 * Create an instance of the class with the input data
97 *
98 * @access public
99 * @param string $data Input data
100 */
101 public function __construct(string $data)
102 {
103 $this->data = $data;
104 $this->data_length = strlen($this->data);
105 }
106
107 /**
108 * Parse the input data
109 *
110 * @access public
111 * @return bool true on success, false on failure
112 */
113 public function parse(): bool
114 {
115 while ($this->state && $this->state !== self::STATE_EMIT && $this->has_data()) {
116 $state = $this->state;
117 $this->$state();
118 }
119 $this->data = '';
120 if ($this->state === self::STATE_EMIT) {
121 return true;
122 }
123
124 // Reset the parser state.
125 $this->version = '1.0';
126 $this->encoding = 'UTF-8';
127 $this->standalone = false;
128 return false;
129 }
130
131 /**
132 * Check whether there is data beyond the pointer
133 *
134 * @access private
135 * @return bool true if there is further data, false if not
136 */
137 public function has_data(): bool
138 {
139 return (bool) ($this->position < $this->data_length);
140 }
141
142 /**
143 * Advance past any whitespace
144 *
145 * @return int Number of whitespace characters passed
146 */
147 public function skip_whitespace()
148 {
149 $whitespace = strspn($this->data, "\x09\x0A\x0D\x20", $this->position);
150 $this->position += $whitespace;
151 return $whitespace;
152 }
153
154 /**
155 * Read value
156 *
157 * @return string|false
158 */
159 public function get_value()
160 {
161 $quote = substr($this->data, $this->position, 1);
162 if ($quote === '"' || $quote === "'") {
163 $this->position++;
164 $len = strcspn($this->data, $quote, $this->position);
165 if ($this->has_data()) {
166 $value = substr($this->data, $this->position, $len);
167 $this->position += $len + 1;
168 return $value;
169 }
170 }
171 return false;
172 }
173
174 public function before_version_name(): void
175 {
176 if ($this->skip_whitespace()) {
177 $this->state = self::STATE_VERSION_NAME;
178 } else {
179 $this->state = self::STATE_ERROR;
180 }
181 }
182
183 public function version_name(): void
184 {
185 if (substr($this->data, $this->position, 7) === 'version') {
186 $this->position += 7;
187 $this->skip_whitespace();
188 $this->state = self::STATE_VERSION_EQUALS;
189 } else {
190 $this->state = self::STATE_ERROR;
191 }
192 }
193
194 public function version_equals(): void
195 {
196 if (substr($this->data, $this->position, 1) === '=') {
197 $this->position++;
198 $this->skip_whitespace();
199 $this->state = self::STATE_VERSION_VALUE;
200 } else {
201 $this->state = self::STATE_ERROR;
202 }
203 }
204
205 public function version_value(): void
206 {
207 if ($version = $this->get_value()) {
208 $this->version = $version;
209 $this->skip_whitespace();
210 if ($this->has_data()) {
211 $this->state = self::STATE_ENCODING_NAME;
212 } else {
213 $this->state = self::STATE_EMIT;
214 }
215 } else {
216 $this->state = self::STATE_ERROR;
217 }
218 }
219
220 public function encoding_name(): void
221 {
222 if (substr($this->data, $this->position, 8) === 'encoding') {
223 $this->position += 8;
224 $this->skip_whitespace();
225 $this->state = self::STATE_ENCODING_EQUALS;
226 } else {
227 $this->state = self::STATE_STANDALONE_NAME;
228 }
229 }
230
231 public function encoding_equals(): void
232 {
233 if (substr($this->data, $this->position, 1) === '=') {
234 $this->position++;
235 $this->skip_whitespace();
236 $this->state = self::STATE_ENCODING_VALUE;
237 } else {
238 $this->state = self::STATE_ERROR;
239 }
240 }
241
242 public function encoding_value(): void
243 {
244 if ($encoding = $this->get_value()) {
245 $this->encoding = $encoding;
246 $this->skip_whitespace();
247 if ($this->has_data()) {
248 $this->state = self::STATE_STANDALONE_NAME;
249 } else {
250 $this->state = self::STATE_EMIT;
251 }
252 } else {
253 $this->state = self::STATE_ERROR;
254 }
255 }
256
257 public function standalone_name(): void
258 {
259 if (substr($this->data, $this->position, 10) === 'standalone') {
260 $this->position += 10;
261 $this->skip_whitespace();
262 $this->state = self::STATE_STANDALONE_EQUALS;
263 } else {
264 $this->state = self::STATE_ERROR;
265 }
266 }
267
268 public function standalone_equals(): void
269 {
270 if (substr($this->data, $this->position, 1) === '=') {
271 $this->position++;
272 $this->skip_whitespace();
273 $this->state = self::STATE_STANDALONE_VALUE;
274 } else {
275 $this->state = self::STATE_ERROR;
276 }
277 }
278
279 public function standalone_value(): void
280 {
281 if ($standalone = $this->get_value()) {
282 switch ($standalone) {
283 case 'yes':
284 $this->standalone = true;
285 break;
286
287 case 'no':
288 $this->standalone = false;
289 break;
290
291 default:
292 $this->state = self::STATE_ERROR;
293 return;
294 }
295
296 $this->skip_whitespace();
297 if ($this->has_data()) {
298 $this->state = self::STATE_ERROR;
299 } else {
300 $this->state = self::STATE_EMIT;
301 }
302 } else {
303 $this->state = self::STATE_ERROR;
304 }
305 }
306}
307
308class_alias('SimplePie\XML\Declaration\Parser', 'SimplePie_XML_Declaration_Parser');
309