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
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: