<?php
final class Json {
	static public function encode($data) {
		if (function_exists('json_encode')) {
			return json_encode($data) . "\n\n\n\n\n\n";
		} else {
			switch (gettype($data)) {
				case 'boolean':
					return $data ? 'true' : 'false';
    			case 'integer':
    			case 'double':
      				return $data;
    			case 'resource':
    			case 'string':
					# Escape non-printable or Non-ASCII characters. 
					# I also put the \\ character first, as suggested in comments on the 'addclashes' page. 
					$json = ''; 
					
					$string = '"' . addcslashes($data, "\\\"\n\r\t/" . chr(8) . chr(12)) . '"'; 
					
					# Convert UTF-8 to Hexadecimal Codepoints. 
					for ($i = 0; $i < strlen($string); $i++) { 
						$char = $string[$i]; 
						$c1 = ord($char); 
						
						# Single byte; 
						if($c1 < 128) { 
							$json .= ($c1 > 31) ? $char : sprintf("\\u%04x", $c1); 
							continue; 
						} 
						
						# Double byte 
						$c2 = ord($string[++$i]); 
						if (($c1 & 32) === 0) { 
							$json .= sprintf("\\u%04x", ($c1 - 192) * 64 + $c2 - 128); 
							continue; 
						} 
						
						# Triple 
						$c3 = ord($string[++$i]); 
						
						if (($c1 & 16) === 0) { 
							$json .= sprintf("\\u%04x", (($c1 - 224) <<12) + (($c2 - 128) << 6) + ($c3 - 128)); 
							continue; 
						} 
							
						# Quadruple 
						$c4 = ord($string[++$i]); 
						
						if (($c1 & 8 ) === 0) { 
							$u = (($c1 & 15) << 2) + (($c2>>4) & 3) - 1; 
						
							$w1 = (54<<10) + ($u<<6) + (($c2 & 15) << 2) + (($c3>>4) & 3); 
							$w2 = (55<<10) + (($c3 & 15)<<6) + ($c4-128); 
							$json .= sprintf("\\u%04x\\u%04x", $w1, $w2); 
						} 
					} 				
				
      				return $json;
				case 'array':
					if (empty($data) || array_keys($data) === range(0, sizeof($data) - 1)) {
						$output = array();
						
						foreach ($data as $value) {
							$output[] = Json::encode($value);
						}
						
						return '[' . implode(',', $output) . ']';
					}
    			case 'object':
      				$output = array();
      				
					foreach ($data as $key => $value) {
        				$output[] = Json::encode(strval($key)) . ':' . Json::encode($value);
					}
					
					return '{' . implode(',', $output) . '}';
				default:
					return 'null';
			}
		}
	}
	
	static public function decode($json, $assoc = false) {
		if (function_exists('json_decode')) {
			return json_decode($json, true);
		} else {
			$match = '/".*?(?<!\\\\)"/';

			$string = preg_replace($match, '', $json);
			$string = preg_replace('/[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]/', '', $string);

			if ($string != '') {
				return null;
			}

			$s2m = array();
			$m2s = array();

			preg_match_all($match, $json, $m);
			
			foreach ($m[0] as $s) {
				$hash = '"' . md5($s) . '"';
				$s2m[$s] = $hash;
				$m2s[$hash] = str_replace('$', '\$', $s);
			}

			$json = strtr($json, $s2m);

			$a = ($assoc) ? '' : '(object) ';
			
			$data = array(
				':' => '=>', 
				'[' => 'array(', 
				'{' => "{$a}array(", 
				']' => ')', 
				'}' => ')'
			);
			
			$json = strtr($json, $data);
  
  			$json = preg_replace('~([\s\(,>])(-?)0~', '$1$2', $json);
  
 			$json = strtr($json, $m2s);

  			$function = @create_function('', "return {$json};");
  			$return = ($function) ? $function() : null;

  			unset($s2m); 
			unset($m2s); 
			unset($function);

  			return $return;
		}
	}
}
?>