1<?php 2 3declare(strict_types=1); 4/** 5 * SimplePie 6 * 7 * A PHP-Based RSS and Atom Feed Framework. 8 * Takes the hard work out of managing a complete RSS/Atom solution. 9 * 10 * Copyright (c) 2004-2022, Ryan Parman, Sam Sneddon, Ryan McCue, and contributors 11 * All rights reserved. 12 * 13 * Redistribution and use in source and binary forms, with or without modification, are 14 * permitted provided that the following conditions are met: 15 * 16 * * Redistributions of source code must retain the above copyright notice, this list of 17 * conditions and the following disclaimer. 18 * 19 * * Redistributions in binary form must reproduce the above copyright notice, this list 20 * of conditions and the following disclaimer in the documentation and/or other materials 21 * provided with the distribution. 22 * 23 * * Neither the name of the SimplePie Team nor the names of its contributors may be used 24 * to endorse or promote products derived from this software without specific prior 25 * written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS 28 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 29 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS 30 * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 32 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 34 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 * POSSIBILITY OF SUCH DAMAGE. 36 * 37 * @package SimplePie 38 * @copyright 2004-2016 Ryan Parman, Sam Sneddon, Ryan McCue 39 * @author Ryan Parman 40 * @author Sam Sneddon 41 * @author Ryan McCue 42 * @link http://simplepie.org/ SimplePie 43 * @license http://www.opensource.org/licenses/bsd-license.php BSD License 44 */ 45 46namespace SimplePie\XML\Declaration; 47 48/** 49 * Parses the XML Declaration 50 * 51 * @package SimplePie 52 * @subpackage Parsing 53 */ 54class Parser 55{ 56 /** 57 * XML Version 58 * 59 * @access public 60 * @var string 61 */ 62 public $version = '1.0'; 63 64 /** 65 * Encoding 66 * 67 * @access public 68 * @var string 69 */ 70 public $encoding = 'UTF-8'; 71 72 /** 73 * Standalone 74 * 75 * @access public 76 * @var bool 77 */ 78 public $standalone = false; 79 80 private const STATE_BEFORE_VERSION_NAME = 'before_version_name'; 81 82 private const STATE_VERSION_NAME = 'version_name'; 83 84 private const STATE_VERSION_EQUALS = 'version_equals'; 85 86 private const STATE_VERSION_VALUE = 'version_value'; 87 88 private const STATE_ENCODING_NAME = 'encoding_name'; 89 90 private const STATE_EMIT = 'emit'; 91 92 private const STATE_ENCODING_EQUALS = 'encoding_equals'; 93 94 private const STATE_STANDALONE_NAME = 'standalone_name'; 95 96 private const STATE_ENCODING_VALUE = 'encoding_value'; 97 98 private const STATE_STANDALONE_EQUALS = 'standalone_equals'; 99 100 private const STATE_STANDALONE_VALUE = 'standalone_value'; 101 102 private const STATE_ERROR = false; 103 104 /** 105 * Current state of the state machine 106 * 107 * @access private 108 * @var self::STATE_* 109 */ 110 public $state = self::STATE_BEFORE_VERSION_NAME; 111 112 /** 113 * Input data 114 * 115 * @access private 116 * @var string 117 */ 118 public $data = ''; 119 120 /** 121 * Input data length (to avoid calling strlen() everytime this is needed) 122 * 123 * @access private 124 * @var int 125 */ 126 public $data_length = 0; 127 128 /** 129 * Current position of the pointer 130 * 131 * @var int 132 * @access private 133 */ 134 public $position = 0; 135 136 /** 137 * Create an instance of the class with the input data 138 * 139 * @access public 140 * @param string $data Input data 141 */ 142 public function __construct($data) 143 { 144 $this->data = $data; 145 $this->data_length = strlen($this->data); 146 } 147 148 /** 149 * Parse the input data 150 * 151 * @access public 152 * @return bool true on success, false on failure 153 */ 154 public function parse() 155 { 156 while ($this->state && $this->state !== self::STATE_EMIT && $this->has_data()) { 157 $state = $this->state; 158 $this->$state(); 159 } 160 $this->data = ''; 161 if ($this->state === self::STATE_EMIT) { 162 return true; 163 } 164 165 $this->version = ''; 166 $this->encoding = ''; 167 $this->standalone = ''; 168 return false; 169 } 170 171 /** 172 * Check whether there is data beyond the pointer 173 * 174 * @access private 175 * @return bool true if there is further data, false if not 176 */ 177 public function has_data() 178 { 179 return (bool) ($this->position < $this->data_length); 180 } 181 182 /** 183 * Advance past any whitespace 184 * 185 * @return int Number of whitespace characters passed 186 */ 187 public function skip_whitespace() 188 { 189 $whitespace = strspn($this->data, "\x09\x0A\x0D\x20", $this->position); 190 $this->position += $whitespace; 191 return $whitespace; 192 } 193 194 /** 195 * Read value 196 */ 197 public function get_value() 198 { 199 $quote = substr($this->data, $this->position, 1); 200 if ($quote === '"' || $quote === "'") { 201 $this->position++; 202 $len = strcspn($this->data, $quote, $this->position); 203 if ($this->has_data()) { 204 $value = substr($this->data, $this->position, $len); 205 $this->position += $len + 1; 206 return $value; 207 } 208 } 209 return false; 210 } 211 212 public function before_version_name() 213 { 214 if ($this->skip_whitespace()) { 215 $this->state = self::STATE_VERSION_NAME; 216 } else { 217 $this->state = self::STATE_ERROR; 218 } 219 } 220 221 public function version_name() 222 { 223 if (substr($this->data, $this->position, 7) === 'version') { 224 $this->position += 7; 225 $this->skip_whitespace(); 226 $this->state = self::STATE_VERSION_EQUALS; 227 } else { 228 $this->state = self::STATE_ERROR; 229 } 230 } 231 232 public function version_equals() 233 { 234 if (substr($this->data, $this->position, 1) === '=') { 235 $this->position++; 236 $this->skip_whitespace(); 237 $this->state = self::STATE_VERSION_VALUE; 238 } else { 239 $this->state = self::STATE_ERROR; 240 } 241 } 242 243 public function version_value() 244 { 245 if ($this->version = $this->get_value()) { 246 $this->skip_whitespace(); 247 if ($this->has_data()) { 248 $this->state = self::STATE_ENCODING_NAME; 249 } else { 250 $this->state = self::STATE_EMIT; 251 } 252 } else { 253 $this->state = self::STATE_ERROR; 254 } 255 } 256 257 public function encoding_name() 258 { 259 if (substr($this->data, $this->position, 8) === 'encoding') { 260 $this->position += 8; 261 $this->skip_whitespace(); 262 $this->state = self::STATE_ENCODING_EQUALS; 263 } else { 264 $this->state = self::STATE_STANDALONE_NAME; 265 } 266 } 267 268 public function encoding_equals() 269 { 270 if (substr($this->data, $this->position, 1) === '=') { 271 $this->position++; 272 $this->skip_whitespace(); 273 $this->state = self::STATE_ENCODING_VALUE; 274 } else { 275 $this->state = self::STATE_ERROR; 276 } 277 } 278 279 public function encoding_value() 280 { 281 if ($this->encoding = $this->get_value()) { 282 $this->skip_whitespace(); 283 if ($this->has_data()) { 284 $this->state = self::STATE_STANDALONE_NAME; 285 } else { 286 $this->state = self::STATE_EMIT; 287 } 288 } else { 289 $this->state = self::STATE_ERROR; 290 } 291 } 292 293 public function standalone_name() 294 { 295 if (substr($this->data, $this->position, 10) === 'standalone') { 296 $this->position += 10; 297 $this->skip_whitespace(); 298 $this->state = self::STATE_STANDALONE_EQUALS; 299 } else { 300 $this->state = self::STATE_ERROR; 301 } 302 } 303 304 public function standalone_equals() 305 { 306 if (substr($this->data, $this->position, 1) === '=') { 307 $this->position++; 308 $this->skip_whitespace(); 309 $this->state = self::STATE_STANDALONE_VALUE; 310 } else { 311 $this->state = self::STATE_ERROR; 312 } 313 } 314 315 public function standalone_value() 316 { 317 if ($standalone = $this->get_value()) { 318 switch ($standalone) { 319 case 'yes': 320 $this->standalone = true; 321 break; 322 323 case 'no': 324 $this->standalone = false; 325 break; 326 327 default: 328 $this->state = self::STATE_ERROR; 329 return; 330 } 331 332 $this->skip_whitespace(); 333 if ($this->has_data()) { 334 $this->state = self::STATE_ERROR; 335 } else { 336 $this->state = self::STATE_EMIT; 337 } 338 } else { 339 $this->state = self::STATE_ERROR; 340 } 341 } 342} 343 344class_alias('SimplePie\XML\Declaration\Parser', 'SimplePie_XML_Declaration_Parser'); 345