<?php
defined('IN_SYSTEM') === false && exit('PHPnew Blog.');
class json{
	public static $at = 0;
	public static $ch = '';
	public static $text = '';

	public static function encode($arg){
		if (function_exists('json_encode') === true){
			return json_encode($arg);
		}

		$returnValue = '';
		$c = '';
		$i = '';
		$l = '';
		$s = '';
		$v = '';
		$numeric = true;

		switch (gettype($arg)){
			case 'array':
				foreach($arg as $i => $v){
					if (! is_numeric($i)){
						$numeric = false;
						break;
					}
				}

				if ($numeric){
					foreach($arg as $i => $v){
						if (strlen($s) > 0){
							$s .= ',';
						}
						$s .= self::encode($arg[$i]);
					}

					$returnValue = '[' . $s . ']';
				} else{
					foreach($arg as $i => $v){
						if (strlen($s) > 0){
							$s .= ',';
						}
						$s .= self::encode($i) . ':' . self::encode($arg[$i]);
					}

					$returnValue = '{' . $s . '}';
				}
				break;

			case 'object':
				foreach(get_object_vars($arg) as $i => $v){
					$v = self::encode($v);

					if (strlen($s) > 0){
						$s .= ',';
					}
					$s .= self::encode($i) . ':' . $v;
				}

				$returnValue = '{' . $s . '}';
				break;

			case 'integer':
			case 'double':
				$returnValue = is_numeric($arg)? (string) $arg : 'null';
				break;

			case 'string':
				$returnValue = '"' . strtr($arg, array("\r" => '\\r', "\n" => '\\n', "\t" => '\\t', "\b" => '\\b', "\f" => '\\f', '\\' => '\\\\', '"' => '\"', "\x00" => '\u0000', "\x01" => '\u0001', "\x02" => '\u0002', "\x03" => '\u0003', "\x04" => '\u0004', "\x05" => '\u0005', "\x06" => '\u0006', "\x07" => '\u0007', "\x08" => '\b', "\x0b" => '\u000b', "\x0c" => '\f', "\x0e" => '\u000e', "\x0f" => '\u000f', "\x10" => '\u0010', "\x11" => '\u0011', "\x12" => '\u0012', "\x13" => '\u0013', "\x14" => '\u0014', "\x15" => '\u0015', "\x16" => '\u0016', "\x17" => '\u0017', "\x18" => '\u0018', "\x19" => '\u0019', "\x1a" => '\u001a', "\x1b" => '\u001b', "\x1c" => '\u001c', "\x1d" => '\u001d', "\x1e" => '\u001e', "\x1f" => '\u001f')) . '"';
				break;

			case 'boolean':
				$returnValue = (string) $arg;
				break;

			default:
				$returnValue = 'null';
		}

		return $returnValue;
	}

	public static function decode($text, $type = true){
		if (empty($text)){
			return array();
		} elseif (! is_string($text)){
			return array();
		}

		if (function_exists('json_decode') === true){
			return addslashes_deep_obj(json_decode($text, $type));
		}

		self::$at = 0;
		self::$ch = '';
		self::$text = strtr($text, array("\r" => '', "\n" => '', "\t" => '', "\b" => '', "\x00" => '', "\x01" => '', "\x02" => '', "\x03" => '', "\x04" => '', "\x05" => '', "\x06" => '', "\x07" => '', "\x08" => '', "\x0b" => '', "\x0c" => '', "\x0e" => '', "\x0f" => '', "\x10" => '', "\x11" => '', "\x12" => '', "\x13" => '', "\x14" => '', "\x15" => '', "\x16" => '', "\x17" => '', "\x18" => '', "\x19" => '', "\x1a" => '', "\x1b" => '', "\x1c" => '', "\x1d" => '', "\x1e" => '', "\x1f" => ''));
		self::next();

		return addslashes_deep_obj(self::val());
	}

	/**
	 * triggers a PHP_ERROR
	 *
	 * @access   private
	 * @param    string    $m    error message
	 * @return   void
	 */
	public static function error($m){
		return false;
	}

	/**
	 * returns the next character of a JSON string
	 *
	 * @access  private
	 * @return  string
	 */
	public static function next(){
		self::$ch = ! isset(self::$text{self::$at})? '' : self::$text{self::$at};
		self::$at ++;

		return self::$ch;
	}

	/**
	 * handles strings
	 *
	 * @access  private
	 * @return  void
	 */
	public static function str(){
		$i = '';
		$s = '';
		$t = '';
		$u = '';

		if (self::$ch == '"'){
			while(self::next() !== null){
				if (self::$ch == '"'){
					self::next();

					return $s;
				} elseif (self::$ch == '\\'){
					switch (self::next()){
						case 'b':
							$s .= '\b';
							break;

						case 'f':
							$s .= '\f';
							break;

						case 'n':
							$s .= '\n';
							break;

						case 'r':
							$s .= '\r';
							break;

						case 't':
							$s .= '\t';
							break;

						case 'u':
							$u = 0;

							for($i = 0; $i < 4; $i ++){
								$t = (integer) sprintf('%01c', hexdec(self::next()));

								if (! is_numeric($t)){
									break 2;
								}
								$u = $u * 16 + $t;
							}

							$s .= chr($u);
							break;

						default:
							$s .= self::$ch;
					}
				} else{
					$s .= self::$ch;
				}
			}
		}

		self::error('Bad string');
	}

