From ff0f833b3e8da0a2737feb0035fb36b7abc5379e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Haso=C5=88?= Date: Wed, 15 Feb 2012 11:59:39 +0100 Subject: [PATCH] Added support for JSON_UNESCAPED_UNICODE and fixed parsing string --- src/Composer/Json/JsonFile.php | 54 +++++++++++++++++------ tests/Composer/Test/Json/JsonFileTest.php | 20 +++++++++ 2 files changed, 60 insertions(+), 14 deletions(-) diff --git a/src/Composer/Json/JsonFile.php b/src/Composer/Json/JsonFile.php index 7d4ab8cb6..ecd286d78 100644 --- a/src/Composer/Json/JsonFile.php +++ b/src/Composer/Json/JsonFile.php @@ -78,8 +78,9 @@ class JsonFile * * @param array $hash writes hash into json file * @param Boolean $prettyPrint If true, output is pretty-printed + * @param Boolean $unescapeUnicode If true, unicode chars in output are unescaped */ - public function write(array $hash, $prettyPrint = true) + public function write(array $hash, $prettyPrint = true, $unescapeUnicode = true) { $dir = dirname($this->path); if (!is_dir($dir)) { @@ -94,7 +95,7 @@ class JsonFile ); } } - file_put_contents($this->path, static::encode($hash, $prettyPrint)); + file_put_contents($this->path, static::encode($hash, $prettyPrint, $unescapeUnicode)); } /** @@ -105,17 +106,23 @@ class JsonFile * * @param array $hash Data to encode into a formatted JSON string * @param Boolean $prettyPrint If true, output is pretty-printed + * @param Boolean $unescapeUnicode If true, unicode chars in output are unescaped * @return string Indented version of the original JSON string */ - static public function encode(array $hash, $prettyPrint = true) + static public function encode(array $hash, $prettyPrint = true, $unescapeUnicode = true) { - if ($prettyPrint && defined('JSON_PRETTY_PRINT')) { - return json_encode($hash, JSON_PRETTY_PRINT); + if (version_compare(PHP_VERSION, '5.4', '>=')) { + $options = $prettyPrint ? JSON_PRETTY_PRINT : 0; + if ($unescapeUnicode) { + $options |= JSON_UNESCAPED_UNICODE; + } + + return json_encode($hash, $options); } $json = json_encode($hash); - if (!$prettyPrint) { + if (!$prettyPrint && !$unescapeUnicode) { return $json; } @@ -124,21 +131,43 @@ class JsonFile $strLen = strlen($json); $indentStr = ' '; $newLine = "\n"; - $prevChar = ''; $outOfQuotes = true; + $buffer = ''; + $noescape = true; for ($i = 0; $i <= $strLen; $i++) { // Grab the next character in the string $char = substr($json, $i, 1); // Are we inside a quoted string? - if ('"' === $char && ('\\' !== $prevChar || '\\\\' === substr($json, $i-2, 2))) { + if ('"' === $char && $noescape) { $outOfQuotes = !$outOfQuotes; - } elseif (':' === $char && $outOfQuotes) { + } + + if (!$outOfQuotes) { + $buffer .= $char; + $noescape = '\\' === $char ? !$noescape : true; + continue; + } elseif ('' !== $buffer) { + if ($unescapeUnicode && function_exists('mb_convert_encoding')) { + // http://stackoverflow.com/questions/2934563/how-to-decode-unicode-escape-sequences-like-u00ed-to-proper-utf-8-encoded-cha + $result .= preg_replace_callback('/\\\\u([0-9a-f]{4})/i', function($match) { + return mb_convert_encoding(pack('H*', $match[1]), 'UTF-8', 'UCS-2BE'); + }, $buffer.$char); + } else { + $result .= $buffer.$char; + } + + $buffer = ''; + continue; + } + + if (':' === $char) { // Add a space after the : character $char .= ' '; - } elseif (('}' === $char || ']' === $char) && $outOfQuotes) { + } elseif (('}' === $char || ']' === $char)) { $pos--; + $prevChar = substr($json, $i - 1, 1); if ('{' !== $prevChar && '[' !== $prevChar) { // If this character is the end of an element, @@ -153,12 +182,11 @@ class JsonFile } } - // Add the character to the result string $result .= $char; // If the last character was the beginning of an element, // output a new line and indent the next line - if ((',' === $char || '{' === $char || '[' === $char) && $outOfQuotes) { + if (',' === $char || '{' === $char || '[' === $char) { $result .= $newLine; if ('{' === $char || '[' === $char) { @@ -169,8 +197,6 @@ class JsonFile $result .= $indentStr; } } - - $prevChar = $char; } return $result; diff --git a/tests/Composer/Test/Json/JsonFileTest.php b/tests/Composer/Test/Json/JsonFileTest.php index 4ebf7b0c5..4ed016fa6 100644 --- a/tests/Composer/Test/Json/JsonFileTest.php +++ b/tests/Composer/Test/Json/JsonFileTest.php @@ -121,6 +121,26 @@ class JsonFileTest extends \PHPUnit_Framework_TestCase $this->assertJsonFormat($json, $data); } + public function testEscape() + { + $data = array("Metadata\\\"" => 'src/'); + $json = '{ + "Metadata\\\\\\"": "src\/" +}'; + + $this->assertJsonFormat($json, $data); + } + + public function testUnicode() + { + $data = array("Žluťoučký \" kůň" => "úpěl ďábelské ódy za €"); + $json = '{ + "Žluťoučký \" kůň": "úpěl ďábelské ódy za €" +}'; + + $this->assertJsonFormat($json, $data); + } + private function expectParseException($text, $json) { try {