Explorer
home
/
zoteqbgb
/
public_html
/
vendor
/
colinodell
/
json5
/
src
Location:
/home/zoteqbgb/public_html/vendor/colinodell/json5/src
Root path:
/home/zoteqbgb/public_html/config/676626
Editing: Json5Decoder.php
<?php /* * This file is part of the colinodell/json5 package. * * (c) Colin O'Dell <colinodell@gmail.com> * * Based on the official JSON5 implementation for JavaScript (https://github.com/json5/json5) * - (c) 2012-2016 Aseem Kishore and others (https://github.com/json5/json5/contributors) * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace ColinODell\Json5; final class Json5Decoder { private $json; private $length; private $at = 0; private $currentByte; private $lineNumber = 1; private $associative; private $maxDepth; private $castBigIntToString; private $depth = 1; private $currentLineStartsAt = 0; /** * Private constructor. */ private function __construct(string $json, bool $associative = false, int $depth = 512, bool $castBigIntToString = false) { $this->json = $json; $this->associative = $associative; $this->maxDepth = $depth; $this->castBigIntToString = $castBigIntToString; $this->length = \strlen($json); $this->currentByte = $this->getByte(0); } /** * Takes a JSON encoded string and converts it into a PHP variable. * * The parameters exactly match PHP's json_decode() function - see * http://php.net/manual/en/function.json-decode.php for more information. * * @param string $source The JSON string being decoded. * @param bool $associative When TRUE, returned objects will be converted into associative arrays. * @param int $depth User specified recursion depth. * @param int $options Bitmask of JSON decode options. * * @throws SyntaxError if the JSON encoded string could not be parsed. * * @return mixed */ public static function decode(string $source, ?bool $associative = false, int $depth = 512, int $options = 0) { // Try parsing with json_decode first, since that's much faster // We only attempt this on PHP 7+ because 5.x doesn't parse some edge cases correctly if (PHP_VERSION_ID >= 70000) { try { $result = \json_decode($source, $associative, $depth, $options); if (\json_last_error() === \JSON_ERROR_NONE) { return $result; } } catch (\Throwable $e) { // ignore exception, continue parsing as JSON5 } } // Fall back to JSON5 if that fails $associative = $associative === true || ($associative === null && $options & \JSON_OBJECT_AS_ARRAY); $castBigIntToString = $options & \JSON_BIGINT_AS_STRING; $decoder = new self($source, $associative, $depth, $castBigIntToString); $result = $decoder->value(); $decoder->white(); if ($decoder->currentByte) { $decoder->throwSyntaxError('Syntax error'); } return $result; } private function getByte(int $at): ?string { if ($at >= $this->length) { return null; } return $this->json[$at]; } private function currentChar(): ?string { if ($this->at >= $this->length) { return null; } return \mb_substr(\substr($this->json, $this->at, 4), 0, 1); } /** * Parse the next character. */ private function next(): ?string { // Get the next character. When there are no more characters, // return the empty string. if ($this->currentByte === "\n" || ($this->currentByte === "\r" && $this->peek() !== "\n")) { $this->lineNumber++; $this->currentLineStartsAt = $this->at + 1; } $this->at++; return $this->currentByte = $this->getByte($this->at); } /** * Parse the next character if it matches $c or fail. */ private function nextOrFail(string $c): ?string { if ($c !== $this->currentByte) { $this->throwSyntaxError(\sprintf( 'Expected %s instead of %s', self::renderChar($c), self::renderChar($this->currentChar()) )); } return $this->next(); } /** * Get the next character without consuming it or * assigning it to the ch variable. */ private function peek(): ?string { return $this->getByte($this->at + 1); } /** * Attempt to match a regular expression at the current position on the current line. * * This function will not match across multiple lines. */ private function match(string $regex): ?string { $subject = \substr($this->json, $this->at); // Only match on the current line if ($pos = \strpos($subject, "\n")) { $subject = \substr($subject, 0, $pos); } if (!\preg_match($regex, $subject, $matches, PREG_OFFSET_CAPTURE)) { return null; } $this->at += $matches[0][1] + \strlen($matches[0][0]); $this->currentByte = $this->getByte($this->at); return $matches[0][0]; } /** * Parse an identifier. * * Normally, reserved words are disallowed here, but we * only use this for unquoted object keys, where reserved words are allowed, * so we don't check for those here. References: * - http://es5.github.com/#x7.6 * - https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/Core_Language_Features#Variables * - http://docstore.mik.ua/orelly/webprog/jscript/ch02_07.htm */ private function identifier(): string { // @codingStandardsIgnoreStart // Be careful when editing this regex, there are a couple Unicode characters in between here -------------vv $match = $this->match('/^(?:[\$_\p{L}\p{Nl}]|\\\\u[0-9A-Fa-f]{4})(?:[\$_\p{L}\p{Nl}\p{Mn}\p{Mc}\p{Nd}\p{Pc}]|\\\\u[0-9A-Fa-f]{4})*/u'); // @codingStandardsIgnoreEnd if ($match === null) { $this->throwSyntaxError('Bad identifier as unquoted key'); } // Un-escape escaped Unicode chars $unescaped = \preg_replace_callback('/(?:\\\\u[0-9A-Fa-f]{4})+/', function ($m) { return \json_decode('"'.$m[0].'"'); }, $match); return $unescaped; } /** * @return int|float|string */ private function number() { $number = null; $sign = ''; $string = ''; $base = 10; if ($this->currentByte === '-' || $this->currentByte === '+') { $sign = $this->currentByte; $this->next(); } // support for Infinity if ($this->currentByte === 'I') { $this->word(); return ($sign === '-') ? -INF : INF; } // support for NaN if ($this->currentByte === 'N') { $number = $this->word(); // ignore sign as -NaN also is NaN return $number; } if ($this->currentByte === '0') { $string .= $this->currentByte; $this->next(); if ($this->currentByte === 'x' || $this->currentByte === 'X') { $string .= $this->currentByte; $this->next(); $base = 16; } elseif (\is_numeric($this->currentByte)) { $this->throwSyntaxError('Octal literal'); } } switch ($base) { case 10: // @codingStandardsIgnoreStart if ((\is_numeric($this->currentByte) || $this->currentByte === '.') && ($match = $this->match('/^\d*\.?\d*/')) !== null) { $string .= $match; } if (($this->currentByte === 'E' || $this->currentByte === 'e') && ($match = $this->match('/^[Ee][-+]?\d*/')) !== null) { $string .= $match; } // @codingStandardsIgnoreEnd $number = $string; break; case 16: if (($match = $this->match('/^[A-Fa-f0-9]+/')) !== null) { $string .= $match; $number = \hexdec($string); break; } $this->throwSyntaxError('Bad hex number'); } if ($sign === '-') { $number = '-' . $number; } if (!\is_numeric($number) || !\is_finite($number)) { $this->throwSyntaxError('Bad number'); } // Adding 0 will automatically cast this to an int or float $asIntOrFloat = $number + 0; $isIntLike = preg_match('/^-?\d+$/', $number) === 1; if ($this->castBigIntToString && $isIntLike && is_float($asIntOrFloat)) { return $number; } return $asIntOrFloat; } private function string(): string { $string = ''; $delim = $this->currentByte; $this->next(); while ($this->currentByte !== null) { if ($this->currentByte === $delim) { $this->next(); return $string; } if ($this->currentByte === '\\') { if ($this->peek() === 'u' && $unicodeEscaped = $this->match('/^(?:\\\\u[A-Fa-f0-9]{4})+/')) { try { $unicodeUnescaped = \json_decode('"' . $unicodeEscaped . '"', false, 1, JSON_THROW_ON_ERROR); if ($unicodeUnescaped === null && ($err = json_last_error_msg())) { throw new \JsonException($err); } $string .= $unicodeUnescaped; } catch (\JsonException $e) { $this->throwSyntaxError($e->getMessage()); } continue; } $this->next(); if ($this->currentByte === "\r") { if ($this->peek() === "\n") { $this->next(); } } elseif (($escapee = self::getEscapee($this->currentByte)) !== null) { $string .= $escapee; } else { break; } } elseif ($this->currentByte === "\n") { // unescaped newlines are invalid; see: // https://github.com/json5/json5/issues/24 // @todo this feels special-cased; are there other invalid unescaped chars? break; } else { $string .= $this->currentByte; } $this->next(); } $this->throwSyntaxError('Bad string'); } /** * Skip an inline comment, assuming this is one. * * The current character should be the second / character in the // pair that begins this inline comment. * To finish the inline comment, we look for a newline or the end of the text. */ private function inlineComment(): void { do { $this->next(); if ($this->currentByte === "\n" || $this->currentByte === "\r") { $this->next(); return; } } while ($this->currentByte !== null); } /** * Skip a block comment, assuming this is one. * * The current character should be the * character in the /* pair that begins this block comment. * To finish the block comment, we look for an ending */ pair of characters, * but we also watch for the end of text before the comment is terminated. */ private function blockComment(): void { do { $this->next(); while ($this->currentByte === '*') { $this->nextOrFail('*'); if ($this->currentByte === '/') { $this->nextOrFail('/'); return; } } } while ($this->currentByte !== null); $this->throwSyntaxError('Unterminated block comment'); } /** * Skip a comment, whether inline or block-level, assuming this is one. */ private function comment(): void { // Comments always begin with a / character. $this->nextOrFail('/'); if ($this->currentByte === '/') { $this->inlineComment(); } elseif ($this->currentByte === '*') { $this->blockComment(); } else { $this->throwSyntaxError('Unrecognized comment'); } } /** * Skip whitespace and comments. * * Note that we're detecting comments by only a single / character. * This works since regular expressions are not valid JSON(5), but this will * break if there are other valid values that begin with a / character! */ private function white(): void { while ($this->currentByte !== null) { if ($this->currentByte === '/') { $this->comment(); } elseif (\preg_match('/^[ \t\r\n\v\f\xA0]/', $this->currentByte) === 1) { $this->next(); } elseif (\ord($this->currentByte) === 0xC2 && \ord($this->peek()) === 0xA0) { // Non-breaking space in UTF-8 $this->next(); $this->next(); } else { return; } } } /** * Matches true, false, null, etc * * @return bool|null|float */ private function word() { switch ($this->currentByte) { case 't': $this->nextOrFail('t'); $this->nextOrFail('r'); $this->nextOrFail('u'); $this->nextOrFail('e'); return true; case 'f': $this->nextOrFail('f'); $this->nextOrFail('a'); $this->nextOrFail('l'); $this->nextOrFail('s'); $this->nextOrFail('e'); return false; case 'n': $this->nextOrFail('n'); $this->nextOrFail('u'); $this->nextOrFail('l'); $this->nextOrFail('l'); return null; case 'I': $this->nextOrFail('I'); $this->nextOrFail('n'); $this->nextOrFail('f'); $this->nextOrFail('i'); $this->nextOrFail('n'); $this->nextOrFail('i'); $this->nextOrFail('t'); $this->nextOrFail('y'); return INF; case 'N': $this->nextOrFail('N'); $this->nextOrFail('a'); $this->nextOrFail('N'); return NAN; } $this->throwSyntaxError('Unexpected ' . self::renderChar($this->currentChar())); } private function arr(): array { $arr = []; if (++$this->depth > $this->maxDepth) { $this->throwSyntaxError('Maximum stack depth exceeded'); } $this->nextOrFail('['); $this->white(); while ($this->currentByte !== null) { if ($this->currentByte === ']') { $this->nextOrFail(']'); $this->depth--; return $arr; // Potentially empty array } // ES5 allows omitting elements in arrays, e.g. [,] and // [,null]. We don't allow this in JSON5. if ($this->currentByte === ',') { $this->throwSyntaxError('Missing array element'); } $arr[] = $this->value(); $this->white(); // If there's no comma after this value, this needs to // be the end of the array. if ($this->currentByte !== ',') { $this->nextOrFail(']'); $this->depth--; return $arr; } $this->nextOrFail(','); $this->white(); } $this->throwSyntaxError('Invalid array'); } /** * Parse an object value * * @return array|object */ private function obj() { $object = $this->associative ? [] : new \stdClass; if (++$this->depth > $this->maxDepth) { $this->throwSyntaxError('Maximum stack depth exceeded'); } $this->nextOrFail('{'); $this->white(); while ($this->currentByte !== null) { if ($this->currentByte === '}') { $this->nextOrFail('}'); $this->depth--; return $object; // Potentially empty object } // Keys can be unquoted. If they are, they need to be // valid JS identifiers. if ($this->currentByte === '"' || $this->currentByte === "'") { $key = $this->string(); } else { $key = $this->identifier(); } $this->white(); $this->nextOrFail(':'); if ($this->associative) { $object[$key] = $this->value(); } else { $object->{$key} = $this->value(); } $this->white(); // If there's no comma after this pair, this needs to be // the end of the object. if ($this->currentByte !== ',') { $this->nextOrFail('}'); $this->depth--; return $object; } $this->nextOrFail(','); $this->white(); } $this->throwSyntaxError('Invalid object'); } /** * Parse a JSON value. * * It could be an object, an array, a string, a number, * or a word. * * @return mixed */ private function value() { $this->white(); switch ($this->currentByte) { case '{': return $this->obj(); case '[': return $this->arr(); case '"': case "'": return $this->string(); case '-': case '+': case '.': return $this->number(); default: return \is_numeric($this->currentByte) ? $this->number() : $this->word(); } } /** * @throws SyntaxError * * @phpstan-return never */ private function throwSyntaxError(string $message): void { // Calculate the column number $str = \substr($this->json, $this->currentLineStartsAt, $this->at - $this->currentLineStartsAt); $column = \mb_strlen($str) + 1; throw new SyntaxError($message, $this->lineNumber, $column); } private static function renderChar(?string $chr): string { return $chr === null ? 'EOF' : "'" . $chr . "'"; } private static function getEscapee(string $ch): ?string { switch ($ch) { // @codingStandardsIgnoreStart case "'": return "'"; case '"': return '"'; case '\\': return '\\'; case '/': return '/'; case "\n": return ''; case 'b': return \chr(8); case 'f': return "\f"; case 'n': return "\n"; case 'r': return "\r"; case 't': return "\t"; default: return null; // @codingStandardsIgnoreEnd } } }
Save maftirs
Upload
Start Upload
New File
Create File
New Folder
Create Folder
Directory Contents
Name
Size
Perms
Modified
Actions
Json5Decoder.php
19,526 bytes
0644
2022-12-27 21:44
âï¸
ðï¸
Rename
SyntaxError.php
1,396 bytes
0644
2022-12-27 21:44
âï¸
ðï¸
Rename
global.php
1,180 bytes
0644
2022-12-27 21:44
âï¸
ðï¸
Rename
Chang
Apply