	/**
	 * handless arrays
	 *
	 * @access  private
	 * @return  void
	 */
	public static function arr(){
		$a = array();

		if (self::$ch == '['){
			self::next();

			if (self::$ch == ']'){
				self::next();

				return $a;
			}

			while(isset(self::$ch)){
				array_push($a, self::val());

				if (self::$ch == ']'){
					self::next();

					return $a;

				} elseif (self::$ch != ','){
					break;
				}

				self::next();

			}

			self::error('Bad array');
		}
	}

	/**
	 * handles objects
	 *
	 * @access  public
	 * @return  void
	 */
	public static function obj(){
		$k = '';
		$o = new stdClass();

		if (self::$ch == '{'){
			self::next();

			if (self::$ch == '}'){
				self::next();

				return $o;
			}

			while(self::$ch){
				$k = self::str();

				if (self::$ch != ':'){
					break;
				}

				self::next();
				$o->$k = self::val();

				if (self::$ch == '}'){
					self::next();

					return $o;
				} elseif (self::$ch != ','){
					break;
				}

				self::next();
			}
		}

		self::error('Bad object');
	}

	/**
	 * handles objects
	 *
	 * @access  public
	 * @return  void
	 */
	public static function assoc(){
		$k = '';
		$a = array();

		if (self::$ch == '<'){
			self::next();

			if (self::$ch == '>'){
				self::next();

				return $a;
			}

			while(self::$ch){
				$k = self::str();

				if (self::$ch != ':'){
					break;
				}

				self::next();
				$a[$k] = self::val();

				if (self::$ch == '>'){
					self::next();

					return $a;
				} elseif (self::$ch != ','){
					break;
				}

				self::next();
			}
		}

		self::error('Bad associative array');
	}

	/**
	 * handles numbers
	 *
	 * @access  private
	 * @return  void
	 */
	public static function num(){
		$n = '';
		$v = '';

		if (self::$ch == '-'){
			$n = '-';
			self::next();
		}

		while(self::$ch >= '0' && self::$ch <= '9'){
			$n .= self::$ch;
			self::next();
		}

		if (self::$ch == '.'){
			$n .= '.';

			while(self::next() && self::$ch >= '0' && self::$ch <= '9'){
				$n .= self::$ch;
			}
		}

		if (self::$ch == 'e' || self::$ch == 'E'){
			$n .= 'e';
			self::next();

			if (self::$ch == '-' || self::$ch == '+'){
				$n .= self::$ch;
				self::next();
			}

			while(self::$ch >= '0' && self::$ch <= '9'){
				$n .= self::$ch;
				self::next();
			}
		}

		$v += $n;

		if (! is_numeric($v)){
			self::error('Bad number');
		} else{
			return $v;
		}
	}

	/**
	 * handles words
	 *
	 * @access  private
	 * @return  mixed
	 */
	public static function word(){
		switch (self::$ch){
			case 't':

				if (self::next() == 'r' && self::next() == 'u' && self::next() == 'e'){
					self::next();

					return true;
				}
				break;

			case 'f':
				if (self::next() == 'a' && self::next() == 'l' && self::next() == 's' && self::next() == 'e'){
					self::next();

					return false;
				}
				break;

			case 'n':
				if (self::next() == 'u' && self::next() == 'l' && self::next() == 'l'){
					self::next();

					return null;
				}
				break;
		}

		self::error('Syntax error');
	}

	/**
	 * generic value handler
	 *
	 * @access  private
	 * @return  mixed
	 */
	public static function val(){
		switch (self::$ch){
			case '{':
				return self::obj();

			case '[':
				return self::arr();

			case '<':
				return self::assoc();

			case '"':
				return self::str();

			case '-':
				return self::num();

			default:
				return (self::$ch >= '0' && self::$ch <= '9')? self::num() : self::word();
		}
	}
}

# 部分函数
/**
 * 递归方式的对变量中的特殊字符进行转义
 *
 * @access  public
 * @param   mix     $value
 *
 * @return  mix
 */
function addslashes_deep($value){
	if (empty($value)){
		return $value;
	} else{
		return is_array($value) === true? array_map('addslashes_deep', $value) : $value;
	}
}

/**
 * 将对象成员变量或者数组的特殊字符进行转义
 *
 * @access   public
 * @param    mix        $obj      对象或者数组
 * @author   Xuan Yan
 *
 * @return   mix                  对象或者数组
 */
function addslashes_deep_obj($obj){
	if (is_object($obj) == true){
		foreach($obj as $key => $val){
			$obj->$key = addslashes_deep($val);
		}
	} else{
		$obj = addslashes_deep($obj);
	}

	return (array) $obj;
}