Chris@0: Chris@0: * Chris@0: * For the full copyright and license information, please view the LICENSE Chris@0: * file that was distributed with this source code. Chris@0: */ Chris@0: Chris@0: namespace Symfony\Component\Yaml; Chris@0: Chris@0: use Symfony\Component\Yaml\Exception\ParseException; Chris@0: Chris@0: /** Chris@0: * Unescaper encapsulates unescaping rules for single and double-quoted Chris@0: * YAML strings. Chris@0: * Chris@0: * @author Matthew Lewinski Chris@0: * Chris@0: * @internal Chris@0: */ Chris@0: class Unescaper Chris@0: { Chris@0: /** Chris@0: * Regex fragment that matches an escaped character in a double quoted string. Chris@0: */ Chris@0: const REGEX_ESCAPED_CHARACTER = '\\\\(x[0-9a-fA-F]{2}|u[0-9a-fA-F]{4}|U[0-9a-fA-F]{8}|.)'; Chris@0: Chris@0: /** Chris@0: * Unescapes a single quoted string. Chris@0: * Chris@0: * @param string $value A single quoted string Chris@0: * Chris@0: * @return string The unescaped string Chris@0: */ Chris@0: public function unescapeSingleQuotedString($value) Chris@0: { Chris@0: return str_replace('\'\'', '\'', $value); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Unescapes a double quoted string. Chris@0: * Chris@0: * @param string $value A double quoted string Chris@0: * Chris@0: * @return string The unescaped string Chris@0: */ Chris@0: public function unescapeDoubleQuotedString($value) Chris@0: { Chris@0: $callback = function ($match) { Chris@0: return $this->unescapeCharacter($match[0]); Chris@0: }; Chris@0: Chris@0: // evaluate the string Chris@0: return preg_replace_callback('/'.self::REGEX_ESCAPED_CHARACTER.'/u', $callback, $value); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Unescapes a character that was found in a double-quoted string. Chris@0: * Chris@0: * @param string $value An escaped character Chris@0: * Chris@0: * @return string The unescaped character Chris@0: */ Chris@0: private function unescapeCharacter($value) Chris@0: { Chris@0: switch ($value[1]) { Chris@0: case '0': Chris@0: return "\x0"; Chris@0: case 'a': Chris@0: return "\x7"; Chris@0: case 'b': Chris@0: return "\x8"; Chris@0: case 't': Chris@0: return "\t"; Chris@0: case "\t": Chris@0: return "\t"; Chris@0: case 'n': Chris@0: return "\n"; Chris@0: case 'v': Chris@0: return "\xB"; Chris@0: case 'f': Chris@0: return "\xC"; Chris@0: case 'r': Chris@0: return "\r"; Chris@0: case 'e': Chris@0: return "\x1B"; Chris@0: case ' ': Chris@0: return ' '; Chris@0: case '"': Chris@0: return '"'; Chris@0: case '/': Chris@0: return '/'; Chris@0: case '\\': Chris@0: return '\\'; Chris@0: case 'N': Chris@0: // U+0085 NEXT LINE Chris@0: return "\xC2\x85"; Chris@0: case '_': Chris@0: // U+00A0 NO-BREAK SPACE Chris@0: return "\xC2\xA0"; Chris@0: case 'L': Chris@0: // U+2028 LINE SEPARATOR Chris@0: return "\xE2\x80\xA8"; Chris@0: case 'P': Chris@0: // U+2029 PARAGRAPH SEPARATOR Chris@0: return "\xE2\x80\xA9"; Chris@0: case 'x': Chris@0: return self::utf8chr(hexdec(substr($value, 2, 2))); Chris@0: case 'u': Chris@0: return self::utf8chr(hexdec(substr($value, 2, 4))); Chris@0: case 'U': Chris@0: return self::utf8chr(hexdec(substr($value, 2, 8))); Chris@0: default: Chris@0: throw new ParseException(sprintf('Found unknown escape character "%s".', $value)); Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * Get the UTF-8 character for the given code point. Chris@0: * Chris@0: * @param int $c The unicode code point Chris@0: * Chris@0: * @return string The corresponding UTF-8 character Chris@0: */ Chris@0: private static function utf8chr($c) Chris@0: { Chris@0: if (0x80 > $c %= 0x200000) { Chris@17: return \chr($c); Chris@0: } Chris@0: if (0x800 > $c) { Chris@17: return \chr(0xC0 | $c >> 6).\chr(0x80 | $c & 0x3F); Chris@0: } Chris@0: if (0x10000 > $c) { Chris@17: return \chr(0xE0 | $c >> 12).\chr(0x80 | $c >> 6 & 0x3F).\chr(0x80 | $c & 0x3F); Chris@0: } Chris@0: Chris@17: return \chr(0xF0 | $c >> 18).\chr(0x80 | $c >> 12 & 0x3F).\chr(0x80 | $c >> 6 & 0x3F).\chr(0x80 | $c & 0x3F); Chris@0: } Chris@0: }