includes/clientside/tinymce/plugins/spellchecker/classes/utils/JSON.php
changeset 784 72df14a56a03
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/includes/clientside/tinymce/plugins/spellchecker/classes/utils/JSON.php	Sun Dec 21 17:56:32 2008 -0500
@@ -0,0 +1,595 @@
+<?php
+/**
+ * $Id: JSON.php 40 2007-06-18 11:43:15Z spocke $
+ *
+ * @package MCManager.utils
+ * @author Moxiecode
+ * @copyright Copyright © 2007, Moxiecode Systems AB, All rights reserved.
+ */
+
+define('JSON_BOOL', 1);
+define('JSON_INT', 2);
+define('JSON_STR', 3);
+define('JSON_FLOAT', 4);
+define('JSON_NULL', 5);
+define('JSON_START_OBJ', 6);
+define('JSON_END_OBJ', 7);
+define('JSON_START_ARRAY', 8);
+define('JSON_END_ARRAY', 9);
+define('JSON_KEY', 10);
+define('JSON_SKIP', 11);
+
+define('JSON_IN_ARRAY', 30);
+define('JSON_IN_OBJECT', 40);
+define('JSON_IN_BETWEEN', 50);
+
+class Moxiecode_JSONReader {
+	var $_data, $_len, $_pos;
+	var $_value, $_token;
+	var $_location, $_lastLocations;
+	var $_needProp;
+
+	function Moxiecode_JSONReader($data) {
+		$this->_data = $data;
+		$this->_len = strlen($data);
+		$this->_pos = -1;
+		$this->_location = JSON_IN_BETWEEN;
+		$this->_lastLocations = array();
+		$this->_needProp = false;
+	}
+
+	function getToken() {
+		return $this->_token;
+	}
+
+	function getLocation() {
+		return $this->_location;
+	}
+
+	function getTokenName() {
+		switch ($this->_token) {
+			case JSON_BOOL:
+				return 'JSON_BOOL';
+
+			case JSON_INT:
+				return 'JSON_INT';
+
+			case JSON_STR:
+				return 'JSON_STR';
+
+			case JSON_FLOAT:
+				return 'JSON_FLOAT';
+
+			case JSON_NULL:
+				return 'JSON_NULL';
+
+			case JSON_START_OBJ:
+				return 'JSON_START_OBJ';
+
+			case JSON_END_OBJ:
+				return 'JSON_END_OBJ';
+
+			case JSON_START_ARRAY:
+				return 'JSON_START_ARRAY';
+
+			case JSON_END_ARRAY:
+				return 'JSON_END_ARRAY';
+
+			case JSON_KEY:
+				return 'JSON_KEY';
+		}
+
+		return 'UNKNOWN';
+	}
+
+	function getValue() {
+		return $this->_value;
+	}
+
+	function readToken() {
+		$chr = $this->read();
+
+		if ($chr != null) {
+			switch ($chr) {
+				case '[':
+					$this->_lastLocation[] = $this->_location;
+					$this->_location = JSON_IN_ARRAY;
+					$this->_token = JSON_START_ARRAY;
+					$this->_value = null;
+					$this->readAway();
+					return true;
+
+				case ']':
+					$this->_location = array_pop($this->_lastLocation);
+					$this->_token = JSON_END_ARRAY;
+					$this->_value = null;
+					$this->readAway();
+
+					if ($this->_location == JSON_IN_OBJECT)
+						$this->_needProp = true;
+
+					return true;
+
+				case '{':
+					$this->_lastLocation[] = $this->_location;
+					$this->_location = JSON_IN_OBJECT;
+					$this->_needProp = true;
+					$this->_token = JSON_START_OBJ;
+					$this->_value = null;
+					$this->readAway();
+					return true;
+
+				case '}':
+					$this->_location = array_pop($this->_lastLocation);
+					$this->_token = JSON_END_OBJ;
+					$this->_value = null;
+					$this->readAway();
+
+					if ($this->_location == JSON_IN_OBJECT)
+						$this->_needProp = true;
+
+					return true;
+
+				// String
+				case '"':
+				case '\'':
+					return $this->_readString($chr);
+
+				// Null
+				case 'n':
+					return $this->_readNull();
+
+				// Bool
+				case 't':
+				case 'f':
+					return $this->_readBool($chr);
+
+				default:
+					// Is number
+					if (is_numeric($chr) || $chr == '-' || $chr == '.')
+						return $this->_readNumber($chr);
+
+					return true;
+			}
+		}
+
+		return false;
+	}
+
+	function _readBool($chr) {
+		$this->_token = JSON_BOOL;
+		$this->_value = $chr == 't';
+
+		if ($chr == 't')
+			$this->skip(3); // rue
+		else
+			$this->skip(4); // alse
+
+		$this->readAway();
+
+		if ($this->_location == JSON_IN_OBJECT && !$this->_needProp)
+			$this->_needProp = true;
+
+		return true;
+	}
+
+	function _readNull() {
+		$this->_token = JSON_NULL;
+		$this->_value = null;
+
+		$this->skip(3); // ull
+		$this->readAway();
+
+		if ($this->_location == JSON_IN_OBJECT && !$this->_needProp)
+			$this->_needProp = true;
+
+		return true;
+	}
+
+	function _readString($quote) {
+		$output = "";
+		$this->_token = JSON_STR;
+		$endString = false;
+
+		while (($chr = $this->peek()) != -1) {
+			switch ($chr) {
+				case '\\':
+					// Read away slash
+					$this->read();
+
+					// Read escape code
+					$chr = $this->read();
+					switch ($chr) {
+							case 't':
+								$output .= "\t";
+								break;
+
+							case 'b':
+								$output .= "\b";
+								break;
+
+							case 'f':
+								$output .= "\f";
+								break;
+
+							case 'r':
+								$output .= "\r";
+								break;
+
+							case 'n':
+								$output .= "\n";
+								break;
+
+							case 'u':
+								$output .= $this->_int2utf8(hexdec($this->read(4)));
+								break;
+
+							default:
+								$output .= $chr;
+								break;
+					}
+
+					break;
+
+					case '\'':
+					case '"':
+						if ($chr == $quote)
+							$endString = true;
+
+						$chr = $this->read();
+						if ($chr != -1 && $chr != $quote)
+							$output .= $chr;
+
+						break;
+
+					default:
+						$output .= $this->read();
+			}
+
+			// String terminated
+			if ($endString)
+				break;
+		}
+
+		$this->readAway();
+		$this->_value = $output;
+
+		// Needed a property
+		if ($this->_needProp) {
+			$this->_token = JSON_KEY;
+			$this->_needProp = false;
+			return true;
+		}
+
+		if ($this->_location == JSON_IN_OBJECT && !$this->_needProp)
+			$this->_needProp = true;
+
+		return true;
+	}
+
+	function _int2utf8($int) {
+		$int = intval($int);
+
+		switch ($int) {
+			case 0:
+				return chr(0);
+
+			case ($int & 0x7F):
+				return chr($int);
+
+			case ($int & 0x7FF):
+				return chr(0xC0 | (($int >> 6) & 0x1F)) . chr(0x80 | ($int & 0x3F));
+
+			case ($int & 0xFFFF):
+				return chr(0xE0 | (($int >> 12) & 0x0F)) . chr(0x80 | (($int >> 6) & 0x3F)) . chr (0x80 | ($int & 0x3F));
+
+			case ($int & 0x1FFFFF):
+				return chr(0xF0 | ($int >> 18)) . chr(0x80 | (($int >> 12) & 0x3F)) . chr(0x80 | (($int >> 6) & 0x3F)) . chr(0x80 | ($int & 0x3F));
+		}
+	}
+
+	function _readNumber($start) {
+		$value = "";
+		$isFloat = false;
+
+		$this->_token = JSON_INT;
+		$value .= $start;
+
+		while (($chr = $this->peek()) != -1) {
+			if (is_numeric($chr) || $chr == '-' || $chr == '.') {
+				if ($chr == '.')
+					$isFloat = true;
+
+				$value .= $this->read();
+			} else
+				break;
+		}
+
+		$this->readAway();
+
+		if ($isFloat) {
+			$this->_token = JSON_FLOAT;
+			$this->_value = floatval($value);
+		} else
+			$this->_value = intval($value);
+
+		if ($this->_location == JSON_IN_OBJECT && !$this->_needProp)
+			$this->_needProp = true;
+
+		return true;
+	}
+
+	function readAway() {
+		while (($chr = $this->peek()) != null) {
+			if ($chr != ':' && $chr != ',' && $chr != ' ')
+				return;
+
+			$this->read();
+		}
+	}
+
+	function read($len = 1) {
+		if ($this->_pos < $this->_len) {
+			if ($len > 1) {
+				$str = substr($this->_data, $this->_pos + 1, $len);
+				$this->_pos += $len;
+
+				return $str;
+			} else
+				return $this->_data[++$this->_pos];
+		}
+
+		return null;
+	}
+
+	function skip($len) {
+		$this->_pos += $len;
+	}
+
+	function peek() {
+		if ($this->_pos < $this->_len)
+			return $this->_data[$this->_pos + 1];
+
+		return null;
+	}
+}
+
+/**
+ * This class handles JSON stuff.
+ *
+ * @package MCManager.utils
+ */
+class Moxiecode_JSON {
+	function Moxiecode_JSON() {
+	}
+
+	function decode($input) {
+		$reader = new Moxiecode_JSONReader($input);
+
+		return $this->readValue($reader);
+	}
+
+	function readValue(&$reader) {
+		$this->data = array();
+		$this->parents = array();
+		$this->cur =& $this->data;
+		$key = null;
+		$loc = JSON_IN_ARRAY;
+
+		while ($reader->readToken()) {
+			switch ($reader->getToken()) {
+				case JSON_STR:
+				case JSON_INT:
+				case JSON_BOOL:
+				case JSON_FLOAT:
+				case JSON_NULL:
+					switch ($reader->getLocation()) {
+						case JSON_IN_OBJECT:
+							$this->cur[$key] = $reader->getValue();
+							break;
+
+						case JSON_IN_ARRAY:
+							$this->cur[] = $reader->getValue();
+							break;
+
+						default:
+							return $reader->getValue();
+					}
+					break;
+
+				case JSON_KEY:
+					$key = $reader->getValue();
+					break;
+
+				case JSON_START_OBJ:
+				case JSON_START_ARRAY:
+					if ($loc == JSON_IN_OBJECT)
+						$this->addArray($key);
+					else
+						$this->addArray(null);
+
+					$cur =& $obj;
+
+					$loc = $reader->getLocation();
+					break;
+
+				case JSON_END_OBJ:
+				case JSON_END_ARRAY:
+					$loc = $reader->getLocation();
+
+					if (count($this->parents) > 0) {
+						$this->cur =& $this->parents[count($this->parents) - 1];
+						array_pop($this->parents);
+					}
+					break;
+			}
+		}
+
+		return $this->data[0];
+	}
+
+	// This method was needed since PHP is crapy and doesn't have pointers/references
+	function addArray($key) {
+		$this->parents[] =& $this->cur;
+		$ar = array();
+
+		if ($key)
+			$this->cur[$key] =& $ar;
+		else
+			$this->cur[] =& $ar;
+
+		$this->cur =& $ar;
+	}
+
+	function getDelim($index, &$reader) {
+		switch ($reader->getLocation()) {
+			case JSON_IN_ARRAY:
+			case JSON_IN_OBJECT:
+				if ($index > 0)
+					return ",";
+				break;
+		}
+
+		return "";
+	}
+
+	function encode($input) {
+		switch (gettype($input)) {
+			case 'boolean':
+				return $input ? 'true' : 'false';
+
+			case 'integer':
+				return (int) $input;
+
+			case 'float':
+			case 'double':
+				return (float) $input;
+
+			case 'NULL':
+				return 'null';
+
+			case 'string':
+				return $this->encodeString($input);
+
+			case 'array':
+				return $this->_encodeArray($input);
+
+			case 'object':
+				return $this->_encodeArray(get_object_vars($input));
+		}
+
+		return '';
+	}
+
+	function encodeString($input) {
+		// Needs to be escaped
+		if (preg_match('/[^a-zA-Z0-9]/', $input)) {
+			$output = '';
+
+			for ($i=0; $i<strlen($input); $i++) {
+				switch ($input[$i]) {
+					case "\b":
+						$output .= "\\b";
+						break;
+
+					case "\t":
+						$output .= "\\t";
+						break;
+
+					case "\f":
+						$output .= "\\f";
+						break;
+
+					case "\r":
+						$output .= "\\r";
+						break;
+
+					case "\n":
+						$output .= "\\n";
+						break;
+
+					case '\\':
+						$output .= "\\\\";
+						break;
+
+					case '\'':
+						$output .= "\\'";
+						break;
+
+					case '"':
+						$output .= '\"';
+						break;
+
+					default:
+						$byte = ord($input[$i]);
+
+						if (($byte & 0xE0) == 0xC0) {
+							$char = pack('C*', $byte, ord($input[$i + 1]));
+							$i += 1;
+							$output .= sprintf('\u%04s', bin2hex($this->_utf82utf16($char)));
+						} if (($byte & 0xF0) == 0xE0) {
+							$char = pack('C*', $byte, ord($input[$i + 1]), ord($input[$i + 2]));
+							$i += 2;
+							$output .= sprintf('\u%04s', bin2hex($this->_utf82utf16($char)));
+						} if (($byte & 0xF8) == 0xF0) {
+							$char = pack('C*', $byte, ord($input[$i + 1]), ord($input[$i + 2], ord($input[$i + 3])));
+							$i += 3;
+							$output .= sprintf('\u%04s', bin2hex($this->_utf82utf16($char)));
+						} if (($byte & 0xFC) == 0xF8) {
+							$char = pack('C*', $byte, ord($input[$i + 1]), ord($input[$i + 2], ord($input[$i + 3]), ord($input[$i + 4])));
+							$i += 4;
+							$output .= sprintf('\u%04s', bin2hex($this->_utf82utf16($char)));
+						} if (($byte & 0xFE) == 0xFC) {
+							$char = pack('C*', $byte, ord($input[$i + 1]), ord($input[$i + 2], ord($input[$i + 3]), ord($input[$i + 4]), ord($input[$i + 5])));
+							$i += 5;
+							$output .= sprintf('\u%04s', bin2hex($this->_utf82utf16($char)));
+						} else if ($byte < 128)
+							$output .= $input[$i];
+				}
+			}
+
+			return '"' . $output . '"';
+		}
+
+		return '"' . $input . '"';
+	}
+
+	function _utf82utf16($utf8) {
+		if (function_exists('mb_convert_encoding'))
+			return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8');
+
+		switch (strlen($utf8)) {
+			case 1:
+				return $utf8;
+
+			case 2:
+				return chr(0x07 & (ord($utf8[0]) >> 2)) . chr((0xC0 & (ord($utf8[0]) << 6)) | (0x3F & ord($utf8[1])));
+
+			case 3:
+				return chr((0xF0 & (ord($utf8[0]) << 4)) | (0x0F & (ord($utf8[1]) >> 2))) . chr((0xC0 & (ord($utf8[1]) << 6)) | (0x7F & ord($utf8[2])));
+		}
+
+		return '';
+	}
+
+	function _encodeArray($input) {
+		$output = '';
+		$isIndexed = true;
+
+		$keys = array_keys($input);
+		for ($i=0; $i<count($keys); $i++) {
+			if (!is_int($keys[$i])) {
+				$output .= $this->encodeString($keys[$i]) . ':' . $this->encode($input[$keys[$i]]);
+				$isIndexed = false;
+			} else
+				$output .= $this->encode($input[$keys[$i]]);
+
+			if ($i != count($keys) - 1)
+				$output .= ',';
+		}
+
+		return $isIndexed ? '[' . $output . ']' : '{' . $output . '}';
+	}
+}
+
+?>