From bb88bf3a54dd21bf4dbddb5cd525d7b0c61b7cda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Mirtes?= Date: Fri, 4 Oct 2024 23:18:41 +0200 Subject: [PATCH] Encoder: fixed encoding of control characters [Closes #72] --- src/Neon/Node/StringNode.php | 10 ++++++---- tests/Neon/Encoder.phpt | 10 ++++++++++ 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/Neon/Node/StringNode.php b/src/Neon/Node/StringNode.php index ffee11f6..5de43846 100644 --- a/src/Neon/Node/StringNode.php +++ b/src/Neon/Node/StringNode.php @@ -80,16 +80,18 @@ function (array $m): string { public function toString(): string { if (strpos($this->value, "\n") === false) { - return "'" . str_replace("'", "''", $this->value) . "'"; + return preg_match('~[\x00-\x08\x0B-\x1F]~', $this->value) + ? json_encode($this->value, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) + : "'" . str_replace("'", "''", $this->value) . "'"; - } elseif (preg_match('~\n[\t ]+\'{3}~', $this->value)) { - $s = json_encode($this->value, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); + } elseif (preg_match('~[\x00-\x08\x0B-\x1F]|\n[\t ]+\'{3}~', $this->value)) { + $s = substr(json_encode($this->value, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), 1, -1); $s = preg_replace_callback( '#[^\\\\]|\\\\(.)#s', function ($m) { return ['n' => "\n", 't' => "\t", '"' => '"'][$m[1] ?? ''] ?? $m[0]; }, - substr($s, 1, -1) + $s ); $s = str_replace('"""', '""\"', $s); $delim = '"""'; diff --git a/tests/Neon/Encoder.phpt b/tests/Neon/Encoder.phpt index 8019c0e9..72f2c8d4 100644 --- a/tests/Neon/Encoder.phpt +++ b/tests/Neon/Encoder.phpt @@ -164,3 +164,13 @@ Assert::same( '[]', Neon::encode([], Neon::BLOCK) ); + +Assert::same( + '"special \u0000 chars"', + Neon::encode("special \x00 chars", true) +); + +Assert::same( + "\"\"\"\n\tspecial\\r\n\tchars\n\"\"\"", + Neon::encode("special\r\nchars", true) +);