File: D:/HostingSpaces/EvLuik/vanluiktegelwerken.nl/wwwroot/plugins/hi_updatecheck/JSON.php
<?php
/**
* Handle encoding and decoding of JSON from resp. to native PHP data structures.
*
* @package CMB
* @copyright Copyright (c) 2012-2013 Christoph M. Becker <http://3-magi.net/>
* @license http://www.gnu.org/licenses/gpl-3.0.en.html GNU GPLv3
* @version $Id: JSON.php 252 2014-10-16 16:56:25Z hi $
*/
/**
* End of string has been reached.
*
* @access private
*/
define('CMB_JSON_EOS', -1);
/**
* Unknown terminal symbol.
*
* @access private
*/
define('CMB_JSON_UNKNOWN', 0);
/**
* <kbd>NUMBER</kbd>
*
* @access private
*/
define('CMB_JSON_NUMBER', 1);
/**
* <kbd>STRING</kbd>
*
* @access private
*/
define('CMB_JSON_STRING', 2);
/**
* <kbd>LBRACE</kbd>
*
* @access private
*/
define('CMB_JSON_LBRACE', 3);
/**
* <kbd>RBRACE</kbd>
*
* @access private
*/
define('CMB_JSON_RBRACE', 4);
/**
* <kbd>LBRACK</kbd>
*
* @access private
*/
define('CMB_JSON_LBRACK', 5);
/**
* <kbd>RBRACK</kbd>
*
* @access private
*/
define('CMB_JSON_RBRACK', 6);
/**
* <kbd>COMMA</kbd>
*
* @access private
*/
define('CMB_JSON_COMMA', 7);
/**
* <kbd>COLON</kbd>
* @access private
*/
define('CMB_JSON_COLON', 8);
/**
* <kdb>TRUE</kbd>
*
* @access private
*/
define('CMB_JSON_TRUE', 9);
/**
* <kbd>FALSE</kbd>
*
* @access private
*/
define('CMB_JSON_FALSE', 10);
/**
* <kbd>NULL</kbd>
*
* @access private
*/
define('CMB_JSON_NULL', 11);
/**
* Handles encoding and decoding of JSON from resp. to native PHP data structures.
*
* It is a <i>simplified</i> alternative to <kbd>json_encode()</kbd> and <kbd>json_decode()</kbd>
* that can be used as fallback for ancient PHP versions.
*
* @package CMB
*/
class CMB_JSON
{
/**
* The set of "first" tokens.
*
* @access private
*
* @var array
*/
var $first;
/**
* The string to parse.
*
* Already parsed parts will be truncated.
*
* @access private
*
* @var string
*/
var $str;
/**
* The current token.
*
* @access private
*
* @var int
*/
var $sym;
/**
* The current value (for strings and numbers).
*
* @access private
*
* @var mixed
*/
var $value;
/**
* Error flag.
*
* @access private
*
* @var bool
*/
var $error;
/**
* Constructor.
*
* @access private
*/
function CMB_JSON()
{
$this->first = array(
'object' => array(CMB_JSON_LBRACE),
'pair' => array(CMB_JSON_STRING),
'array' => array(CMB_JSON_LBRACK),
'value' => array(CMB_JSON_STRING, CMB_JSON_NUMBER,
CMB_JSON_LBRACE, CMB_JSON_LBRACK,
CMB_JSON_TRUE, CMB_JSON_FALSE,
CMB_JSON_NULL));
}
/**
* Quotes a string for use as JSON string.
*
* @access private
*
* @param string $string
* @return string
*/
function quote($string)
{
$string = addcslashes($string, "\"\\");
$string = preg_replace('/[\x00-\x1f]/s', '\u00$1', $string);
return $string;
}
/**
* Returns UTF-8 chars for JSON unicode escape sequence.
*
* Ignores BOM and illegal surrogates.
*
* @access private
*
* @param array $matches
* @return string
*/
function unescape($matches)
{
$n = hexdec($matches[1]);
if ($n >= 0 && $n <= 0x007f) {
return chr($n);
} elseif ($n <= 0x07ff) {
return chr(0xc0 | ($n >> 6))
. chr(0x80 | ($n & 0x003f));
} elseif($n == 0xfeff) {
return ''; // skip BOM
} elseif ($n >= 0xd800 && $n <= 0xdfff) {
// TODO: what to do here?
return '';
} else {
return chr(0xe0 | ($n >> 12))
. chr(0x80 | (($n >> 6) & 0x003f))
. chr(0x80 | ($n & 0x003f));
}
}
/**
* Scans the next token and sets $this->sym accordingly.
*
* @access private
*
* @return void
*/
function getSym()
{
$this->str = preg_replace('/^\s*/', '', $this->str); // TODO: all UTF-8 whitespace
if (empty($this->str)) {
$this->sym = CMB_JSON_EOS;
return;
}
switch ($this->str{0}) {
case '-': case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
preg_match('/-?(?:0|[1-9][0-9]*(?:\.[0-9]+)?(?:[eE][-+]?[0-9]+)?)/',
$this->str, $m);
$i = intval($m[0]);
$this->value = $i == $m[0] ? $i : floatval($m[0]);
$this->str = substr($this->str, strlen($m[0]));
$this->sym = CMB_JSON_NUMBER;
break;
case '"':
preg_match('/^"((?:[^"\\\\]|[\\\\](?:["\\\\\/bfnrt]|u[0-9a-fA-F]{4}))*)/',
$this->str, $m);
$m[1] = preg_replace_callback('/\\\\u([0-9a-fA-F]{4})/',
array($this, 'unescape'),
$m[1]);
$this->value = stripcslashes($m[1]);
$this->str = substr($this->str, strlen($m[0]) + 1);
$this->sym = CMB_JSON_STRING;
break;
case '{':
$this->str = substr($this->str, 1);
$this->sym = CMB_JSON_LBRACE;
break;
case '}':
$this->str = substr($this->str, 1);
$this->sym = CMB_JSON_RBRACE;
break;
case '[':
$this->str = substr($this->str, 1);
$this->sym = CMB_JSON_LBRACK;
break;
case ']':
$this->str = substr($this->str, 1);
$this->sym = CMB_JSON_RBRACK;
break;
case ',':
$this->str = substr($this->str, 1);
$this->sym = CMB_JSON_COMMA;
break;
case ':':
$this->str = substr($this->str, 1);
$this->sym = CMB_JSON_COLON;
break;
case 't':
if (strpos($this->str, 'true') === 0) {
$this->str = substr($this->str, 4);
$this->sym = CMB_JSON_TRUE;
} else {
$this->sym = CMB_JSON_UNKNOWN;
}
break;
case 'f':
if (strpos($this->str, 'false') === 0) {
$this->str = substr($this->str, 5);
$this->sym = CMB_JSON_FALSE;
} else {
$this->sym = CMB_JSON_UNKNOWN;
}
break;
case 'n':
if (strpos($this->str, 'null') === 0) {
$this->str = substr($this->str, 4);
$this->sym = CMB_JSON_NULL;
} else {
$this->sym = CMB_JSON_UNKNOWN;
}
break;
default:
$this->sym = CMB_JSON_UNKNOWN;
}
}
/**
* Expect and consume a terminal symbol.
*
* Set <var>$error</var> to true, if symbol was not found.
*
* @access private
*
* @param string $terminal
* @return void
*/
function accept($terminal)
{
if ($this->sym != $terminal) {
$this->error = true;
}
$this->getSym();
}
/**
* Parse an object.
*
* <samp>object -> LBRACE [ pair { COMMA pair ] RBRACE</samp>
*
* @access private
*
* @param object &$res
* @return void
*/
function parseObject(&$res)
{
$this->accept(CMB_JSON_LBRACE);
$res = array();
if (in_array($this->sym, $this->first['pair'])) {
$this->parsePair($key, $val);
$res[$key]= $val;
while ($this->sym == CMB_JSON_COMMA) {
$this->accept(CMB_JSON_COMMA);
$this->parsePair($key, $val);
$res[$key] = $val;
}
}
$this->accept(CMB_JSON_RBRACE);
}
/**
* Parse a pair.
*
* <samp>pair -> STRING COLON value</samp>
*
* @access private
*
* @param string &$key
* @param mixed &$val
* @return void
*/
function parsePair(&$key, &$val)
{
$this->accept(CMB_JSON_STRING);
$key = $this->value;
$this->accept(CMB_JSON_COLON);
$this->parseValue($val);
}
/**
* Parse an array.
*
* <samp>array -> LBRACK [ value { COMMA value } ] RBRACK</samp>
*
* @access private
*
* @param array &$res
* @return void
*/
function parseArray(&$res)
{
$this->accept(CMB_JSON_LBRACK);
$res = array();
if (in_array($this->sym, $this->first['value'])) {
$this->parseValue($res1);
$res[] = $res1;
while ($this->sym == CMB_JSON_COMMA) {
$this->accept(CMB_JSON_COMMA);
$this->parseValue($res1);
$res[] = $res1;
}
}
$this->accept(CMB_JSON_RBRACK);
}
/**
* Parse a value.
*
* <samp>value -> STRING | NUMBER | object | array | TRUE | FALSE | NULL</samp>
*
* @access private
*
* @param mixed &$res
* @return void
*/
function parseValue(&$res)
{
switch ($this->sym) {
case CMB_JSON_STRING:
$res = $this->value;
$this->getSym();
break;
case CMB_JSON_NUMBER:
$res = $this->value;
$this->getSym();
break;
case CMB_JSON_LBRACE:
$this->parseObject($res);
break;
case CMB_JSON_LBRACK:
$this->parseArray($res);
break;
case CMB_JSON_TRUE:
$res = true;
$this->getSym();
break;
case CMB_JSON_FALSE:
$res = false;
$this->getSym();
break;
case CMB_JSON_NULL:
$res = null;
$this->getSym();
break;
}
}
/**
* Returns a PHP value encoded as JSON string.
*
* <kbd>encode($value)</kbd> should be equivalent to
* <kbd>json_encode($value, JSON_UNESCAPED_SLASHES
* | JSON_UNESCAPED_UNICODE)</kbd>.
*
* @access public
*
* @param mixed $value
* @return string
*/
function encode($value)
{
switch (gettype($value)) {
case 'boolean':
return $value ? 'true' : 'false';
case 'integer':
case 'double':
return $value;
case 'string':
return '"' . $this->quote($value) . '"';
case 'array':
if (array_keys($value) === range(0, count($value) - 1)) {
// encode as array
$elts = array();
foreach ($value as $val) {
$elts[] = $this->encode($val);
}
return '[' . implode(',', $elts) . ']';
} else {
// encode as object
$members = array();
foreach ($value as $key => $val) {
$members[] = '"' . $this->quote($key) . '":'
. $this->encode($val);
}
return '{' . implode(',', $members) . '}';
}
case 'object':
return $this->encode(get_object_vars($value));
case 'NULL':
return 'null';
default:
$msg = __FUNCTION__ . '(): type is unsupported, encoded as null';
trigger_error($msg, E_USER_WARNING);
return 'null';
}
}
/**
* Returns the JSON string decoded as PHP value.
*
* <kbd>decode($string)</kbd> should be equivalent to
* <kbd>json_decode($string, true)</kbd> for valid UTF-8.
*
* If the input is erroneous, NULL is returned. To distinguish this from
* a real NULL value, use {@link CMB_JSON::lastError()}.
*
* @access public
*
* @param string $string
* @return mixed
*/
function decode($string)
{
$this->str = $string;
$this->sym = $this->value = null;
$this->error = false;
$this->getSym();
$this->parseValue($res);
return $this->error ? null : $res;
}
/**
* Returns whether an error has occurred during the last {@link CMB_JSON::decode()}.
*
* @access public
*
* @return bool
*/
function lastError()
{
return $this->error;
}
/**
* Returns the unique instance of the class.
*
* @access public
*
* @return object
*/
function instance()
{
static $instance;
if (!isset($instance)) {
$instance = new CMB_JSON();
}
return $instance;
}
}
?>