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-dev
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: */
51: class SimplePie_XML_Declaration_Parser
52: {
53: /**
54: * XML Version
55: *
56: * @access public
57: * @var string
58: */
59: var $version = '1.0';
60:
61: /**
62: * Encoding
63: *
64: * @access public
65: * @var string
66: */
67: var $encoding = 'UTF-8';
68:
69: /**
70: * Standalone
71: *
72: * @access public
73: * @var bool
74: */
75: var $standalone = false;
76:
77: /**
78: * Current state of the state machine
79: *
80: * @access private
81: * @var string
82: */
83: var $state = 'before_version_name';
84:
85: /**
86: * Input data
87: *
88: * @access private
89: * @var string
90: */
91: var $data = '';
92:
93: /**
94: * Input data length (to avoid calling strlen() everytime this is needed)
95: *
96: * @access private
97: * @var int
98: */
99: var $data_length = 0;
100:
101: /**
102: * Current position of the pointer
103: *
104: * @var int
105: * @access private
106: */
107: var $position = 0;
108:
109: /**
110: * Create an instance of the class with the input data
111: *
112: * @access public
113: * @param string $data Input data
114: */
115: public function __construct($data)
116: {
117: $this->data = $data;
118: $this->data_length = strlen($this->data);
119: }
120:
121: /**
122: * Parse the input data
123: *
124: * @access public
125: * @return bool true on success, false on failure
126: */
127: public function parse()
128: {
129: while ($this->state && $this->state !== 'emit' && $this->has_data())
130: {
131: $state = $this->state;
132: $this->$state();
133: }
134: $this->data = '';
135: if ($this->state === 'emit')
136: {
137: return true;
138: }
139: else
140: {
141: $this->version = '';
142: $this->encoding = '';
143: $this->standalone = '';
144: return false;
145: }
146: }
147:
148: /**
149: * Check whether there is data beyond the pointer
150: *
151: * @access private
152: * @return bool true if there is further data, false if not
153: */
154: public function has_data()
155: {
156: return (bool) ($this->position < $this->data_length);
157: }
158:
159: /**
160: * Advance past any whitespace
161: *
162: * @return int Number of whitespace characters passed
163: */
164: public function skip_whitespace()
165: {
166: $whitespace = strspn($this->data, "\x09\x0A\x0D\x20", $this->position);
167: $this->position += $whitespace;
168: return $whitespace;
169: }
170:
171: /**
172: * Read value
173: */
174: public function get_value()
175: {
176: $quote = substr($this->data, $this->position, 1);
177: if ($quote === '"' || $quote === "'")
178: {
179: $this->position++;
180: $len = strcspn($this->data, $quote, $this->position);
181: if ($this->has_data())
182: {
183: $value = substr($this->data, $this->position, $len);
184: $this->position += $len + 1;
185: return $value;
186: }
187: }
188: return false;
189: }
190:
191: public function before_version_name()
192: {
193: if ($this->skip_whitespace())
194: {
195: $this->state = 'version_name';
196: }
197: else
198: {
199: $this->state = false;
200: }
201: }
202:
203: public function version_name()
204: {
205: if (substr($this->data, $this->position, 7) === 'version')
206: {
207: $this->position += 7;
208: $this->skip_whitespace();
209: $this->state = 'version_equals';
210: }
211: else
212: {
213: $this->state = false;
214: }
215: }
216:
217: public function version_equals()
218: {
219: if (substr($this->data, $this->position, 1) === '=')
220: {
221: $this->position++;
222: $this->skip_whitespace();
223: $this->state = 'version_value';
224: }
225: else
226: {
227: $this->state = false;
228: }
229: }
230:
231: public function version_value()
232: {
233: if ($this->version = $this->get_value())
234: {
235: $this->skip_whitespace();
236: if ($this->has_data())
237: {
238: $this->state = 'encoding_name';
239: }
240: else
241: {
242: $this->state = 'emit';
243: }
244: }
245: else
246: {
247: $this->state = false;
248: }
249: }
250:
251: public function encoding_name()
252: {
253: if (substr($this->data, $this->position, 8) === 'encoding')
254: {
255: $this->position += 8;
256: $this->skip_whitespace();
257: $this->state = 'encoding_equals';
258: }
259: else
260: {
261: $this->state = 'standalone_name';
262: }
263: }
264:
265: public function encoding_equals()
266: {
267: if (substr($this->data, $this->position, 1) === '=')
268: {
269: $this->position++;
270: $this->skip_whitespace();
271: $this->state = 'encoding_value';
272: }
273: else
274: {
275: $this->state = false;
276: }
277: }
278:
279: public function encoding_value()
280: {
281: if ($this->encoding = $this->get_value())
282: {
283: $this->skip_whitespace();
284: if ($this->has_data())
285: {
286: $this->state = 'standalone_name';
287: }
288: else
289: {
290: $this->state = 'emit';
291: }
292: }
293: else
294: {
295: $this->state = false;
296: }
297: }
298:
299: public function standalone_name()
300: {
301: if (substr($this->data, $this->position, 10) === 'standalone')
302: {
303: $this->position += 10;
304: $this->skip_whitespace();
305: $this->state = 'standalone_equals';
306: }
307: else
308: {
309: $this->state = false;
310: }
311: }
312:
313: public function standalone_equals()
314: {
315: if (substr($this->data, $this->position, 1) === '=')
316: {
317: $this->position++;
318: $this->skip_whitespace();
319: $this->state = 'standalone_value';
320: }
321: else
322: {
323: $this->state = false;
324: }
325: }
326:
327: public function standalone_value()
328: {
329: if ($standalone = $this->get_value())
330: {
331: switch ($standalone)
332: {
333: case 'yes':
334: $this->standalone = true;
335: break;
336:
337: case 'no':
338: $this->standalone = false;
339: break;
340:
341: default:
342: $this->state = false;
343: return;
344: }
345:
346: $this->skip_whitespace();
347: if ($this->has_data())
348: {
349: $this->state = false;
350: }
351: else
352: {
353: $this->state = 'emit';
354: }
355: }
356: else
357: {
358: $this->state = false;
359: }
360: }
361: }
362: