diff --git a/src/pocketmine/command/Command.php b/src/pocketmine/command/Command.php index 0e949f3f4..2f47e2029 100644 --- a/src/pocketmine/command/Command.php +++ b/src/pocketmine/command/Command.php @@ -26,6 +26,7 @@ declare(strict_types=1); */ namespace pocketmine\command; +use pocketmine\command\utils\CommandException; use pocketmine\lang\TextContainer; use pocketmine\lang\TranslationContainer; use pocketmine\permission\PermissionManager; @@ -92,6 +93,7 @@ abstract class Command{ * @param string[] $args * * @return mixed + * @throws CommandException */ abstract public function execute(CommandSender $sender, string $commandLabel, array $args); diff --git a/src/pocketmine/command/SimpleCommandMap.php b/src/pocketmine/command/SimpleCommandMap.php index 88d95a5ba..d7296f82f 100644 --- a/src/pocketmine/command/SimpleCommandMap.php +++ b/src/pocketmine/command/SimpleCommandMap.php @@ -66,13 +66,13 @@ use pocketmine\command\defaults\VersionCommand; use pocketmine\command\defaults\WhitelistCommand; use pocketmine\command\utils\InvalidCommandSyntaxException; use pocketmine\Server; -use function array_map; use function array_shift; use function count; use function explode; use function implode; use function min; -use function str_getcsv; +use function preg_match_all; +use function stripslashes; use function strpos; use function strtolower; use function trim; @@ -247,7 +247,16 @@ class SimpleCommandMap implements CommandMap{ } public function dispatch(CommandSender $sender, string $commandLine) : bool{ - $args = array_map("\stripslashes", str_getcsv($commandLine, " ")); + $args = []; + preg_match_all('/"((?:\\\\.|[^\\\\"])*)"|(\S+)/u', $commandLine, $matches); + foreach($matches[0] as $k => $_){ + for($i = 1; $i <= 2; ++$i){ + if($matches[$i][$k] !== ""){ + $args[$k] = stripslashes($matches[$i][$k]); + break; + } + } + } $sentCommandLabel = ""; $target = $this->matchCommand($sentCommandLabel, $args); diff --git a/src/pocketmine/entity/Human.php b/src/pocketmine/entity/Human.php index ee02412cb..d24b4f536 100644 --- a/src/pocketmine/entity/Human.php +++ b/src/pocketmine/entity/Human.php @@ -301,7 +301,7 @@ class Human extends Creature implements ProjectileSource, InventoryHolder{ $food = $this->getFood(); if($food > 0){ $food--; - $this->setFood($food); + $this->setFood(max($food, 0)); } } } diff --git a/src/pocketmine/tile/Sign.php b/src/pocketmine/tile/Sign.php index ca577ad93..39b3b550b 100644 --- a/src/pocketmine/tile/Sign.php +++ b/src/pocketmine/tile/Sign.php @@ -33,6 +33,8 @@ use function array_pad; use function array_slice; use function explode; use function implode; +use function mb_check_encoding; +use function mb_scrub; use function sprintf; class Sign extends Spawnable{ @@ -57,6 +59,9 @@ class Sign extends Spawnable{ } } } + $this->text = array_map(function(string $line) : string{ + return mb_scrub($line, 'UTF-8'); + }, $this->text); } protected function writeSaveData(CompoundTag $nbt) : void{ @@ -79,16 +84,16 @@ class Sign extends Spawnable{ */ public function setText(?string $line1 = "", ?string $line2 = "", ?string $line3 = "", ?string $line4 = "") : void{ if($line1 !== null){ - $this->text[0] = $line1; + $this->setLine(0, $line1, false); } if($line2 !== null){ - $this->text[1] = $line2; + $this->setLine(1, $line2, false); } if($line3 !== null){ - $this->text[2] = $line3; + $this->setLine(2, $line3, false); } if($line4 !== null){ - $this->text[3] = $line4; + $this->setLine(3, $line4, false); } $this->onChanged(); @@ -103,6 +108,9 @@ class Sign extends Spawnable{ if($index < 0 or $index > 3){ throw new \InvalidArgumentException("Index must be in the range 0-3!"); } + if(!mb_check_encoding($line, 'UTF-8')){ + throw new \InvalidArgumentException("Text must be valid UTF-8"); + } $this->text[$index] = $line; if($update){ diff --git a/src/pocketmine/utils/TextFormat.php b/src/pocketmine/utils/TextFormat.php index 40d236347..7d5b028ac 100644 --- a/src/pocketmine/utils/TextFormat.php +++ b/src/pocketmine/utils/TextFormat.php @@ -25,6 +25,7 @@ namespace pocketmine\utils; use function is_array; use function json_encode; +use function mb_scrub; use function preg_quote; use function preg_replace; use function preg_split; @@ -77,18 +78,19 @@ abstract class TextFormat{ } /** - * Cleans the string from Minecraft codes and ANSI Escape Codes + * Cleans the string from Minecraft codes, ANSI Escape Codes and invalid UTF-8 characters * * @param string $string * @param bool $removeFormat * - * @return string + * @return string valid clean UTF-8 */ public static function clean(string $string, bool $removeFormat = true) : string{ + $string = mb_scrub($string, 'UTF-8'); if($removeFormat){ - return str_replace(TextFormat::ESCAPE, "", preg_replace(["/" . TextFormat::ESCAPE . "[0-9a-fk-or]/", "/\x1b[\\(\\][[0-9;\\[\\(]+[Bm]/"], "", $string)); + return str_replace(TextFormat::ESCAPE, "", preg_replace(["/" . TextFormat::ESCAPE . "[0-9a-fk-or]/u", "/\x1b[\\(\\][[0-9;\\[\\(]+[Bm]/u"], "", $string)); } - return str_replace("\x1b", "", preg_replace("/\x1b[\\(\\][[0-9;\\[\\(]+[Bm]/", "", $string)); + return str_replace("\x1b", "", preg_replace("/\x1b[\\(\\][[0-9;\\[\\(]+[Bm]/u", "", $string)); } /**