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