PageRenderTime 73ms CodeModel.GetById 41ms app.highlight 25ms RepoModel.GetById 2ms app.codeStats 0ms

/public/wp-includes/js/tinymce/plugins/spellchecker/classes/utils/JSON.php

https://bitbucket.org/symphonicpixels/wordpress-boilerplate
PHP | 595 lines | 520 code | 63 blank | 12 comment | 32 complexity | 0a1ce8027621826c5c2f8c086c4ae76a MD5 | raw file
  1<?php
  2/**
  3 * $Id: JSON.php 40 2007-06-18 11:43:15Z spocke $
  4 *
  5 * @package MCManager.utils
  6 * @author Moxiecode
  7 * @copyright Copyright � 2007, Moxiecode Systems AB, All rights reserved.
  8 */
  9
 10define('JSON_BOOL', 1);
 11define('JSON_INT', 2);
 12define('JSON_STR', 3);
 13define('JSON_FLOAT', 4);
 14define('JSON_NULL', 5);
 15define('JSON_START_OBJ', 6);
 16define('JSON_END_OBJ', 7);
 17define('JSON_START_ARRAY', 8);
 18define('JSON_END_ARRAY', 9);
 19define('JSON_KEY', 10);
 20define('JSON_SKIP', 11);
 21
 22define('JSON_IN_ARRAY', 30);
 23define('JSON_IN_OBJECT', 40);
 24define('JSON_IN_BETWEEN', 50);
 25
 26class Moxiecode_JSONReader {
 27	var $_data, $_len, $_pos;
 28	var $_value, $_token;
 29	var $_location, $_lastLocations;
 30	var $_needProp;
 31
 32	function Moxiecode_JSONReader($data) {
 33		$this->_data = $data;
 34		$this->_len = strlen($data);
 35		$this->_pos = -1;
 36		$this->_location = JSON_IN_BETWEEN;
 37		$this->_lastLocations = array();
 38		$this->_needProp = false;
 39	}
 40
 41	function getToken() {
 42		return $this->_token;
 43	}
 44
 45	function getLocation() {
 46		return $this->_location;
 47	}
 48
 49	function getTokenName() {
 50		switch ($this->_token) {
 51			case JSON_BOOL:
 52				return 'JSON_BOOL';
 53
 54			case JSON_INT:
 55				return 'JSON_INT';
 56
 57			case JSON_STR:
 58				return 'JSON_STR';
 59
 60			case JSON_FLOAT:
 61				return 'JSON_FLOAT';
 62
 63			case JSON_NULL:
 64				return 'JSON_NULL';
 65
 66			case JSON_START_OBJ:
 67				return 'JSON_START_OBJ';
 68
 69			case JSON_END_OBJ:
 70				return 'JSON_END_OBJ';
 71
 72			case JSON_START_ARRAY:
 73				return 'JSON_START_ARRAY';
 74
 75			case JSON_END_ARRAY:
 76				return 'JSON_END_ARRAY';
 77
 78			case JSON_KEY:
 79				return 'JSON_KEY';
 80		}
 81
 82		return 'UNKNOWN';
 83	}
 84
 85	function getValue() {
 86		return $this->_value;
 87	}
 88
 89	function readToken() {
 90		$chr = $this->read();
 91
 92		if ($chr != null) {
 93			switch ($chr) {
 94				case '[':
 95					$this->_lastLocation[] = $this->_location;
 96					$this->_location = JSON_IN_ARRAY;
 97					$this->_token = JSON_START_ARRAY;
 98					$this->_value = null;
 99					$this->readAway();
100					return true;
101
102				case ']':
103					$this->_location = array_pop($this->_lastLocation);
104					$this->_token = JSON_END_ARRAY;
105					$this->_value = null;
106					$this->readAway();
107
108					if ($this->_location == JSON_IN_OBJECT)
109						$this->_needProp = true;
110
111					return true;
112
113				case '{':
114					$this->_lastLocation[] = $this->_location;
115					$this->_location = JSON_IN_OBJECT;
116					$this->_needProp = true;
117					$this->_token = JSON_START_OBJ;
118					$this->_value = null;
119					$this->readAway();
120					return true;
121
122				case '}':
123					$this->_location = array_pop($this->_lastLocation);
124					$this->_token = JSON_END_OBJ;
125					$this->_value = null;
126					$this->readAway();
127
128					if ($this->_location == JSON_IN_OBJECT)
129						$this->_needProp = true;
130
131					return true;
132
133				// String
134				case '"':
135				case '\'':
136					return $this->_readString($chr);
137
138				// Null
139				case 'n':
140					return $this->_readNull();
141
142				// Bool
143				case 't':
144				case 'f':
145					return $this->_readBool($chr);
146
147				default:
148					// Is number
149					if (is_numeric($chr) || $chr == '-' || $chr == '.')
150						return $this->_readNumber($chr);
151
152					return true;
153			}
154		}
155
156		return false;
157	}
158
159	function _readBool($chr) {
160		$this->_token = JSON_BOOL;
161		$this->_value = $chr == 't';
162
163		if ($chr == 't')
164			$this->skip(3); // rue
165		else
166			$this->skip(4); // alse
167
168		$this->readAway();
169
170		if ($this->_location == JSON_IN_OBJECT && !$this->_needProp)
171			$this->_needProp = true;
172
173		return true;
174	}
175
176	function _readNull() {
177		$this->_token = JSON_NULL;
178		$this->_value = null;
179
180		$this->skip(3); // ull
181		$this->readAway();
182
183		if ($this->_location == JSON_IN_OBJECT && !$this->_needProp)
184			$this->_needProp = true;
185
186		return true;
187	}
188
189	function _readString($quote) {
190		$output = "";
191		$this->_token = JSON_STR;
192		$endString = false;
193
194		while (($chr = $this->peek()) != -1) {
195			switch ($chr) {
196				case '\\':
197					// Read away slash
198					$this->read();
199
200					// Read escape code
201					$chr = $this->read();
202					switch ($chr) {
203							case 't':
204								$output .= "\t";
205								break;
206
207							case 'b':
208								$output .= "\b";
209								break;
210
211							case 'f':
212								$output .= "\f";
213								break;
214
215							case 'r':
216								$output .= "\r";
217								break;
218
219							case 'n':
220								$output .= "\n";
221								break;
222
223							case 'u':
224								$output .= $this->_int2utf8(hexdec($this->read(4)));
225								break;
226
227							default:
228								$output .= $chr;
229								break;
230					}
231
232					break;
233
234					case '\'':
235					case '"':
236						if ($chr == $quote)
237							$endString = true;
238
239						$chr = $this->read();
240						if ($chr != -1 && $chr != $quote)
241							$output .= $chr;
242
243						break;
244
245					default:
246						$output .= $this->read();
247			}
248
249			// String terminated
250			if ($endString)
251				break;
252		}
253
254		$this->readAway();
255		$this->_value = $output;
256
257		// Needed a property
258		if ($this->_needProp) {
259			$this->_token = JSON_KEY;
260			$this->_needProp = false;
261			return true;
262		}
263
264		if ($this->_location == JSON_IN_OBJECT && !$this->_needProp)
265			$this->_needProp = true;
266
267		return true;
268	}
269
270	function _int2utf8($int) {
271		$int = intval($int);
272
273		switch ($int) {
274			case 0:
275				return chr(0);
276
277			case ($int & 0x7F):
278				return chr($int);
279
280			case ($int & 0x7FF):
281				return chr(0xC0 | (($int >> 6) & 0x1F)) . chr(0x80 | ($int & 0x3F));
282
283			case ($int & 0xFFFF):
284				return chr(0xE0 | (($int >> 12) & 0x0F)) . chr(0x80 | (($int >> 6) & 0x3F)) . chr (0x80 | ($int & 0x3F));
285
286			case ($int & 0x1FFFFF):
287				return chr(0xF0 | ($int >> 18)) . chr(0x80 | (($int >> 12) & 0x3F)) . chr(0x80 | (($int >> 6) & 0x3F)) . chr(0x80 | ($int & 0x3F));
288		}
289	}
290
291	function _readNumber($start) {
292		$value = "";
293		$isFloat = false;
294
295		$this->_token = JSON_INT;
296		$value .= $start;
297
298		while (($chr = $this->peek()) != -1) {
299			if (is_numeric($chr) || $chr == '-' || $chr == '.') {
300				if ($chr == '.')
301					$isFloat = true;
302
303				$value .= $this->read();
304			} else
305				break;
306		}
307
308		$this->readAway();
309
310		if ($isFloat) {
311			$this->_token = JSON_FLOAT;
312			$this->_value = floatval($value);
313		} else
314			$this->_value = intval($value);
315
316		if ($this->_location == JSON_IN_OBJECT && !$this->_needProp)
317			$this->_needProp = true;
318
319		return true;
320	}
321
322	function readAway() {
323		while (($chr = $this->peek()) != null) {
324			if ($chr != ':' && $chr != ',' && $chr != ' ')
325				return;
326
327			$this->read();
328		}
329	}
330
331	function read($len = 1) {
332		if ($this->_pos < $this->_len) {
333			if ($len > 1) {
334				$str = substr($this->_data, $this->_pos + 1, $len);
335				$this->_pos += $len;
336
337				return $str;
338			} else
339				return $this->_data[++$this->_pos];
340		}
341
342		return null;
343	}
344
345	function skip($len) {
346		$this->_pos += $len;
347	}
348
349	function peek() {
350		if ($this->_pos < $this->_len)
351			return $this->_data[$this->_pos + 1];
352
353		return null;
354	}
355}
356
357/**
358 * This class handles JSON stuff.
359 *
360 * @package MCManager.utils
361 */
362class Moxiecode_JSON {
363	function Moxiecode_JSON() {
364	}
365
366	function decode($input) {
367		$reader = new Moxiecode_JSONReader($input);
368
369		return $this->readValue($reader);
370	}
371
372	function readValue(&$reader) {
373		$this->data = array();
374		$this->parents = array();
375		$this->cur =& $this->data;
376		$key = null;
377		$loc = JSON_IN_ARRAY;
378
379		while ($reader->readToken()) {
380			switch ($reader->getToken()) {
381				case JSON_STR:
382				case JSON_INT:
383				case JSON_BOOL:
384				case JSON_FLOAT:
385				case JSON_NULL:
386					switch ($reader->getLocation()) {
387						case JSON_IN_OBJECT:
388							$this->cur[$key] = $reader->getValue();
389							break;
390
391						case JSON_IN_ARRAY:
392							$this->cur[] = $reader->getValue();
393							break;
394
395						default:
396							return $reader->getValue();
397					}
398					break;
399
400				case JSON_KEY:
401					$key = $reader->getValue();
402					break;
403
404				case JSON_START_OBJ:
405				case JSON_START_ARRAY:
406					if ($loc == JSON_IN_OBJECT)
407						$this->addArray($key);
408					else
409						$this->addArray(null);
410
411					$cur =& $obj;
412
413					$loc = $reader->getLocation();
414					break;
415
416				case JSON_END_OBJ:
417				case JSON_END_ARRAY:
418					$loc = $reader->getLocation();
419
420					if (count($this->parents) > 0) {
421						$this->cur =& $this->parents[count($this->parents) - 1];
422						array_pop($this->parents);
423					}
424					break;
425			}
426		}
427
428		return $this->data[0];
429	}
430
431	// This method was needed since PHP is crapy and doesn't have pointers/references
432	function addArray($key) {
433		$this->parents[] =& $this->cur;
434		$ar = array();
435
436		if ($key)
437			$this->cur[$key] =& $ar;
438		else
439			$this->cur[] =& $ar;
440
441		$this->cur =& $ar;
442	}
443
444	function getDelim($index, &$reader) {
445		switch ($reader->getLocation()) {
446			case JSON_IN_ARRAY:
447			case JSON_IN_OBJECT:
448				if ($index > 0)
449					return ",";
450				break;
451		}
452
453		return "";
454	}
455
456	function encode($input) {
457		switch (gettype($input)) {
458			case 'boolean':
459				return $input ? 'true' : 'false';
460
461			case 'integer':
462				return (int) $input;
463
464			case 'float':
465			case 'double':
466				return (float) $input;
467
468			case 'NULL':
469				return 'null';
470
471			case 'string':
472				return $this->encodeString($input);
473
474			case 'array':
475				return $this->_encodeArray($input);
476
477			case 'object':
478				return $this->_encodeArray(get_object_vars($input));
479		}
480
481		return '';
482	}
483
484	function encodeString($input) {
485		// Needs to be escaped
486		if (preg_match('/[^a-zA-Z0-9]/', $input)) {
487			$output = '';
488
489			for ($i=0; $i<strlen($input); $i++) {
490				switch ($input[$i]) {
491					case "\b":
492						$output .= "\\b";
493						break;
494
495					case "\t":
496						$output .= "\\t";
497						break;
498
499					case "\f":
500						$output .= "\\f";
501						break;
502
503					case "\r":
504						$output .= "\\r";
505						break;
506
507					case "\n":
508						$output .= "\\n";
509						break;
510
511					case '\\':
512						$output .= "\\\\";
513						break;
514
515					case '\'':
516						$output .= "\\'";
517						break;
518
519					case '"':
520						$output .= '\"';
521						break;
522
523					default:
524						$byte = ord($input[$i]);
525
526						if (($byte & 0xE0) == 0xC0) {
527							$char = pack('C*', $byte, ord($input[$i + 1]));
528							$i += 1;
529							$output .= sprintf('\u%04s', bin2hex($this->_utf82utf16($char)));
530						} if (($byte & 0xF0) == 0xE0) {
531							$char = pack('C*', $byte, ord($input[$i + 1]), ord($input[$i + 2]));
532							$i += 2;
533							$output .= sprintf('\u%04s', bin2hex($this->_utf82utf16($char)));
534						} if (($byte & 0xF8) == 0xF0) {
535							$char = pack('C*', $byte, ord($input[$i + 1]), ord($input[$i + 2]), ord($input[$i + 3]));
536							$i += 3;
537							$output .= sprintf('\u%04s', bin2hex($this->_utf82utf16($char)));
538						} if (($byte & 0xFC) == 0xF8) {
539							$char = pack('C*', $byte, ord($input[$i + 1]), ord($input[$i + 2]), ord($input[$i + 3]), ord($input[$i + 4]));
540							$i += 4;
541							$output .= sprintf('\u%04s', bin2hex($this->_utf82utf16($char)));
542						} if (($byte & 0xFE) == 0xFC) {
543							$char = pack('C*', $byte, ord($input[$i + 1]), ord($input[$i + 2]), ord($input[$i + 3]), ord($input[$i + 4]), ord($input[$i + 5]));
544							$i += 5;
545							$output .= sprintf('\u%04s', bin2hex($this->_utf82utf16($char)));
546						} else if ($byte < 128)
547							$output .= $input[$i];
548				}
549			}
550
551			return '"' . $output . '"';
552		}
553
554		return '"' . $input . '"';
555	}
556
557	function _utf82utf16($utf8) {
558		if (function_exists('mb_convert_encoding'))
559			return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8');
560
561		switch (strlen($utf8)) {
562			case 1:
563				return $utf8;
564
565			case 2:
566				return chr(0x07 & (ord($utf8[0]) >> 2)) . chr((0xC0 & (ord($utf8[0]) << 6)) | (0x3F & ord($utf8[1])));
567
568			case 3:
569				return chr((0xF0 & (ord($utf8[0]) << 4)) | (0x0F & (ord($utf8[1]) >> 2))) . chr((0xC0 & (ord($utf8[1]) << 6)) | (0x7F & ord($utf8[2])));
570		}
571
572		return '';
573	}
574
575	function _encodeArray($input) {
576		$output = '';
577		$isIndexed = true;
578
579		$keys = array_keys($input);
580		for ($i=0; $i<count($keys); $i++) {
581			if (!is_int($keys[$i])) {
582				$output .= $this->encodeString($keys[$i]) . ':' . $this->encode($input[$keys[$i]]);
583				$isIndexed = false;
584			} else
585				$output .= $this->encode($input[$keys[$i]]);
586
587			if ($i != count($keys) - 1)
588				$output .= ',';
589		}
590
591		return $isIndexed ? '[' . $output . ']' : '{' . $output . '}';
592	}
593}
594
595?>