Verzeichnisstruktur phpBB-3.3.16


Veröffentlicht
27.04.2026

So funktioniert es


Auf das letzte Element klicken. Dies geht jeweils ein Schritt zurück

Auf das Icon klicken, dies öffnet das Verzeichnis. Nochmal klicken schließt das Verzeichnis.
Auf den Verzeichnisnamen klicken, dies zeigt nur das Verzeichnis mit Inhalt an

      (Beispiel Datei-Icons)

Auf das Icon klicken um den Quellcode anzuzeigen

Inline.php

Zuletzt modifiziert: 01.05.2026, 11:26 - Dateigröße: 37.78 KiB


 001  <?php
 002   
 003  /*
 004   * This file is part of the Symfony package.
 005   *
 006   * (c) Fabien Potencier <fabien@symfony.com>
 007   *
 008   * For the full copyright and license information, please view the LICENSE
 009   * file that was distributed with this source code.
 010   */
 011   
 012  namespace Symfony\Component\Yaml;
 013   
 014  use Symfony\Component\Yaml\Exception\DumpException;
 015  use Symfony\Component\Yaml\Exception\ParseException;
 016  use Symfony\Component\Yaml\Tag\TaggedValue;
 017   
 018  /**
 019   * Inline implements a YAML parser/dumper for the YAML inline syntax.
 020   *
 021   * @author Fabien Potencier <fabien@symfony.com>
 022   *
 023   * @internal
 024   */
 025  class Inline
 026  {
 027      const REGEX_QUOTED_STRING = '(?:"([^"\\\\]*+(?:\\\\.[^"\\\\]*+)*+)"|\'([^\']*+(?:\'\'[^\']*+)*+)\')';
 028   
 029      public static $parsedLineNumber = -1;
 030      public static $parsedFilename;
 031   
 032      private static $exceptionOnInvalidType = false;
 033      private static $objectSupport = false;
 034      private static $objectForMap = false;
 035      private static $constantSupport = false;
 036   
 037      /**
 038       * @param int         $flags
 039       * @param int|null    $parsedLineNumber
 040       * @param string|null $parsedFilename
 041       */
 042      public static function initialize($flags, $parsedLineNumber = null, $parsedFilename = null)
 043      {
 044          self::$exceptionOnInvalidType = (bool) (Yaml::PARSE_EXCEPTION_ON_INVALID_TYPE & $flags);
 045          self::$objectSupport = (bool) (Yaml::PARSE_OBJECT & $flags);
 046          self::$objectForMap = (bool) (Yaml::PARSE_OBJECT_FOR_MAP & $flags);
 047          self::$constantSupport = (bool) (Yaml::PARSE_CONSTANT & $flags);
 048          self::$parsedFilename = $parsedFilename;
 049   
 050          if (null !== $parsedLineNumber) {
 051              self::$parsedLineNumber = $parsedLineNumber;
 052          }
 053      }
 054   
 055      /**
 056       * Converts a YAML string to a PHP value.
 057       *
 058       * @param string $value      A YAML string
 059       * @param int    $flags      A bit field of PARSE_* constants to customize the YAML parser behavior
 060       * @param array  $references Mapping of variable names to values
 061       *
 062       * @return mixed A PHP value
 063       *
 064       * @throws ParseException
 065       */
 066      public static function parse($value, $flags = 0, $references = [])
 067      {
 068          if (\is_bool($flags)) {
 069              @trigger_error('Passing a boolean flag to toggle exception handling is deprecated since Symfony 3.1 and will be removed in 4.0. Use the Yaml::PARSE_EXCEPTION_ON_INVALID_TYPE flag instead.', \E_USER_DEPRECATED);
 070   
 071              if ($flags) {
 072                  $flags = Yaml::PARSE_EXCEPTION_ON_INVALID_TYPE;
 073              } else {
 074                  $flags = 0;
 075              }
 076          }
 077   
 078          if (\func_num_args() >= 3 && !\is_array($references)) {
 079              @trigger_error('Passing a boolean flag to toggle object support is deprecated since Symfony 3.1 and will be removed in 4.0. Use the Yaml::PARSE_OBJECT flag instead.', \E_USER_DEPRECATED);
 080   
 081              if ($references) {
 082                  $flags |= Yaml::PARSE_OBJECT;
 083              }
 084   
 085              if (\func_num_args() >= 4) {
 086                  @trigger_error('Passing a boolean flag to toggle object for map support is deprecated since Symfony 3.1 and will be removed in 4.0. Use the Yaml::PARSE_OBJECT_FOR_MAP flag instead.', \E_USER_DEPRECATED);
 087   
 088                  if (func_get_arg(3)) {
 089                      $flags |= Yaml::PARSE_OBJECT_FOR_MAP;
 090                  }
 091              }
 092   
 093              if (\func_num_args() >= 5) {
 094                  $references = func_get_arg(4);
 095              } else {
 096                  $references = [];
 097              }
 098          }
 099   
 100          self::initialize($flags);
 101   
 102          $value = trim($value);
 103   
 104          if ('' === $value) {
 105              return '';
 106          }
 107   
 108          if (2 /* MB_OVERLOAD_STRING */ & (int) ini_get('mbstring.func_overload')) {
 109              $mbEncoding = mb_internal_encoding();
 110              mb_internal_encoding('ASCII');
 111          }
 112   
 113          try {
 114              $i = 0;
 115              $tag = self::parseTag($value, $i, $flags);
 116              switch ($value[$i]) {
 117                  case '[':
 118                      $result = self::parseSequence($value, $flags, $i, $references);
 119                      ++$i;
 120                      break;
 121                  case '{':
 122                      $result = self::parseMapping($value, $flags, $i, $references);
 123                      ++$i;
 124                      break;
 125                  default:
 126                      $result = self::parseScalar($value, $flags, null, $i, null === $tag, $references);
 127              }
 128   
 129              // some comments are allowed at the end
 130              if (preg_replace('/\s*#.*$/A', '', substr($value, $i))) {
 131                  throw new ParseException(sprintf('Unexpected characters near "%s".', substr($value, $i)), self::$parsedLineNumber + 1, $value, self::$parsedFilename);
 132              }
 133   
 134              if (null !== $tag) {
 135                  return new TaggedValue($tag, $result);
 136              }
 137   
 138              return $result;
 139          } finally {
 140              if (isset($mbEncoding)) {
 141                  mb_internal_encoding($mbEncoding);
 142              }
 143          }
 144      }
 145   
 146      /**
 147       * Dumps a given PHP variable to a YAML string.
 148       *
 149       * @param mixed $value The PHP variable to convert
 150       * @param int   $flags A bit field of Yaml::DUMP_* constants to customize the dumped YAML string
 151       *
 152       * @return string The YAML string representing the PHP value
 153       *
 154       * @throws DumpException When trying to dump PHP resource
 155       */
 156      public static function dump($value, $flags = 0)
 157      {
 158          if (\is_bool($flags)) {
 159              @trigger_error('Passing a boolean flag to toggle exception handling is deprecated since Symfony 3.1 and will be removed in 4.0. Use the Yaml::DUMP_EXCEPTION_ON_INVALID_TYPE flag instead.', \E_USER_DEPRECATED);
 160   
 161              if ($flags) {
 162                  $flags = Yaml::DUMP_EXCEPTION_ON_INVALID_TYPE;
 163              } else {
 164                  $flags = 0;
 165              }
 166          }
 167   
 168          if (\func_num_args() >= 3) {
 169              @trigger_error('Passing a boolean flag to toggle object support is deprecated since Symfony 3.1 and will be removed in 4.0. Use the Yaml::DUMP_OBJECT flag instead.', \E_USER_DEPRECATED);
 170   
 171              if (func_get_arg(2)) {
 172                  $flags |= Yaml::DUMP_OBJECT;
 173              }
 174          }
 175   
 176          switch (true) {
 177              case \is_resource($value):
 178                  if (Yaml::DUMP_EXCEPTION_ON_INVALID_TYPE & $flags) {
 179                      throw new DumpException(sprintf('Unable to dump PHP resources in a YAML file ("%s").', get_resource_type($value)));
 180                  }
 181   
 182                  return 'null';
 183              case $value instanceof \DateTimeInterface:
 184                  return $value->format('c');
 185              case \is_object($value):
 186                  if ($value instanceof TaggedValue) {
 187                      return '!'.$value->getTag().' '.self::dump($value->getValue(), $flags);
 188                  }
 189   
 190                  if (Yaml::DUMP_OBJECT & $flags) {
 191                      return '!php/object '.self::dump(serialize($value));
 192                  }
 193   
 194                  if (Yaml::DUMP_OBJECT_AS_MAP & $flags && ($value instanceof \stdClass || $value instanceof \ArrayObject)) {
 195                      return self::dumpArray($value, $flags & ~Yaml::DUMP_EMPTY_ARRAY_AS_SEQUENCE);
 196                  }
 197   
 198                  if (Yaml::DUMP_EXCEPTION_ON_INVALID_TYPE & $flags) {
 199                      throw new DumpException('Object support when dumping a YAML file has been disabled.');
 200                  }
 201   
 202                  return 'null';
 203              case \is_array($value):
 204                  return self::dumpArray($value, $flags);
 205              case null === $value:
 206                  return 'null';
 207              case true === $value:
 208                  return 'true';
 209              case false === $value:
 210                  return 'false';
 211              case ctype_digit($value):
 212                  return \is_string($value) ? "'$value'" : (int) $value;
 213              case is_numeric($value) && false === strpos($value, "\f") && false === strpos($value, "\n") && false === strpos($value, "\r") && false === strpos($value, "\t") && false === strpos($value, "\v"):
 214                  $locale = setlocale(\LC_NUMERIC, 0);
 215                  if (false !== $locale) {
 216                      setlocale(\LC_NUMERIC, 'C');
 217                  }
 218                  if (\is_float($value)) {
 219                      $repr = (string) $value;
 220                      if (is_infinite($value)) {
 221                          $repr = str_ireplace('INF', '.Inf', $repr);
 222                      } elseif (floor($value) == $value && $repr == $value) {
 223                          // Preserve float data type since storing a whole number will result in integer value.
 224                          $repr = '!!float '.$repr;
 225                      }
 226                  } else {
 227                      $repr = \is_string($value) ? "'$value'" : (string) $value;
 228                  }
 229                  if (false !== $locale) {
 230                      setlocale(\LC_NUMERIC, $locale);
 231                  }
 232   
 233                  return $repr;
 234              case '' == $value:
 235                  return "''";
 236              case self::isBinaryString($value):
 237                  return '!!binary '.base64_encode($value);
 238              case Escaper::requiresDoubleQuoting($value):
 239                  return Escaper::escapeWithDoubleQuotes($value);
 240              case Escaper::requiresSingleQuoting($value):
 241              case Parser::preg_match('{^[0-9]+[_0-9]*$}', $value):
 242              case Parser::preg_match(self::getHexRegex(), $value):
 243              case Parser::preg_match(self::getTimestampRegex(), $value):
 244                  return Escaper::escapeWithSingleQuotes($value);
 245              default:
 246                  return $value;
 247          }
 248      }
 249   
 250      /**
 251       * Check if given array is hash or just normal indexed array.
 252       *
 253       * @internal
 254       *
 255       * @param array|\ArrayObject|\stdClass $value The PHP array or array-like object to check
 256       *
 257       * @return bool true if value is hash array, false otherwise
 258       */
 259      public static function isHash($value)
 260      {
 261          if ($value instanceof \stdClass || $value instanceof \ArrayObject) {
 262              return true;
 263          }
 264   
 265          $expectedKey = 0;
 266   
 267          foreach ($value as $key => $val) {
 268              if ($key !== $expectedKey++) {
 269                  return true;
 270              }
 271          }
 272   
 273          return false;
 274      }
 275   
 276      /**
 277       * Dumps a PHP array to a YAML string.
 278       *
 279       * @param array $value The PHP array to dump
 280       * @param int   $flags A bit field of Yaml::DUMP_* constants to customize the dumped YAML string
 281       *
 282       * @return string The YAML string representing the PHP array
 283       */
 284      private static function dumpArray($value, $flags)
 285      {
 286          // array
 287          if (($value || Yaml::DUMP_EMPTY_ARRAY_AS_SEQUENCE & $flags) && !self::isHash($value)) {
 288              $output = [];
 289              foreach ($value as $val) {
 290                  $output[] = self::dump($val, $flags);
 291              }
 292   
 293              return sprintf('[%s]', implode(', ', $output));
 294          }
 295   
 296          // hash
 297          $output = [];
 298          foreach ($value as $key => $val) {
 299              $output[] = sprintf('%s: %s', self::dump($key, $flags), self::dump($val, $flags));
 300          }
 301   
 302          return sprintf('{ %s }', implode(', ', $output));
 303      }
 304   
 305      /**
 306       * Parses a YAML scalar.
 307       *
 308       * @param string   $scalar
 309       * @param int      $flags
 310       * @param string[] $delimiters
 311       * @param int      &$i
 312       * @param bool     $evaluate
 313       * @param array    $references
 314       *
 315       * @return string
 316       *
 317       * @throws ParseException When malformed inline YAML string is parsed
 318       *
 319       * @internal
 320       */
 321      public static function parseScalar($scalar, $flags = 0, $delimiters = null, &$i = 0, $evaluate = true, $references = [], $legacyOmittedKeySupport = false)
 322      {
 323          if (\in_array($scalar[$i], ['"', "'"])) {
 324              // quoted scalar
 325              $output = self::parseQuotedScalar($scalar, $i);
 326   
 327              if (null !== $delimiters) {
 328                  $tmp = ltrim(substr($scalar, $i), ' ');
 329                  if ('' === $tmp) {
 330                      throw new ParseException(sprintf('Unexpected end of line, expected one of "%s".', implode('', $delimiters)), self::$parsedLineNumber + 1, $scalar, self::$parsedFilename);
 331                  }
 332                  if (!\in_array($tmp[0], $delimiters)) {
 333                      throw new ParseException(sprintf('Unexpected characters (%s).', substr($scalar, $i)), self::$parsedLineNumber + 1, $scalar, self::$parsedFilename);
 334                  }
 335              }
 336          } else {
 337              // "normal" string
 338              if (!$delimiters) {
 339                  $output = substr($scalar, $i);
 340                  $i += \strlen($output);
 341   
 342                  // remove comments
 343                  if (Parser::preg_match('/[ \t]+#/', $output, $match, \PREG_OFFSET_CAPTURE)) {
 344                      $output = substr($output, 0, $match[0][1]);
 345                  }
 346              } elseif (Parser::preg_match('/^(.'.($legacyOmittedKeySupport ? '+' : '*').'?)('.implode('|', $delimiters).')/', substr($scalar, $i), $match)) {
 347                  $output = $match[1];
 348                  $i += \strlen($output);
 349              } else {
 350                  throw new ParseException(sprintf('Malformed inline YAML string: "%s".', $scalar), self::$parsedLineNumber + 1, null, self::$parsedFilename);
 351              }
 352   
 353              // a non-quoted string cannot start with @ or ` (reserved) nor with a scalar indicator (| or >)
 354              if ($output && ('@' === $output[0] || '`' === $output[0] || '|' === $output[0] || '>' === $output[0])) {
 355                  throw new ParseException(sprintf('The reserved indicator "%s" cannot start a plain scalar; you need to quote the scalar.', $output[0]), self::$parsedLineNumber + 1, $output, self::$parsedFilename);
 356              }
 357   
 358              if ($output && '%' === $output[0]) {
 359                  @trigger_error(self::getDeprecationMessage(sprintf('Not quoting the scalar "%s" starting with the "%%" indicator character is deprecated since Symfony 3.1 and will throw a ParseException in 4.0.', $output)), \E_USER_DEPRECATED);
 360              }
 361   
 362              if ($evaluate) {
 363                  $output = self::evaluateScalar($output, $flags, $references);
 364              }
 365          }
 366   
 367          return $output;
 368      }
 369   
 370      /**
 371       * Parses a YAML quoted scalar.
 372       *
 373       * @param string $scalar
 374       * @param int    &$i
 375       *
 376       * @return string
 377       *
 378       * @throws ParseException When malformed inline YAML string is parsed
 379       */
 380      private static function parseQuotedScalar($scalar, &$i)
 381      {
 382          if (!Parser::preg_match('/'.self::REGEX_QUOTED_STRING.'/Au', substr($scalar, $i), $match)) {
 383              throw new ParseException(sprintf('Malformed inline YAML string: "%s".', substr($scalar, $i)), self::$parsedLineNumber + 1, $scalar, self::$parsedFilename);
 384          }
 385   
 386          $output = substr($match[0], 1, \strlen($match[0]) - 2);
 387   
 388          $unescaper = new Unescaper();
 389          if ('"' == $scalar[$i]) {
 390              $output = $unescaper->unescapeDoubleQuotedString($output);
 391          } else {
 392              $output = $unescaper->unescapeSingleQuotedString($output);
 393          }
 394   
 395          $i += \strlen($match[0]);
 396   
 397          return $output;
 398      }
 399   
 400      /**
 401       * Parses a YAML sequence.
 402       *
 403       * @param string $sequence
 404       * @param int    $flags
 405       * @param int    &$i
 406       * @param array  $references
 407       *
 408       * @return array
 409       *
 410       * @throws ParseException When malformed inline YAML string is parsed
 411       */
 412      private static function parseSequence($sequence, $flags, &$i = 0, $references = [])
 413      {
 414          $output = [];
 415          $len = \strlen($sequence);
 416          ++$i;
 417   
 418          // [foo, bar, ...]
 419          while ($i < $len) {
 420              if (']' === $sequence[$i]) {
 421                  return $output;
 422              }
 423              if (',' === $sequence[$i] || ' ' === $sequence[$i]) {
 424                  ++$i;
 425   
 426                  continue;
 427              }
 428   
 429              $tag = self::parseTag($sequence, $i, $flags);
 430              switch ($sequence[$i]) {
 431                  case '[':
 432                      // nested sequence
 433                      $value = self::parseSequence($sequence, $flags, $i, $references);
 434                      break;
 435                  case '{':
 436                      // nested mapping
 437                      $value = self::parseMapping($sequence, $flags, $i, $references);
 438                      break;
 439                  default:
 440                      $isQuoted = \in_array($sequence[$i], ['"', "'"]);
 441                      $value = self::parseScalar($sequence, $flags, [',', ']'], $i, null === $tag, $references);
 442   
 443                      // the value can be an array if a reference has been resolved to an array var
 444                      if (\is_string($value) && !$isQuoted && false !== strpos($value, ': ')) {
 445                          // embedded mapping?
 446                          try {
 447                              $pos = 0;
 448                              $value = self::parseMapping('{'.$value.'}', $flags, $pos, $references);
 449                          } catch (\InvalidArgumentException $e) {
 450                              // no, it's not
 451                          }
 452                      }
 453   
 454                      --$i;
 455              }
 456   
 457              if (null !== $tag) {
 458                  $value = new TaggedValue($tag, $value);
 459              }
 460   
 461              $output[] = $value;
 462   
 463              ++$i;
 464          }
 465   
 466          throw new ParseException(sprintf('Malformed inline YAML string: "%s".', $sequence), self::$parsedLineNumber + 1, null, self::$parsedFilename);
 467      }
 468   
 469      /**
 470       * Parses a YAML mapping.
 471       *
 472       * @param string $mapping
 473       * @param int    $flags
 474       * @param int    &$i
 475       * @param array  $references
 476       *
 477       * @return array|\stdClass
 478       *
 479       * @throws ParseException When malformed inline YAML string is parsed
 480       */
 481      private static function parseMapping($mapping, $flags, &$i = 0, $references = [])
 482      {
 483          $output = [];
 484          $len = \strlen($mapping);
 485          ++$i;
 486          $allowOverwrite = false;
 487   
 488          // {foo: bar, bar:foo, ...}
 489          while ($i < $len) {
 490              switch ($mapping[$i]) {
 491                  case ' ':
 492                  case ',':
 493                      ++$i;
 494                      continue 2;
 495                  case '}':
 496                      if (self::$objectForMap) {
 497                          return (object) $output;
 498                      }
 499   
 500                      return $output;
 501              }
 502   
 503              // key
 504              $isKeyQuoted = \in_array($mapping[$i], ['"', "'"], true);
 505              $key = self::parseScalar($mapping, $flags, [':', ' '], $i, false, [], true);
 506   
 507              if ('!php/const' === $key) {
 508                  $key .= self::parseScalar($mapping, $flags, [':', ' '], $i, false, [], true);
 509                  if ('!php/const:' === $key && ':' !== $mapping[$i]) {
 510                      $key = '';
 511                      --$i;
 512                  } else {
 513                      $key = self::evaluateScalar($key, $flags);
 514                  }
 515              }
 516   
 517              if (':' !== $key && false === $i = strpos($mapping, ':', $i)) {
 518                  break;
 519              }
 520   
 521              if (':' === $key) {
 522                  @trigger_error(self::getDeprecationMessage('Omitting the key of a mapping is deprecated and will throw a ParseException in 4.0.'), \E_USER_DEPRECATED);
 523              }
 524   
 525              if (!$isKeyQuoted) {
 526                  $evaluatedKey = self::evaluateScalar($key, $flags, $references);
 527   
 528                  if ('' !== $key && $evaluatedKey !== $key && !\is_string($evaluatedKey) && !\is_int($evaluatedKey)) {
 529                      @trigger_error(self::getDeprecationMessage('Implicit casting of incompatible mapping keys to strings is deprecated since Symfony 3.3 and will throw \Symfony\Component\Yaml\Exception\ParseException in 4.0. Quote your evaluable mapping keys instead.'), \E_USER_DEPRECATED);
 530                  }
 531              }
 532   
 533              if (':' !== $key && !$isKeyQuoted && (!isset($mapping[$i + 1]) || !\in_array($mapping[$i + 1], [' ', ',', '[', ']', '{', '}'], true))) {
 534                  @trigger_error(self::getDeprecationMessage('Using a colon after an unquoted mapping key that is not followed by an indication character (i.e. " ", ",", "[", "]", "{", "}") is deprecated since Symfony 3.2 and will throw a ParseException in 4.0.'), \E_USER_DEPRECATED);
 535              }
 536   
 537              if ('<<' === $key) {
 538                  $allowOverwrite = true;
 539              }
 540   
 541              while ($i < $len) {
 542                  if (':' === $mapping[$i] || ' ' === $mapping[$i]) {
 543                      ++$i;
 544   
 545                      continue;
 546                  }
 547   
 548                  $tag = self::parseTag($mapping, $i, $flags);
 549                  switch ($mapping[$i]) {
 550                      case '[':
 551                          // nested sequence
 552                          $value = self::parseSequence($mapping, $flags, $i, $references);
 553                          // Spec: Keys MUST be unique; first one wins.
 554                          // Parser cannot abort this mapping earlier, since lines
 555                          // are processed sequentially.
 556                          // But overwriting is allowed when a merge node is used in current block.
 557                          if ('<<' === $key) {
 558                              foreach ($value as $parsedValue) {
 559                                  $output += $parsedValue;
 560                              }
 561                          } elseif ($allowOverwrite || !isset($output[$key])) {
 562                              if (null !== $tag) {
 563                                  $output[$key] = new TaggedValue($tag, $value);
 564                              } else {
 565                                  $output[$key] = $value;
 566                              }
 567                          } elseif (isset($output[$key])) {
 568                              @trigger_error(self::getDeprecationMessage(sprintf('Duplicate key "%s" detected whilst parsing YAML. Silent handling of duplicate mapping keys in YAML is deprecated since Symfony 3.2 and will throw \Symfony\Component\Yaml\Exception\ParseException in 4.0.', $key)), \E_USER_DEPRECATED);
 569                          }
 570                          break;
 571                      case '{':
 572                          // nested mapping
 573                          $value = self::parseMapping($mapping, $flags, $i, $references);
 574                          // Spec: Keys MUST be unique; first one wins.
 575                          // Parser cannot abort this mapping earlier, since lines
 576                          // are processed sequentially.
 577                          // But overwriting is allowed when a merge node is used in current block.
 578                          if ('<<' === $key) {
 579                              $output += $value;
 580                          } elseif ($allowOverwrite || !isset($output[$key])) {
 581                              if (null !== $tag) {
 582                                  $output[$key] = new TaggedValue($tag, $value);
 583                              } else {
 584                                  $output[$key] = $value;
 585                              }
 586                          } elseif (isset($output[$key])) {
 587                              @trigger_error(self::getDeprecationMessage(sprintf('Duplicate key "%s" detected whilst parsing YAML. Silent handling of duplicate mapping keys in YAML is deprecated since Symfony 3.2 and will throw \Symfony\Component\Yaml\Exception\ParseException in 4.0.', $key)), \E_USER_DEPRECATED);
 588                          }
 589                          break;
 590                      default:
 591                          $value = self::parseScalar($mapping, $flags, [',', '}'], $i, null === $tag, $references);
 592                          // Spec: Keys MUST be unique; first one wins.
 593                          // Parser cannot abort this mapping earlier, since lines
 594                          // are processed sequentially.
 595                          // But overwriting is allowed when a merge node is used in current block.
 596                          if ('<<' === $key) {
 597                              $output += $value;
 598                          } elseif ($allowOverwrite || !isset($output[$key])) {
 599                              if (null !== $tag) {
 600                                  $output[$key] = new TaggedValue($tag, $value);
 601                              } else {
 602                                  $output[$key] = $value;
 603                              }
 604                          } elseif (isset($output[$key])) {
 605                              @trigger_error(self::getDeprecationMessage(sprintf('Duplicate key "%s" detected whilst parsing YAML. Silent handling of duplicate mapping keys in YAML is deprecated since Symfony 3.2 and will throw \Symfony\Component\Yaml\Exception\ParseException in 4.0.', $key)), \E_USER_DEPRECATED);
 606                          }
 607                          --$i;
 608                  }
 609                  ++$i;
 610   
 611                  continue 2;
 612              }
 613          }
 614   
 615          throw new ParseException(sprintf('Malformed inline YAML string: "%s".', $mapping), self::$parsedLineNumber + 1, null, self::$parsedFilename);
 616      }
 617   
 618      /**
 619       * Evaluates scalars and replaces magic values.
 620       *
 621       * @param string $scalar
 622       * @param int    $flags
 623       * @param array  $references
 624       *
 625       * @return mixed The evaluated YAML string
 626       *
 627       * @throws ParseException when object parsing support was disabled and the parser detected a PHP object or when a reference could not be resolved
 628       */
 629      private static function evaluateScalar($scalar, $flags, $references = [])
 630      {
 631          $scalar = trim($scalar);
 632          $scalarLower = strtolower($scalar);
 633   
 634          if (0 === strpos($scalar, '*')) {
 635              if (false !== $pos = strpos($scalar, '#')) {
 636                  $value = substr($scalar, 1, $pos - 2);
 637              } else {
 638                  $value = substr($scalar, 1);
 639              }
 640   
 641              // an unquoted *
 642              if (false === $value || '' === $value) {
 643                  throw new ParseException('A reference must contain at least one character.', self::$parsedLineNumber + 1, $value, self::$parsedFilename);
 644              }
 645   
 646              if (!\array_key_exists($value, $references)) {
 647                  throw new ParseException(sprintf('Reference "%s" does not exist.', $value), self::$parsedLineNumber + 1, $value, self::$parsedFilename);
 648              }
 649   
 650              return $references[$value];
 651          }
 652   
 653          switch (true) {
 654              case 'null' === $scalarLower:
 655              case '' === $scalar:
 656              case '~' === $scalar:
 657                  return null;
 658              case 'true' === $scalarLower:
 659                  return true;
 660              case 'false' === $scalarLower:
 661                  return false;
 662              case '!' === $scalar[0]:
 663                  switch (true) {
 664                      case 0 === strpos($scalar, '!str'):
 665                          @trigger_error(self::getDeprecationMessage('Support for the !str tag is deprecated since Symfony 3.4. Use the !!str tag instead.'), \E_USER_DEPRECATED);
 666   
 667                          return (string) substr($scalar, 5);
 668                      case 0 === strpos($scalar, '!!str '):
 669                          return (string) substr($scalar, 6);
 670                      case 0 === strpos($scalar, '! '):
 671                          @trigger_error(self::getDeprecationMessage('Using the non-specific tag "!" is deprecated since Symfony 3.4 as its behavior will change in 4.0. It will force non-evaluating your values in 4.0. Use plain integers or !!float instead.'), \E_USER_DEPRECATED);
 672   
 673                          return (int) self::parseScalar(substr($scalar, 2), $flags);
 674                      case 0 === strpos($scalar, '!php/object:'):
 675                          if (self::$objectSupport) {
 676                              @trigger_error(self::getDeprecationMessage('The !php/object: tag to indicate dumped PHP objects is deprecated since Symfony 3.4 and will be removed in 4.0. Use the !php/object (without the colon) tag instead.'), \E_USER_DEPRECATED);
 677   
 678                              return unserialize(substr($scalar, 12));
 679                          }
 680   
 681                          if (self::$exceptionOnInvalidType) {
 682                              throw new ParseException('Object support when parsing a YAML file has been disabled.', self::$parsedLineNumber + 1, $scalar, self::$parsedFilename);
 683                          }
 684   
 685                          return null;
 686                      case 0 === strpos($scalar, '!!php/object:'):
 687                          if (self::$objectSupport) {
 688                              @trigger_error(self::getDeprecationMessage('The !!php/object: tag to indicate dumped PHP objects is deprecated since Symfony 3.1 and will be removed in 4.0. Use the !php/object (without the colon) tag instead.'), \E_USER_DEPRECATED);
 689   
 690                              return unserialize(substr($scalar, 13));
 691                          }
 692   
 693                          if (self::$exceptionOnInvalidType) {
 694                              throw new ParseException('Object support when parsing a YAML file has been disabled.', self::$parsedLineNumber + 1, $scalar, self::$parsedFilename);
 695                          }
 696   
 697                          return null;
 698                      case 0 === strpos($scalar, '!php/object'):
 699                          if (self::$objectSupport) {
 700                              if (!isset($scalar[12])) {
 701                                  return false;
 702                              }
 703   
 704                              return unserialize(self::parseScalar(substr($scalar, 12)));
 705                          }
 706   
 707                          if (self::$exceptionOnInvalidType) {
 708                              throw new ParseException('Object support when parsing a YAML file has been disabled.', self::$parsedLineNumber + 1, $scalar, self::$parsedFilename);
 709                          }
 710   
 711                          return null;
 712                      case 0 === strpos($scalar, '!php/const:'):
 713                          if (self::$constantSupport) {
 714                              @trigger_error(self::getDeprecationMessage('The !php/const: tag to indicate dumped PHP constants is deprecated since Symfony 3.4 and will be removed in 4.0. Use the !php/const (without the colon) tag instead.'), \E_USER_DEPRECATED);
 715   
 716                              if (\defined($const = substr($scalar, 11))) {
 717                                  return \constant($const);
 718                              }
 719   
 720                              throw new ParseException(sprintf('The constant "%s" is not defined.', $const), self::$parsedLineNumber + 1, $scalar, self::$parsedFilename);
 721                          }
 722                          if (self::$exceptionOnInvalidType) {
 723                              throw new ParseException(sprintf('The string "%s" could not be parsed as a constant. Did you forget to pass the "Yaml::PARSE_CONSTANT" flag to the parser?', $scalar), self::$parsedLineNumber + 1, $scalar, self::$parsedFilename);
 724                          }
 725   
 726                          return null;
 727                      case 0 === strpos($scalar, '!php/const'):
 728                          if (self::$constantSupport) {
 729                              if (!isset($scalar[11])) {
 730                                  return '';
 731                              }
 732   
 733                              $i = 0;
 734                              if (\defined($const = self::parseScalar(substr($scalar, 11), 0, null, $i, false))) {
 735                                  return \constant($const);
 736                              }
 737   
 738                              throw new ParseException(sprintf('The constant "%s" is not defined.', $const), self::$parsedLineNumber + 1, $scalar, self::$parsedFilename);
 739                          }
 740                          if (self::$exceptionOnInvalidType) {
 741                              throw new ParseException(sprintf('The string "%s" could not be parsed as a constant. Did you forget to pass the "Yaml::PARSE_CONSTANT" flag to the parser?', $scalar), self::$parsedLineNumber + 1, $scalar, self::$parsedFilename);
 742                          }
 743   
 744                          return null;
 745                      case 0 === strpos($scalar, '!!float '):
 746                          return (float) substr($scalar, 8);
 747                      case 0 === strpos($scalar, '!!binary '):
 748                          return self::evaluateBinaryScalar(substr($scalar, 9));
 749                      default:
 750                          @trigger_error(self::getDeprecationMessage(sprintf('Using the unquoted scalar value "%s" is deprecated since Symfony 3.3 and will be considered as a tagged value in 4.0. You must quote it.', $scalar)), \E_USER_DEPRECATED);
 751                  }
 752   
 753              // Optimize for returning strings.
 754              // no break
 755              case '+' === $scalar[0] || '-' === $scalar[0] || '.' === $scalar[0] || is_numeric($scalar[0]):
 756                  if (Parser::preg_match('{^[+-]?[0-9][0-9_]*$}', $scalar)) {
 757                      $scalar = str_replace('_', '', (string) $scalar);
 758                  }
 759   
 760                  switch (true) {
 761                      case ctype_digit($scalar):
 762                          if (preg_match('/^0[0-7]+$/', $scalar)) {
 763                              return octdec($scalar);
 764                          }
 765   
 766                          $cast = (int) $scalar;
 767   
 768                          return ($scalar === (string) $cast) ? $cast : $scalar;
 769                      case '-' === $scalar[0] && ctype_digit(substr($scalar, 1)):
 770                          if (preg_match('/^-0[0-7]+$/', $scalar)) {
 771                              return -octdec(substr($scalar, 1));
 772                          }
 773   
 774                          $cast = (int) $scalar;
 775   
 776                          return ($scalar === (string) $cast) ? $cast : $scalar;
 777                      case is_numeric($scalar):
 778                      case Parser::preg_match(self::getHexRegex(), $scalar):
 779                          $scalar = str_replace('_', '', $scalar);
 780   
 781                          return '0x' === $scalar[0].$scalar[1] ? hexdec($scalar) : (float) $scalar;
 782                      case '.inf' === $scalarLower:
 783                      case '.nan' === $scalarLower:
 784                          return -log(0);
 785                      case '-.inf' === $scalarLower:
 786                          return log(0);
 787                      case Parser::preg_match('/^(-|\+)?[0-9][0-9,]*(\.[0-9_]+)?$/', $scalar):
 788                      case Parser::preg_match('/^(-|\+)?[0-9][0-9_]*(\.[0-9_]+)?$/', $scalar):
 789                          if (false !== strpos($scalar, ',')) {
 790                              @trigger_error(self::getDeprecationMessage('Using the comma as a group separator for floats is deprecated since Symfony 3.2 and will be removed in 4.0.'), \E_USER_DEPRECATED);
 791                          }
 792   
 793                          return (float) str_replace([',', '_'], '', $scalar);
 794                      case Parser::preg_match(self::getTimestampRegex(), $scalar):
 795                          if (Yaml::PARSE_DATETIME & $flags) {
 796                              // When no timezone is provided in the parsed date, YAML spec says we must assume UTC.
 797                              return new \DateTime($scalar, new \DateTimeZone('UTC'));
 798                          }
 799   
 800                          $timeZone = date_default_timezone_get();
 801                          date_default_timezone_set('UTC');
 802                          $time = strtotime($scalar);
 803                          date_default_timezone_set($timeZone);
 804   
 805                          return $time;
 806                  }
 807          }
 808   
 809          return (string) $scalar;
 810      }
 811   
 812      /**
 813       * @param string $value
 814       * @param int    &$i
 815       * @param int    $flags
 816       *
 817       * @return string|null
 818       */
 819      private static function parseTag($value, &$i, $flags)
 820      {
 821          if ('!' !== $value[$i]) {
 822              return null;
 823          }
 824   
 825          $tagLength = strcspn($value, " \t\n", $i + 1);
 826          $tag = substr($value, $i + 1, $tagLength);
 827   
 828          $nextOffset = $i + $tagLength + 1;
 829          $nextOffset += strspn($value, ' ', $nextOffset);
 830   
 831          // Is followed by a scalar
 832          if ((!isset($value[$nextOffset]) || !\in_array($value[$nextOffset], ['[', '{'], true)) && 'tagged' !== $tag) {
 833              // Manage non-whitelisted scalars in {@link self::evaluateScalar()}
 834              return null;
 835          }
 836   
 837          // Built-in tags
 838          if ($tag && '!' === $tag[0]) {
 839              throw new ParseException(sprintf('The built-in tag "!%s" is not implemented.', $tag), self::$parsedLineNumber + 1, $value, self::$parsedFilename);
 840          }
 841   
 842          if (Yaml::PARSE_CUSTOM_TAGS & $flags) {
 843              $i = $nextOffset;
 844   
 845              return $tag;
 846          }
 847   
 848          throw new ParseException(sprintf('Tags support is not enabled. Enable the `Yaml::PARSE_CUSTOM_TAGS` flag to use "!%s".', $tag), self::$parsedLineNumber + 1, $value, self::$parsedFilename);
 849      }
 850   
 851      /**
 852       * @param string $scalar
 853       *
 854       * @return string
 855       *
 856       * @internal
 857       */
 858      public static function evaluateBinaryScalar($scalar)
 859      {
 860          $parsedBinaryData = self::parseScalar(preg_replace('/\s/', '', $scalar));
 861   
 862          if (0 !== (\strlen($parsedBinaryData) % 4)) {
 863              throw new ParseException(sprintf('The normalized base64 encoded data (data without whitespace characters) length must be a multiple of four (%d bytes given).', \strlen($parsedBinaryData)), self::$parsedLineNumber + 1, $scalar, self::$parsedFilename);
 864          }
 865   
 866          if (!Parser::preg_match('#^[A-Z0-9+/]+={0,2}$#i', $parsedBinaryData)) {
 867              throw new ParseException(sprintf('The base64 encoded data (%s) contains invalid characters.', $parsedBinaryData), self::$parsedLineNumber + 1, $scalar, self::$parsedFilename);
 868          }
 869   
 870          return base64_decode($parsedBinaryData, true);
 871      }
 872   
 873      private static function isBinaryString($value)
 874      {
 875          return !preg_match('//u', $value) || preg_match('/[^\x00\x07-\x0d\x1B\x20-\xff]/', $value);
 876      }
 877   
 878      /**
 879       * Gets a regex that matches a YAML date.
 880       *
 881       * @return string The regular expression
 882       *
 883       * @see http://www.yaml.org/spec/1.2/spec.html#id2761573
 884       */
 885      private static function getTimestampRegex()
 886      {
 887          return <<<EOF
 888          ~^
 889          (?P<year>[0-9][0-9][0-9][0-9])
 890          -(?P<month>[0-9][0-9]?)
 891          -(?P<day>[0-9][0-9]?)
 892          (?:(?:[Tt]|[ \t]+)
 893          (?P<hour>[0-9][0-9]?)
 894          :(?P<minute>[0-9][0-9])
 895          :(?P<second>[0-9][0-9])
 896          (?:\.(?P<fraction>[0-9]*))?
 897          (?:[ \t]*(?P<tz>Z|(?P<tz_sign>[-+])(?P<tz_hour>[0-9][0-9]?)
 898          (?::(?P<tz_minute>[0-9][0-9]))?))?)?
 899          $~x
 900  EOF;
 901   
 902      }
 903   
 904      /**
 905       * Gets a regex that matches a YAML number in hexadecimal notation.
 906       *
 907       * @return string
 908       */
 909      private static function getHexRegex()
 910      {
 911          return '~^0x[0-9a-f_]++$~i';
 912      }
 913   
 914      private static function getDeprecationMessage($message)
 915      {
 916          $message = rtrim($message, '.');
 917   
 918          if (null !== self::$parsedFilename) {
 919              $message .= ' in '.self::$parsedFilename;
 920          }
 921   
 922          if (-1 !== self::$parsedLineNumber) {
 923              $message .= ' on line '.(self::$parsedLineNumber + 1);
 924          }
 925   
 926          return $message.'.';
 927      }
 928  }
 929