From f3c38700f57ed5b72ee9e2e0983f6dc19f55c708 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Sun, 14 May 2017 20:48:58 +0100 Subject: [PATCH 1/9] Removed options for disabling assertion exceptions --- src/pocketmine/Server.php | 2 +- src/pocketmine/resources/pocketmine.yml | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/pocketmine/Server.php b/src/pocketmine/Server.php index 4af97a252..da78efb94 100644 --- a/src/pocketmine/Server.php +++ b/src/pocketmine/Server.php @@ -1506,7 +1506,7 @@ class Server{ $this->logger->warning("Debugging assertions are enabled, this may impact on performance. To disable them, set `zend.assertions = -1` in php.ini."); } - ini_set('assert.exception', (bool) $this->getProperty("debug.assertions.throw-exception", 0)); + ini_set('assert.exception', '1'); if($this->logger instanceof MainLogger){ $this->logger->setLogDebug(\pocketmine\DEBUG > 1); diff --git a/src/pocketmine/resources/pocketmine.yml b/src/pocketmine/resources/pocketmine.yml index 8efe10809..5fa080618 100644 --- a/src/pocketmine/resources/pocketmine.yml +++ b/src/pocketmine/resources/pocketmine.yml @@ -88,9 +88,6 @@ debug: assertions: #Warn if assertions are enabled in php.ini, due to assertions may impact on runtime performance if enabled. warn-if-enabled: true - #Enable throwing exceptions when assertions fail, will allow obtaining more detailed information on the failed assertion, but may cause a server crash. - #If set to false, a warning will be raised instead of throwing an exception. - throw-exception: false #If > 1, it will show debug messages in the console level: 1 #Enables /status, /gc From f6c0ba9846426cedf2ab219f8adc3b95a3637667 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 19 May 2017 18:30:32 +0100 Subject: [PATCH 2/9] Cleaned up some duplicated code in NBT parser --- src/pocketmine/nbt/NBT.php | 187 +++++++++-------------------- src/pocketmine/nbt/tag/ListTag.php | 62 +--------- 2 files changed, 59 insertions(+), 190 deletions(-) diff --git a/src/pocketmine/nbt/NBT.php b/src/pocketmine/nbt/NBT.php index f929f58e3..a3cd0df12 100644 --- a/src/pocketmine/nbt/NBT.php +++ b/src/pocketmine/nbt/NBT.php @@ -71,6 +71,42 @@ class NBT{ public $endianness; private $data; + /** + * @param int $type + * + * @return Tag + */ + public static function createTag(int $type){ + switch($type){ + case self::TAG_End: + return new EndTag(); + case self::TAG_Byte: + return new ByteTag(); + case self::TAG_Short: + return new ShortTag(); + case self::TAG_Int: + return new IntTag(); + case self::TAG_Long: + return new LongTag(); + case self::TAG_Float: + return new FloatTag(); + case self::TAG_Double: + return new DoubleTag(); + case self::TAG_ByteArray: + return new ByteArrayTag(); + case self::TAG_String: + return new StringTag(); + case self::TAG_List: + return new ListTag(); + case self::TAG_Compound: + return new CompoundTag(); + case self::TAG_IntArray: + return new IntArrayTag(); + default: + throw new \InvalidArgumentException("Unknown NBT tag type $type"); + } + } + public static function matchList(ListTag $tag1, ListTag $tag2){ if($tag1->getName() !== $tag2->getName() or $tag1->getCount() !== $tag2->getCount()){ return false; @@ -170,40 +206,11 @@ class NBT{ $value = self::readValue($str, $offset, $type); - switch($type){ - case NBT::TAG_Byte: - $data[$key] = new ByteTag($key, $value); - break; - case NBT::TAG_Short: - $data[$key] = new ShortTag($key, $value); - break; - case NBT::TAG_Int: - $data[$key] = new IntTag($key, $value); - break; - case NBT::TAG_Long: - $data[$key] = new LongTag($key, $value); - break; - case NBT::TAG_Float: - $data[$key] = new FloatTag($key, $value); - break; - case NBT::TAG_Double: - $data[$key] = new DoubleTag($key, $value); - break; - case NBT::TAG_ByteArray: - $data[$key] = new ByteArrayTag($key, $value); - break; - case NBT::TAG_String: - $data[$key] = new StringTag($key, $value); - break; - case NBT::TAG_List: - $data[$key] = new ListTag($key, $value); - break; - case NBT::TAG_Compound: - $data[$key] = new CompoundTag($key, $value); - break; - case NBT::TAG_IntArray: - $data[$key] = new IntArrayTag($key, $value); - break; + $tag = self::createTag($type); + if($tag instanceof NamedTag){ + $tag->setName($key); + $tag->setValue($value); + $data[$key] = $tag; } $key++; @@ -228,40 +235,11 @@ class NBT{ $key = self::readKey($str, $offset); $value = self::readValue($str, $offset, $type); - switch($type){ - case NBT::TAG_Byte: - $data[$key] = new ByteTag($key, $value); - break; - case NBT::TAG_Short: - $data[$key] = new ShortTag($key, $value); - break; - case NBT::TAG_Int: - $data[$key] = new IntTag($key, $value); - break; - case NBT::TAG_Long: - $data[$key] = new LongTag($key, $value); - break; - case NBT::TAG_Float: - $data[$key] = new FloatTag($key, $value); - break; - case NBT::TAG_Double: - $data[$key] = new DoubleTag($key, $value); - break; - case NBT::TAG_ByteArray: - $data[$key] = new ByteArrayTag($key, $value); - break; - case NBT::TAG_String: - $data[$key] = new StringTag($key, $value); - break; - case NBT::TAG_List: - $data[$key] = new ListTag($key, $value); - break; - case NBT::TAG_Compound: - $data[$key] = new CompoundTag($key, $value); - break; - case NBT::TAG_IntArray: - $data[$key] = new IntArrayTag($key, $value); - break; + $tag = self::createTag($type); + if($tag instanceof NamedTag){ + $tag->setName($key); + $tag->setValue($value); + $data[$key] = $tag; } } @@ -427,11 +405,6 @@ class NBT{ $this->read(zlib_decode($buffer)); } - public function readNetworkCompressed($buffer){ - $this->read(zlib_decode($buffer), false, true); - } - - /** * @param bool $network * @@ -463,71 +436,19 @@ class NBT{ return false; } - public function writeNetworkCompressed($compression = ZLIB_ENCODING_GZIP, $level = 7){ - if(($write = $this->write(true)) !== false){ - return zlib_encode($write, $compression, $level); - } - - return false; - } - public function readTag(bool $network = false){ if($this->feof()){ - $tagType = -1; //prevent crashes for empty tags - }else{ - $tagType = $this->getByte(); + return new EndTag(); } - switch($tagType){ - case NBT::TAG_Byte: - $tag = new ByteTag($this->getString($network)); - $tag->read($this, $network); - break; - case NBT::TAG_Short: - $tag = new ShortTag($this->getString($network)); - $tag->read($this, $network); - break; - case NBT::TAG_Int: - $tag = new IntTag($this->getString($network)); - $tag->read($this, $network); - break; - case NBT::TAG_Long: - $tag = new LongTag($this->getString($network)); - $tag->read($this, $network); - break; - case NBT::TAG_Float: - $tag = new FloatTag($this->getString($network)); - $tag->read($this, $network); - break; - case NBT::TAG_Double: - $tag = new DoubleTag($this->getString($network)); - $tag->read($this, $network); - break; - case NBT::TAG_ByteArray: - $tag = new ByteArrayTag($this->getString($network)); - $tag->read($this, $network); - break; - case NBT::TAG_String: - $tag = new StringTag($this->getString($network)); - $tag->read($this, $network); - break; - case NBT::TAG_List: - $tag = new ListTag($this->getString($network)); - $tag->read($this, $network); - break; - case NBT::TAG_Compound: - $tag = new CompoundTag($this->getString($network)); - $tag->read($this, $network); - break; - case NBT::TAG_IntArray: - $tag = new IntArrayTag($this->getString($network)); - $tag->read($this, $network); - break; - case NBT::TAG_End: //No named tag - default: - $tag = new EndTag; - break; + $tagType = $this->getByte(); + $tag = self::createTag($tagType); + + if($tag instanceof NamedTag){ + $tag->setName($this->getString($network)); + $tag->read($this, $network); } + return $tag; } diff --git a/src/pocketmine/nbt/tag/ListTag.php b/src/pocketmine/nbt/tag/ListTag.php index 361db14d6..821744c61 100644 --- a/src/pocketmine/nbt/tag/ListTag.php +++ b/src/pocketmine/nbt/tag/ListTag.php @@ -118,64 +118,12 @@ class ListTag extends NamedTag implements \ArrayAccess, \Countable{ $this->value = []; $this->tagType = $nbt->getByte(); $size = $nbt->getInt($network); + + $tagBase = NBT::createTag($this->tagType); for($i = 0; $i < $size and !$nbt->feof(); ++$i){ - switch($this->tagType){ - case NBT::TAG_Byte: - $tag = new ByteTag(""); - $tag->read($nbt, $network); - $this->{$i} = $tag; - break; - case NBT::TAG_Short: - $tag = new ShortTag(""); - $tag->read($nbt, $network); - $this->{$i} = $tag; - break; - case NBT::TAG_Int: - $tag = new IntTag(""); - $tag->read($nbt, $network); - $this->{$i} = $tag; - break; - case NBT::TAG_Long: - $tag = new LongTag(""); - $tag->read($nbt, $network); - $this->{$i} = $tag; - break; - case NBT::TAG_Float: - $tag = new FloatTag(""); - $tag->read($nbt, $network); - $this->{$i} = $tag; - break; - case NBT::TAG_Double: - $tag = new DoubleTag(""); - $tag->read($nbt, $network); - $this->{$i} = $tag; - break; - case NBT::TAG_ByteArray: - $tag = new ByteArrayTag(""); - $tag->read($nbt, $network); - $this->{$i} = $tag; - break; - case NBT::TAG_String: - $tag = new StringTag(""); - $tag->read($nbt, $network); - $this->{$i} = $tag; - break; - case NBT::TAG_List: - $tag = new TagEnum(""); - $tag->read($nbt, $network); - $this->{$i} = $tag; - break; - case NBT::TAG_Compound: - $tag = new CompoundTag(""); - $tag->read($nbt, $network); - $this->{$i} = $tag; - break; - case NBT::TAG_IntArray: - $tag = new IntArrayTag(""); - $tag->read($nbt, $network); - $this->{$i} = $tag; - break; - } + $tag = clone $tagBase; + $tag->read($nbt, $network); + $this->{$i} = $tag; } } From d4cc7d13cd33568c881ab7bca18f2267cbde5542 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 19 May 2017 19:11:36 +0100 Subject: [PATCH 3/9] Fixed setValue() being useless for CompoundTags and ListTags --- src/pocketmine/nbt/tag/CompoundTag.php | 10 ++++++++++ src/pocketmine/nbt/tag/ListTag.php | 10 ++++++++++ 2 files changed, 20 insertions(+) diff --git a/src/pocketmine/nbt/tag/CompoundTag.php b/src/pocketmine/nbt/tag/CompoundTag.php index 45ab5bf6d..0448f0580 100644 --- a/src/pocketmine/nbt/tag/CompoundTag.php +++ b/src/pocketmine/nbt/tag/CompoundTag.php @@ -49,6 +49,16 @@ class CompoundTag extends NamedTag implements \ArrayAccess{ return $count; } + public function setValue($value){ + if(is_array($value)){ + foreach($value as $name => $tag){ + if($tag instanceof NamedTag){ + $this->{$name} = $tag; + } + } + } + } + public function offsetExists($offset){ return isset($this->{$offset}) and $this->{$offset} instanceof Tag; } diff --git a/src/pocketmine/nbt/tag/ListTag.php b/src/pocketmine/nbt/tag/ListTag.php index 821744c61..6c8e70a68 100644 --- a/src/pocketmine/nbt/tag/ListTag.php +++ b/src/pocketmine/nbt/tag/ListTag.php @@ -48,6 +48,16 @@ class ListTag extends NamedTag implements \ArrayAccess, \Countable{ return $value; } + public function setValue($value){ + if(is_array($value)){ + foreach($value as $name => $tag){ + if($tag instanceof NamedTag){ + $this->{$name} = $tag; + } + } + } + } + public function getCount(){ $count = 0; foreach($this as $tag){ From 2e480b5ea1ee8d0959efc7818bc24a531d04cb2a Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 19 May 2017 19:15:08 +0100 Subject: [PATCH 4/9] Fixed broken logic for recursive counts of ListTag --- src/pocketmine/nbt/tag/ListTag.php | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/pocketmine/nbt/tag/ListTag.php b/src/pocketmine/nbt/tag/ListTag.php index 6c8e70a68..e02835611 100644 --- a/src/pocketmine/nbt/tag/ListTag.php +++ b/src/pocketmine/nbt/tag/ListTag.php @@ -98,18 +98,16 @@ class ListTag extends NamedTag implements \ArrayAccess, \Countable{ } public function count($mode = COUNT_NORMAL){ - for($i = 0; true; $i++){ - if(!isset($this->{$i})){ - return $i; - } - if($mode === COUNT_RECURSIVE){ - if($this->{$i} instanceof \Countable){ - $i += count($this->{$i}); - } + $count = 0; + for($i = 0; isset($this->{$i}); $i++){ + if($mode === COUNT_RECURSIVE and $this->{$i} instanceof \Countable){ + $count += count($this->{$i}); + }else{ + $count++; } } - return $i; + return $count; } public function getType(){ From afd90adb1ccbbf7b43e35098e45816a75b466c00 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 19 May 2017 20:02:43 +0100 Subject: [PATCH 5/9] Refactored JSON-parsing NBT utilities into their own class --- .../command/defaults/GiveCommand.php | 4 +- src/pocketmine/nbt/JsonNBTParser.php | 259 ++++++++++++++++++ src/pocketmine/nbt/NBT.php | 193 ------------- 3 files changed, 261 insertions(+), 195 deletions(-) create mode 100644 src/pocketmine/nbt/JsonNBTParser.php diff --git a/src/pocketmine/command/defaults/GiveCommand.php b/src/pocketmine/command/defaults/GiveCommand.php index f26f8b688..a8bcb84e2 100644 --- a/src/pocketmine/command/defaults/GiveCommand.php +++ b/src/pocketmine/command/defaults/GiveCommand.php @@ -25,7 +25,7 @@ use pocketmine\command\Command; use pocketmine\command\CommandSender; use pocketmine\event\TranslationContainer; use pocketmine\item\Item; -use pocketmine\nbt\NBT; +use pocketmine\nbt\JsonNBTParser; use pocketmine\nbt\tag\CompoundTag; use pocketmine\Player; use pocketmine\utils\TextFormat; @@ -65,7 +65,7 @@ class GiveCommand extends VanillaCommand{ $tags = $exception = null; $data = implode(" ", array_slice($args, 3)); try{ - $tags = NBT::parseJSON($data); + $tags = JsonNBTParser::parseJSON($data); }catch(\Throwable $ex){ $exception = $ex; } diff --git a/src/pocketmine/nbt/JsonNBTParser.php b/src/pocketmine/nbt/JsonNBTParser.php new file mode 100644 index 000000000..f8c8d6a2b --- /dev/null +++ b/src/pocketmine/nbt/JsonNBTParser.php @@ -0,0 +1,259 @@ +setName($key); + $tag->setValue($value); + $data[$key] = $tag; + } + + $key++; + } + + return $data; + } + + /** + * @param string $str + * @param int $offset + * + * @return NamedTag[] + */ + private static function parseCompound(string $str, int &$offset = 0) : array{ + $len = strlen($str); + + $data = []; + + for(; $offset < $len; ++$offset){ + if($str{$offset - 1} === "}"){ + break; + }elseif($str{$offset} === "}"){ + ++$offset; + break; + } + + $key = self::readKey($str, $offset); + $value = self::readValue($str, $offset, $type); + + $tag = NBT::createTag($type); + if($tag instanceof NamedTag){ + $tag->setName($key); + $tag->setValue($value); + $data[$key] = $tag; + } + } + + return $data; + } + + /** + * @param string $data + * @param int $offset + * @param int|null $type + * + * @return mixed + * @throws \Exception + */ + private static function readValue(string $data, int &$offset, &$type = null){ + $value = ""; + $type = null; + $inQuotes = false; + + $len = strlen($data); + for(; $offset < $len; ++$offset){ + $c = $data{$offset}; + + if(!$inQuotes and ($c === " " or $c === "\r" or $c === "\n" or $c === "\t" or $c === "," or $c === "}" or $c === "]")){ + if($c === "," or $c === "}" or $c === "]"){ + break; + } + }elseif($c === '"'){ + $inQuotes = !$inQuotes; + if($type === null){ + $type = NBT::TAG_String; + }elseif($inQuotes){ + throw new \Exception("Syntax error: invalid quote at offset $offset"); + } + }elseif($c === "\\"){ + $value .= $data{$offset + 1} ?? ""; + ++$offset; + }elseif($c === "{" and !$inQuotes){ + if($value !== ""){ + throw new \Exception("Syntax error: invalid compound start at offset $offset"); + } + ++$offset; + $value = self::parseCompound($data, $offset); + $type = NBT::TAG_Compound; + break; + }elseif($c === "[" and !$inQuotes){ + if($value !== ""){ + throw new \Exception("Syntax error: invalid list start at offset $offset"); + } + ++$offset; + $value = self::parseList($data, $offset); + $type = NBT::TAG_List; + break; + }else{ + $value .= $c; + } + } + + if($value === ""){ + throw new \Exception("Syntax error: invalid empty value at offset $offset"); + } + + if($type === null and strlen($value) > 0){ + $value = trim($value); + $last = strtolower(substr($value, -1)); + $part = substr($value, 0, -1); + + if($last !== "b" and $last !== "s" and $last !== "l" and $last !== "f" and $last !== "d"){ + $part = $value; + $last = null; + } + + if($last !== "f" and $last !== "d" and ((string) ((int) $part)) === $part){ + if($last === "b"){ + $type = NBT::TAG_Byte; + }elseif($last === "s"){ + $type = NBT::TAG_Short; + }elseif($last === "l"){ + $type = NBT::TAG_Long; + }else{ + $type = NBT::TAG_Int; + } + $value = (int) $part; + }elseif(is_numeric($part)){ + if($last === "f" or $last === "d" or strpos($part, ".") !== false){ + if($last === "f"){ + $type = NBT::TAG_Float; + }elseif($last === "d"){ + $type = NBT::TAG_Double; + }else{ + $type = NBT::TAG_Float; + } + $value = (float) $part; + }else{ + if($last === "l"){ + $type = NBT::TAG_Long; + }else{ + $type = NBT::TAG_Int; + } + + $value = $part; + } + }else{ + $type = NBT::TAG_String; + } + } + + return $value; + } + + /** + * @param string $data + * @param int $offset + * + * @return string + * @throws \Exception + */ + private static function readKey(string $data, int &$offset){ + $key = ""; + + $len = strlen($data); + for(; $offset < $len; ++$offset){ + $c = $data{$offset}; + + if($c === ":"){ + ++$offset; + break; + }elseif($c !== " " and $c !== "\r" and $c !== "\n" and $c !== "\t" and $c !== "\""){ + $key .= $c; + } + } + + if($key === ""){ + throw new \Exception("Syntax error: invalid empty key at offset $offset"); + } + + return $key; + } +} \ No newline at end of file diff --git a/src/pocketmine/nbt/NBT.php b/src/pocketmine/nbt/NBT.php index a3cd0df12..b3380c8e4 100644 --- a/src/pocketmine/nbt/NBT.php +++ b/src/pocketmine/nbt/NBT.php @@ -171,199 +171,6 @@ class NBT{ return true; } - public static function parseJSON($data, &$offset = 0){ - $len = strlen($data); - for(; $offset < $len; ++$offset){ - $c = $data{$offset}; - if($c === "{"){ - ++$offset; - $data = self::parseCompound($data, $offset); - return new CompoundTag("", $data); - }elseif($c !== " " and $c !== "\r" and $c !== "\n" and $c !== "\t"){ - throw new \Exception("Syntax error: unexpected '$c' at offset $offset"); - } - } - - return null; - } - - private static function parseList($str, &$offset = 0){ - $len = strlen($str); - - - $key = 0; - $value = null; - - $data = []; - - for(; $offset < $len; ++$offset){ - if($str{$offset - 1} === "]"){ - break; - }elseif($str{$offset} === "]"){ - ++$offset; - break; - } - - $value = self::readValue($str, $offset, $type); - - $tag = self::createTag($type); - if($tag instanceof NamedTag){ - $tag->setName($key); - $tag->setValue($value); - $data[$key] = $tag; - } - - $key++; - } - - return $data; - } - - private static function parseCompound($str, &$offset = 0){ - $len = strlen($str); - - $data = []; - - for(; $offset < $len; ++$offset){ - if($str{$offset - 1} === "}"){ - break; - }elseif($str{$offset} === "}"){ - ++$offset; - break; - } - - $key = self::readKey($str, $offset); - $value = self::readValue($str, $offset, $type); - - $tag = self::createTag($type); - if($tag instanceof NamedTag){ - $tag->setName($key); - $tag->setValue($value); - $data[$key] = $tag; - } - } - - return $data; - } - - private static function readValue($data, &$offset, &$type = null){ - $value = ""; - $type = null; - $inQuotes = false; - - $len = strlen($data); - for(; $offset < $len; ++$offset){ - $c = $data{$offset}; - - if(!$inQuotes and ($c === " " or $c === "\r" or $c === "\n" or $c === "\t" or $c === "," or $c === "}" or $c === "]")){ - if($c === "," or $c === "}" or $c === "]"){ - break; - } - }elseif($c === '"'){ - $inQuotes = !$inQuotes; - if($type === null){ - $type = self::TAG_String; - }elseif($inQuotes){ - throw new \Exception("Syntax error: invalid quote at offset $offset"); - } - }elseif($c === "\\"){ - $value .= $data{$offset + 1} ?? ""; - ++$offset; - }elseif($c === "{" and !$inQuotes){ - if($value !== ""){ - throw new \Exception("Syntax error: invalid compound start at offset $offset"); - } - ++$offset; - $value = self::parseCompound($data, $offset); - $type = self::TAG_Compound; - break; - }elseif($c === "[" and !$inQuotes){ - if($value !== ""){ - throw new \Exception("Syntax error: invalid list start at offset $offset"); - } - ++$offset; - $value = self::parseList($data, $offset); - $type = self::TAG_List; - break; - }else{ - $value .= $c; - } - } - - if($value === ""){ - throw new \Exception("Syntax error: invalid empty value at offset $offset"); - } - - if($type === null and strlen($value) > 0){ - $value = trim($value); - $last = strtolower(substr($value, -1)); - $part = substr($value, 0, -1); - - if($last !== "b" and $last !== "s" and $last !== "l" and $last !== "f" and $last !== "d"){ - $part = $value; - $last = null; - } - - if($last !== "f" and $last !== "d" and ((string) ((int) $part)) === $part){ - if($last === "b"){ - $type = self::TAG_Byte; - }elseif($last === "s"){ - $type = self::TAG_Short; - }elseif($last === "l"){ - $type = self::TAG_Long; - }else{ - $type = self::TAG_Int; - } - $value = (int) $part; - }elseif(is_numeric($part)){ - if($last === "f" or $last === "d" or strpos($part, ".") !== false){ - if($last === "f"){ - $type = self::TAG_Float; - }elseif($last === "d"){ - $type = self::TAG_Double; - }else{ - $type = self::TAG_Float; - } - $value = (float) $part; - }else{ - if($last === "l"){ - $type = self::TAG_Long; - }else{ - $type = self::TAG_Int; - } - - $value = $part; - } - }else{ - $type = self::TAG_String; - } - } - - return $value; - } - - private static function readKey($data, &$offset){ - $key = ""; - - $len = strlen($data); - for(; $offset < $len; ++$offset){ - $c = $data{$offset}; - - if($c === ":"){ - ++$offset; - break; - }elseif($c !== " " and $c !== "\r" and $c !== "\n" and $c !== "\t" and $c !== "\""){ - $key .= $c; - } - } - - if($key === ""){ - throw new \Exception("Syntax error: invalid empty key at offset $offset"); - } - - return $key; - } - public function get($len){ if($len < 0){ $this->offset = strlen($this->buffer) - 1; From a77c1ce13c5ef279b5131b68d92e9b3340554fbf Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Fri, 19 May 2017 20:03:11 +0100 Subject: [PATCH 6/9] remove leftover --- src/pocketmine/nbt/tag/ListTag.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pocketmine/nbt/tag/ListTag.php b/src/pocketmine/nbt/tag/ListTag.php index e02835611..405402eae 100644 --- a/src/pocketmine/nbt/tag/ListTag.php +++ b/src/pocketmine/nbt/tag/ListTag.php @@ -22,7 +22,6 @@ namespace pocketmine\nbt\tag; use pocketmine\nbt\NBT; -use pocketmine\nbt\tag\ListTag as TagEnum; #include From 86f3b257a72afa819a99628d95368d0bf83ef2e9 Mon Sep 17 00:00:00 2001 From: Muqsit Rayyan Date: Tue, 30 May 2017 15:27:47 +0300 Subject: [PATCH 7/9] Remove unneeded foreach loop in Human::getDrops() (#941) * Remove unneeded foreach loop in Human::getDrops() * Use array_values() for backwards compatibility. --- src/pocketmine/entity/Human.php | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/pocketmine/entity/Human.php b/src/pocketmine/entity/Human.php index 9797ead87..51ab0e819 100644 --- a/src/pocketmine/entity/Human.php +++ b/src/pocketmine/entity/Human.php @@ -425,14 +425,7 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{ } public function getDrops(){ - $drops = []; - if($this->inventory !== null){ - foreach($this->inventory->getContents() as $item){ - $drops[] = $item; - } - } - - return $drops; + return $this->inventory !== null ? array_values($this->inventory->getContents()) : []; } public function saveNBT(){ From caced595d21dc526d1c78c0ab84117be174c755e Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 30 May 2017 14:15:20 +0100 Subject: [PATCH 8/9] Fixed server crash on startup on 32-bit with memory limit set >= 4096MB --- src/pocketmine/MemoryManager.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/pocketmine/MemoryManager.php b/src/pocketmine/MemoryManager.php index 8b291dd9c..a3111af69 100644 --- a/src/pocketmine/MemoryManager.php +++ b/src/pocketmine/MemoryManager.php @@ -89,6 +89,11 @@ class MemoryManager{ $hardLimit = ((int) $this->server->getProperty("memory.main-hard-limit", $defaultMemory)); + if(PHP_INT_SIZE === 4 and $hardLimit >= 4096){ + $this->server->getLogger()->warning("Cannot set memory limit higher than 4GB on 32-bit, defaulting to max 4095MB"); + $hardLimit = 4095; + } + if($hardLimit <= 0){ ini_set("memory_limit", -1); }else{ From db3cd1829ceccb483603335c6c2ebe32b3a82a01 Mon Sep 17 00:00:00 2001 From: "Dylan K. Taylor" Date: Tue, 30 May 2017 14:19:34 +0100 Subject: [PATCH 9/9] Made Binary::readVarInt/VarLong methods less useless --- src/pocketmine/nbt/NBT.php | 4 +- src/pocketmine/utils/Binary.php | 66 ++++++++++++++++----------- src/pocketmine/utils/BinaryStream.php | 8 ++-- 3 files changed, 46 insertions(+), 32 deletions(-) diff --git a/src/pocketmine/nbt/NBT.php b/src/pocketmine/nbt/NBT.php index b3380c8e4..1c238adc5 100644 --- a/src/pocketmine/nbt/NBT.php +++ b/src/pocketmine/nbt/NBT.php @@ -285,7 +285,7 @@ class NBT{ public function getInt(bool $network = false){ if($network === true){ - return Binary::readVarInt($this); + return Binary::readVarInt($this->buffer, $this->offset); } return $this->endianness === self::BIG_ENDIAN ? Binary::readInt($this->get(4)) : Binary::readLInt($this->get(4)); } @@ -323,7 +323,7 @@ class NBT{ } public function getString(bool $network = false){ - $len = $network ? Binary::readUnsignedVarInt($this) : $this->getShort(); + $len = $network ? Binary::readUnsignedVarInt($this->buffer, $this->offset) : $this->getShort(); return $this->get($len); } diff --git a/src/pocketmine/utils/Binary.php b/src/pocketmine/utils/Binary.php index 60099b7c4..922c6c582 100644 --- a/src/pocketmine/utils/Binary.php +++ b/src/pocketmine/utils/Binary.php @@ -341,13 +341,14 @@ class Binary{ /** * Reads a 32-bit zigzag-encoded variable-length integer from the supplied stream. * - * @param \pocketmine\nbt\NBT|BinaryStream $stream + * @param string $buffer + * @param int &$offset * * @return int */ - public static function readVarInt($stream){ + public static function readVarInt(string $buffer, int &$offset){ $shift = PHP_INT_SIZE === 8 ? 63 : 31; - $raw = self::readUnsignedVarInt($stream); + $raw = self::readUnsignedVarInt($buffer, $offset); $temp = ((($raw << $shift) >> $shift) ^ $raw) >> 1; return $temp ^ ($raw & (1 << $shift)); } @@ -355,18 +356,21 @@ class Binary{ /** * Reads a 32-bit variable-length unsigned integer from the supplied stream. * - * @param \pocketmine\nbt\NBT|BinaryStream $stream + * @param string $buffer + * @param int &$offset * * @return int */ - public static function readUnsignedVarInt($stream){ + public static function readUnsignedVarInt(string $buffer, int &$offset){ $value = 0; for($i = 0; $i <= 35; $i += 7){ - $b = $stream->getByte(); + $b = ord($buffer{$offset++}); $value |= (($b & 0x7f) << $i); if(($b & 0x80) === 0){ return $value; + }elseif(!isset($buffer{$offset})){ + throw new \UnexpectedValueException("Expected more bytes, none left to read"); } } @@ -414,27 +418,29 @@ class Binary{ /** * Reads a 64-bit zigzag-encoded variable-length integer from the supplied stream. - * @param \pocketmine\nbt\NBT|BinaryStream $stream + * @param string $buffer + * @param int &$offset * * @return int|string */ - public static function readVarLong($stream){ + public static function readVarLong(string $buffer, int &$offset){ if(PHP_INT_SIZE === 8){ - return self::readVarLong_64($stream); + return self::readVarLong_64($buffer, $offset); }else{ - return self::readVarLong_32($stream); + return self::readVarLong_32($buffer, $offset); } } /** * Legacy BC Math zigzag VarLong reader. Will work on 32-bit or 64-bit, but will be slower than the regular 64-bit method. - * @param \pocketmine\nbt\NBT|BinaryStream $stream + * @param string $buffer + * @param int &$offset * * @return string */ - public static function readVarLong_32($stream){ + public static function readVarLong_32(string $buffer, int &$offset){ /** @var string $raw */ - $raw = self::readUnsignedVarLong_32($stream); + $raw = self::readUnsignedVarLong_32($buffer, $offset); $result = bcdiv($raw, "2"); if(bcmod($raw, "2") === "1"){ $result = bcsub(bcmul($result, "-1"), "1"); @@ -445,44 +451,49 @@ class Binary{ /** * 64-bit zizgag VarLong reader. - * @param \pocketmine\nbt\NBT|BinaryStream $stream + * @param string $buffer + * @param int &$offset * * @return int */ - public static function readVarLong_64($stream){ - $raw = self::readUnsignedVarLong_64($stream); + public static function readVarLong_64(string $buffer, int &$offset){ + $raw = self::readUnsignedVarLong_64($buffer, $offset); $temp = ((($raw << 63) >> 63) ^ $raw) >> 1; return $temp ^ ($raw & (1 << 63)); } /** * Reads an unsigned VarLong from the supplied stream. - * @param \pocketmine\nbt\NBT|BinaryStream $stream + * @param string $buffer + * @param int &$offset * * @return int|string */ - public static function readUnsignedVarLong($stream){ + public static function readUnsignedVarLong(string $buffer, int &$offset){ if(PHP_INT_SIZE === 8){ - return self::readUnsignedVarLong_64($stream); + return self::readUnsignedVarLong_64($buffer, $offset); }else{ - return self::readUnsignedVarLong_32($stream); + return self::readUnsignedVarLong_32($buffer, $offset); } } /** * Legacy BC Math unsigned VarLong reader. - * @param \pocketmine\nbt\NBT|BinaryStream $stream + * @param string $buffer + * @param int &$offset * * @return string */ - public static function readUnsignedVarLong_32($stream){ + public static function readUnsignedVarLong_32(string $buffer, int &$offset){ $value = "0"; for($i = 0; $i <= 63; $i += 7){ - $b = $stream->getByte(); + $b = ord($buffer{$offset++}); $value = bcadd($value, bcmul($b & 0x7f, bcpow("2", "$i"))); if(($b & 0x80) === 0){ return $value; + }elseif(!isset($buffer{$offset})){ + throw new \UnexpectedValueException("Expected more bytes, none left to read"); } } @@ -491,18 +502,21 @@ class Binary{ /** * 64-bit unsigned VarLong reader. - * @param \pocketmine\nbt\NBT|BinaryStream $stream + * @param string $buffer + * @param int &$offset * * @return int */ - public static function readUnsignedVarLong_64($stream){ + public static function readUnsignedVarLong_64(string $buffer, int &$offset){ $value = 0; for($i = 0; $i <= 63; $i += 7){ - $b = $stream->getByte(); + $b = ord($buffer{$offset++}); $value |= (($b & 0x7f) << $i); if(($b & 0x80) === 0){ return $value; + }elseif(!isset($buffer{$offset})){ + throw new \UnexpectedValueException("Expected more bytes, none left to read"); } } diff --git a/src/pocketmine/utils/BinaryStream.php b/src/pocketmine/utils/BinaryStream.php index 5fc671f4b..849054310 100644 --- a/src/pocketmine/utils/BinaryStream.php +++ b/src/pocketmine/utils/BinaryStream.php @@ -246,7 +246,7 @@ class BinaryStream extends \stdClass{ * @return int */ public function getUnsignedVarInt(){ - return Binary::readUnsignedVarInt($this); + return Binary::readUnsignedVarInt($this->buffer, $this->offset); } /** @@ -262,7 +262,7 @@ class BinaryStream extends \stdClass{ * @return int */ public function getVarInt(){ - return Binary::readVarInt($this); + return Binary::readVarInt($this->buffer, $this->offset); } /** @@ -278,7 +278,7 @@ class BinaryStream extends \stdClass{ * @return int|string int, or the string representation of an int64 on 32-bit platforms */ public function getUnsignedVarLong(){ - return Binary::readUnsignedVarLong($this); + return Binary::readUnsignedVarLong($this->buffer, $this->offset); } /** @@ -294,7 +294,7 @@ class BinaryStream extends \stdClass{ * @return int|string int, or the string representation of an int64 on 32-bit platforms */ public function getVarLong(){ - return Binary::readVarLong($this); + return Binary::readVarLong($this->buffer, $this->offset); } /**