55            if(($b = $stream->get(1)) !== 
"{"){
 
   56                throw new NbtDataException(
"Syntax error: expected compound start but got '$b'");
 
   58            $ret = self::parseCompound($stream); 
 
   60            throw new NbtDataException($e->getMessage() . 
" at offset " . $stream->getOffset());
 
   61        }
catch(BinaryDataException $e){
 
   62            throw new NbtDataException(
"Syntax error: " . $e->getMessage() . 
" at offset " . $stream->getOffset());
 
   65            throw new NbtDataException(
"Syntax error: unexpected trailing characters after end of tag: " . $stream->getRemaining());
 
 
   75    private static function parseList(BinaryStream $stream) : ListTag{
 
   76        $retval = new ListTag();
 
   78        if(self::skipWhitespace($stream, 
"]")){
 
   79            while(!$stream->feof()){
 
   81                    $value = self::readValue($stream);
 
   82                }
catch(InvalidTagValueException $e){
 
   83                    throw new NbtDataException(
"Data error: " . $e->getMessage());
 
   85                $expectedType = $retval->getTagType();
 
   86                if($expectedType !== NBT::TAG_End && $expectedType !== $value->getType()){
 
   87                    throw new NbtDataException(
"Data error: lists can only contain one type of value");
 
   89                $retval->push($value);
 
   90                if(self::readBreak($stream, 
"]")){
 
   95            throw new NbtDataException(
"Syntax error: unexpected end of stream");
 
  105    private static function parseCompound(BinaryStream $stream) : CompoundTag{
 
  106        $retval = new CompoundTag();
 
  108        if(self::skipWhitespace($stream, 
"}")){
 
  109            while(!$stream->feof()){
 
  110                $k = self::readKey($stream);
 
  111                if($retval->getTag($k) !== 
null){
 
  112                    throw new NbtDataException(
"Syntax error: duplicate compound leaf node '$k'");
 
  115                    $retval->setTag($k, self::readValue($stream));
 
  116                }
catch(InvalidTagValueException $e){
 
  117                    throw new NbtDataException(
"Data error: " . $e->getMessage());
 
  120                if(self::readBreak($stream, 
"}")){
 
  125            throw new NbtDataException(
"Syntax error: unexpected end of stream");
 
  135    private static function skipWhitespace(BinaryStream $stream, 
string $terminator) : bool{
 
  136        while(!$stream->feof()){
 
  137            $b = $stream->get(1);
 
  138            if($b === $terminator){
 
  141            if($b === 
" " or $b === 
"\n" or $b === 
"\t" or $b === 
"\r"){
 
  145            $stream->setOffset($stream->getOffset() - 1);
 
  149        throw new NbtDataException(
"Syntax error: unexpected end of stream, expected start of key");
 
  157    private static function readBreak(BinaryStream $stream, 
string $terminator) : bool{
 
  159            throw new NbtDataException(
"Syntax error: unexpected end of stream, expected '$terminator'");
 
  161        $offset = $stream->getOffset();
 
  162        $c = $stream->get(1);
 
  166        if($c === $terminator){
 
  170        throw new NbtDataException(
"Syntax error: unexpected '$c' end at offset $offset");
 
  178    private static function readValue(BinaryStream $stream) : Tag{
 
  182        $offset = $stream->getOffset();
 
  189        while(!$stream->feof()){
 
  190            $offset = $stream->getOffset();
 
  191            $c = $stream->get(1);
 
  196                    $retval = 
new StringTag($value);
 
  198                }elseif($c === 
"\\"){
 
  199                    $value .= $stream->get(1);
 
  204                if($c === 
"," or $c === 
"}" or $c === 
"]"){ 
 
  205                    $stream->setOffset($stream->getOffset() - 1); 
 
  210                if($value === 
"" or $foundEnd){
 
  211                    if($c === 
"\r" or $c === 
"\n" or $c === 
"\t" or $c === 
" "){ 
 
  216                        throw new NbtDataException(
"Syntax error: unexpected '$c' after end of value at offset $offset");
 
  222                        throw new NbtDataException(
"Syntax error: unexpected quote at offset $offset");
 
  228                        throw new NbtDataException(
"Syntax error: unexpected compound start at offset $offset (enclose in double quotes for literal)");
 
  231                    $retval = self::parseCompound($stream);
 
  236                        throw new NbtDataException(
"Syntax error: unexpected list start at offset $offset (enclose in double quotes for literal)");
 
  239                    $retval = self::parseList($stream);
 
  248        if($retval !== 
null){
 
  253            throw new NbtDataException(
"Syntax error: empty value at offset $offset");
 
  256            throw new NbtDataException(
"Syntax error: unexpected end of stream at offset $offset");
 
  259        $last = strtolower(substr($value, -1));
 
  260        $part = substr($value, 0, -1);
 
  262        if($last !== 
"b" and $last !== 
"s" and $last !== 
"l" and $last !== 
"f" and $last !== 
"d"){
 
  267        if(is_numeric($part)){
 
  268            if($last === 
"f" or $last === 
"d" or strpos($part, 
".") !== 
false or strpos($part, 
"e") !== 
false){ 
 
  269                $value = (float) $part;
 
  272                        return new DoubleTag($value);
 
  275                        return new FloatTag($value);
 
  278                $value = (int) $part;
 
  281                        return new ByteTag($value);
 
  283                        return new ShortTag($value);
 
  285                        return new LongTag($value);
 
  287                        return new IntTag($value);
 
  291            return new StringTag($value);
 
  299    private static function readKey(BinaryStream $stream) : string{
 
  301        $offset = $stream->getOffset();
 
  306        while(!$stream->feof()){
 
  307            $c = $stream->get(1);
 
  313                }elseif($c === 
"\\"){
 
  314                    $key .= $stream->get(1);
 
  324                if($key === 
"" or $foundEnd){
 
  325                    if($c === 
"\r" or $c === 
"\n" or $c === 
"\t" or $c === 
" "){ 
 
  330                        throw new NbtDataException(
"Syntax error: unexpected '$c' after end of value at offset $offset");
 
  336                        throw new NbtDataException(
"Syntax error: unexpected quote at offset $offset");
 
  340                }elseif($c === 
"{" or $c === 
"}" or $c === 
"[" or $c === 
"]" or $c === 
","){
 
  341                    throw new NbtDataException(
"Syntax error: unexpected '$c' at offset $offset (enclose in double quotes for literal)");
 
  349            throw new NbtDataException(
"Syntax error: invalid empty key at offset $offset");
 
  352            throw new NbtDataException(
"Syntax error: unexpected end of stream at offset $offset");