PluginProbe
WindPress – Tailwind CSS integration for WordPress / 3.2.90
WindPress – Tailwind CSS integration for WordPress v3.2.90
3.2.90 3.2.89 3.2.88 3.2.87 3.2.86 3.2.85 3.2.84 3.2.83 3.2.82 3.2.81 trunk 3.0.0 3.0.1 3.0.10 3.0.11 3.0.12 3.0.13 3.0.14 3.0.15 3.0.16 3.0.17 3.0.2 3.0.3 3.0.4 3.0.5 All 144 releases
windpress / vendor / symfony / yaml / Inline.php

Inline.php in WindPress – Tailwind CSS integration for WordPress 3.2.90, at vendor/symfony/yaml/Inline.php

719 lines 34.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /*
4 * This file is part of the Symfony package.
5 *
6 * (c) Fabien Potencier <fabien@symfony.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11 namespace WindPressDeps\Symfony\Component\Yaml;
12
13 use WindPressDeps\Symfony\Component\Yaml\Exception\DumpException;
14 use WindPressDeps\Symfony\Component\Yaml\Exception\ParseException;
15 use WindPressDeps\Symfony\Component\Yaml\Tag\TaggedValue;
16 /**
17 * Inline implements a YAML parser/dumper for the YAML inline syntax.
18 *
19 * @author Fabien Potencier <fabien@symfony.com>
20 *
21 * @internal
22 */
23 class Inline
24 {
25 public const REGEX_QUOTED_STRING = '(?:"([^"\\\\]*+(?:\\\\.[^"\\\\]*+)*+)"|\'([^\']*+(?:\'\'[^\']*+)*+)\')';
26 public static $parsedLineNumber = -1;
27 public static $parsedFilename;
28 private static $exceptionOnInvalidType = \false;
29 private static $objectSupport = \false;
30 private static $objectForMap = \false;
31 private static $constantSupport = \false;
32 public static function initialize(int $flags, ?int $parsedLineNumber = null, ?string $parsedFilename = null)
33 {
34 self::$exceptionOnInvalidType = (bool) (Yaml::PARSE_EXCEPTION_ON_INVALID_TYPE & $flags);
35 self::$objectSupport = (bool) (Yaml::PARSE_OBJECT & $flags);
36 self::$objectForMap = (bool) (Yaml::PARSE_OBJECT_FOR_MAP & $flags);
37 self::$constantSupport = (bool) (Yaml::PARSE_CONSTANT & $flags);
38 self::$parsedFilename = $parsedFilename;
39 if (null !== $parsedLineNumber) {
40 self::$parsedLineNumber = $parsedLineNumber;
41 }
42 }
43 /**
44 * Converts a YAML string to a PHP value.
45 *
46 * @param string|null $value A YAML string
47 * @param int $flags A bit field of Yaml::PARSE_* constants to customize the YAML parser behavior
48 * @param array $references Mapping of variable names to values
49 *
50 * @return mixed
51 *
52 * @throws ParseException
53 */
54 public static function parse(?string $value = null, int $flags = 0, array &$references = [], ?ParserState $state = null)
55 {
56 if (null === $value) {
57 return '';
58 }
59 self::initialize($flags);
60 $state = $state ?? new ParserState();
61 $value = trim($value);
62 if ('' === $value) {
63 return '';
64 }
65 if (2 & (int) \ini_get('mbstring.func_overload')) {
66 $mbEncoding = mb_internal_encoding();
67 mb_internal_encoding('ASCII');
68 }
69 try {
70 $i = 0;
71 $isQuoted = null;
72 $tag = self::parseTag($value, $i, $flags);
73 switch ($value[$i]) {
74 case '[':
75 $result = self::parseSequence($state, $value, $flags, $i, $references);
76 ++$i;
77 break;
78 case '{':
79 $result = self::parseMapping($state, $value, $flags, $i, $references);
80 ++$i;
81 break;
82 default:
83 $result = self::parseScalar($value, $flags, null, $i, \true, $references, $isQuoted, $state);
84 }
85 // some comments are allowed at the end
86 if (preg_replace('/\s*#.*$/A', '', substr($value, $i))) {
87 throw new ParseException(sprintf('Unexpected characters near "%s".', substr($value, $i)), self::$parsedLineNumber + 1, $value, self::$parsedFilename);
88 }
89 if (null !== $tag && '' !== $tag) {
90 return new TaggedValue($tag, $result);
91 }
92 return $result;
93 } finally {
94 if (isset($mbEncoding)) {
95 mb_internal_encoding($mbEncoding);
96 }
97 }
98 }
99 /**
100 * Dumps a given PHP variable to a YAML string.
101 *
102 * @param mixed $value The PHP variable to convert
103 * @param int $flags A bit field of Yaml::DUMP_* constants to customize the dumped YAML string
104 *
105 * @throws DumpException When trying to dump PHP resource
106 */
107 public static function dump($value, int $flags = 0): string
108 {
109 switch (\true) {
110 case \is_resource($value):
111 if (Yaml::DUMP_EXCEPTION_ON_INVALID_TYPE & $flags) {
112 throw new DumpException(sprintf('Unable to dump PHP resources in a YAML file ("%s").', get_resource_type($value)));
113 }
114 return self::dumpNull($flags);
115 case $value instanceof \DateTimeInterface:
116 return $value->format('c');
117 case $value instanceof \UnitEnum:
118 return sprintf('!php/const %s::%s', \get_class($value), $value->name);
119 case \is_object($value):
120 if ($value instanceof TaggedValue) {
121 return '!' . $value->getTag() . ' ' . self::dump($value->getValue(), $flags);
122 }
123 if (Yaml::DUMP_OBJECT & $flags) {
124 return '!php/object ' . self::dump(serialize($value));
125 }
126 if (Yaml::DUMP_OBJECT_AS_MAP & $flags && ($value instanceof \stdClass || $value instanceof \ArrayObject)) {
127 $output = [];
128 foreach ($value as $key => $val) {
129 $output[] = sprintf('%s: %s', self::dump($key, $flags), self::dump($val, $flags));
130 }
131 return sprintf('{ %s }', implode(', ', $output));
132 }
133 if (Yaml::DUMP_EXCEPTION_ON_INVALID_TYPE & $flags) {
134 throw new DumpException('Object support when dumping a YAML file has been disabled.');
135 }
136 return self::dumpNull($flags);
137 case \is_array($value):
138 return self::dumpArray($value, $flags);
139 case null === $value:
140 return self::dumpNull($flags);
141 case \true === $value:
142 return 'true';
143 case \false === $value:
144 return 'false';
145 case \is_int($value):
146 return $value;
147 case is_numeric($value) && \false === strpbrk($value, "\f\n\r\t\v"):
148 $locale = setlocale(\LC_NUMERIC, 0);
149 if (\false !== $locale) {
150 setlocale(\LC_NUMERIC, 'C');
151 }
152 if (\is_float($value)) {
153 $repr = (string) $value;
154 if (is_infinite($value)) {
155 $repr = str_ireplace('INF', '.Inf', $repr);
156 } elseif (floor($value) == $value && $repr == $value) {
157 // Preserve float data type since storing a whole number will result in integer value.
158 if (\false === strpos($repr, 'E')) {
159 $repr = $repr . '.0';
160 }
161 }
162 } else {
163 $repr = \is_string($value) ? "'{$value}'" : (string) $value;
164 }
165 if (\false !== $locale) {
166 setlocale(\LC_NUMERIC, $locale);
167 }
168 return $repr;
169 case '' == $value:
170 return "''";
171 case self::isBinaryString($value):
172 return '!!binary ' . base64_encode($value);
173 case Escaper::requiresDoubleQuoting($value):
174 return Escaper::escapeWithDoubleQuotes($value);
175 case Escaper::requiresSingleQuoting($value):
176 case Parser::preg_match('{^[0-9]+[_0-9]*$}', $value):
177 case Parser::preg_match(self::getHexRegex(), $value):
178 case Parser::preg_match(self::getTimestampRegex(), $value):
179 return Escaper::escapeWithSingleQuotes($value);
180 default:
181 return $value;
182 }
183 }
184 /**
185 * Check if given array is hash or just normal indexed array.
186 *
187 * @param array|\ArrayObject|\stdClass $value The PHP array or array-like object to check
188 */
189 public static function isHash($value): bool
190 {
191 if ($value instanceof \stdClass || $value instanceof \ArrayObject) {
192 return \true;
193 }
194 $expectedKey = 0;
195 foreach ($value as $key => $val) {
196 if ($key !== $expectedKey++) {
197 return \true;
198 }
199 }
200 return \false;
201 }
202 /**
203 * Dumps a PHP array to a YAML string.
204 *
205 * @param array $value The PHP array to dump
206 * @param int $flags A bit field of Yaml::DUMP_* constants to customize the dumped YAML string
207 */
208 private static function dumpArray(array $value, int $flags): string
209 {
210 // array
211 if (($value || Yaml::DUMP_EMPTY_ARRAY_AS_SEQUENCE & $flags) && !self::isHash($value)) {
212 $output = [];
213 foreach ($value as $val) {
214 $output[] = self::dump($val, $flags);
215 }
216 return sprintf('[%s]', implode(', ', $output));
217 }
218 // hash
219 $output = [];
220 foreach ($value as $key => $val) {
221 $output[] = sprintf('%s: %s', self::dump($key, $flags), self::dump($val, $flags));
222 }
223 return sprintf('{ %s }', implode(', ', $output));
224 }
225 private static function dumpNull(int $flags): string
226 {
227 if (Yaml::DUMP_NULL_AS_TILDE & $flags) {
228 return '~';
229 }
230 return 'null';
231 }
232 /**
233 * Parses a YAML scalar.
234 *
235 * @return mixed
236 *
237 * @throws ParseException When malformed inline YAML string is parsed
238 */
239 public static function parseScalar(string $scalar, int $flags = 0, ?array $delimiters = null, int &$i = 0, bool $evaluate = \true, array &$references = [], ?bool &$isQuoted = null, ?ParserState $state = null)
240 {
241 if (\in_array($scalar[$i], ['"', "'"], \true)) {
242 // quoted scalar
243 $isQuoted = \true;
244 $output = self::parseQuotedScalar($scalar, $i);
245 if (null !== $delimiters) {
246 $tmp = ltrim(substr($scalar, $i), " \n");
247 if ('' === $tmp) {
248 throw new ParseException(sprintf('Unexpected end of line, expected one of "%s".', implode('', $delimiters)), self::$parsedLineNumber + 1, $scalar, self::$parsedFilename);
249 }
250 if (!\in_array($tmp[0], $delimiters)) {
251 throw new ParseException(sprintf('Unexpected characters (%s).', substr($scalar, $i)), self::$parsedLineNumber + 1, $scalar, self::$parsedFilename);
252 }
253 }
254 } else {
255 // "normal" string
256 $isQuoted = \false;
257 if (!$delimiters) {
258 $output = substr($scalar, $i);
259 $i += \strlen($output);
260 // remove comments
261 if (Parser::preg_match('/[ \t]+#/', $output, $match, \PREG_OFFSET_CAPTURE)) {
262 $output = substr($output, 0, $match[0][1]);
263 }
264 } elseif (Parser::preg_match('/^(.*?)(' . implode('|', $delimiters) . ')/', substr($scalar, $i), $match)) {
265 $output = $match[1];
266 $i += \strlen($output);
267 $output = trim($output);
268 } else {
269 throw new ParseException(sprintf('Malformed inline YAML string: "%s".', $scalar), self::$parsedLineNumber + 1, null, self::$parsedFilename);
270 }
271 // a non-quoted string cannot start with @ or ` (reserved) nor with a scalar indicator (| or >)
272 if ($output && ('@' === $output[0] || '`' === $output[0] || '|' === $output[0] || '>' === $output[0] || '%' === $output[0])) {
273 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);
274 }
275 if ($evaluate) {
276 $state = $state ?? new ParserState();
277 $output = self::evaluateScalar($state, $output, $flags, $references, $isQuoted);
278 }
279 }
280 return $output;
281 }
282 /**
283 * Parses a YAML quoted scalar.
284 *
285 * @throws ParseException When malformed inline YAML string is parsed
286 */
287 private static function parseQuotedScalar(string $scalar, int &$i = 0): string
288 {
289 if (!Parser::preg_match('/' . self::REGEX_QUOTED_STRING . '/Au', substr($scalar, $i), $match)) {
290 throw new ParseException(sprintf('Malformed inline YAML string: "%s".', substr($scalar, $i)), self::$parsedLineNumber + 1, $scalar, self::$parsedFilename);
291 }
292 $output = substr($match[0], 1, -1);
293 $unescaper = new Unescaper();
294 if ('"' == $scalar[$i]) {
295 $output = $unescaper->unescapeDoubleQuotedString($output);
296 } else {
297 $output = $unescaper->unescapeSingleQuotedString($output);
298 }
299 $i += \strlen($match[0]);
300 return $output;
301 }
302 /**
303 * Parses a YAML sequence.
304 *
305 * @throws ParseException When malformed inline YAML string is parsed
306 */
307 private static function parseSequence(ParserState $state, string $sequence, int $flags, int &$i = 0, array &$references = []): array
308 {
309 $state->enterNestingLevel(self::$parsedLineNumber + 1, null, self::$parsedFilename);
310 $output = [];
311 $len = \strlen($sequence);
312 ++$i;
313 try {
314 // [foo, bar, ...]
315 $lastToken = null;
316 while ($i < $len) {
317 if (']' === $sequence[$i]) {
318 return $output;
319 }
320 if (',' === $sequence[$i] || ' ' === $sequence[$i]) {
321 if (',' === $sequence[$i] && (null === $lastToken || 'separator' === $lastToken)) {
322 $output[] = null;
323 } elseif (',' === $sequence[$i]) {
324 $lastToken = 'separator';
325 }
326 ++$i;
327 continue;
328 }
329 $tag = self::parseTag($sequence, $i, $flags);
330 switch ($sequence[$i]) {
331 case '[':
332 // nested sequence
333 $value = self::parseSequence($state, $sequence, $flags, $i, $references);
334 break;
335 case '{':
336 // nested mapping
337 $value = self::parseMapping($state, $sequence, $flags, $i, $references);
338 break;
339 default:
340 $value = self::parseScalar($sequence, $flags, [',', ']'], $i, null === $tag, $references, $isQuoted, $state);
341 // the value can be an array if a reference has been resolved to an array var
342 if (\is_string($value) && !$isQuoted && \false !== strpos($value, ': ')) {
343 // embedded mapping?
344 try {
345 $pos = 0;
346 $value = self::parseMapping($state, '{' . $value . '}', $flags, $pos, $references);
347 } catch (\InvalidArgumentException $e) {
348 // no, it's not
349 }
350 }
351 if (!$isQuoted && \is_string($value) && '' !== $value && '&' === $value[0] && Parser::preg_match(Parser::REFERENCE_PATTERN, $value, $matches)) {
352 $references[$matches['ref']] = $matches['value'];
353 $value = $matches['value'];
354 }
355 --$i;
356 }
357 if (null !== $tag && '' !== $tag) {
358 $value = new TaggedValue($tag, $value);
359 }
360 $output[] = $value;
361 $lastToken = 'value';
362 ++$i;
363 }
364 throw new ParseException(sprintf('Malformed inline YAML string: "%s".', $sequence), self::$parsedLineNumber + 1, null, self::$parsedFilename);
365 } finally {
366 $state->leaveNestingLevel();
367 }
368 }
369 /**
370 * Parses a YAML mapping.
371 *
372 * @return array|\stdClass
373 *
374 * @throws ParseException When malformed inline YAML string is parsed
375 */
376 private static function parseMapping(ParserState $state, string $mapping, int $flags, int &$i = 0, array &$references = [])
377 {
378 $state->enterNestingLevel(self::$parsedLineNumber + 1, null, self::$parsedFilename);
379 $output = [];
380 $len = \strlen($mapping);
381 ++$i;
382 $allowOverwrite = \false;
383 try {
384 // {foo: bar, bar:foo, ...}
385 while ($i < $len) {
386 switch ($mapping[$i]) {
387 case ' ':
388 case ',':
389 case "\n":
390 ++$i;
391 continue 2;
392 case '}':
393 if (self::$objectForMap) {
394 return (object) $output;
395 }
396 return $output;
397 }
398 // key
399 $offsetBeforeKeyParsing = $i;
400 $isKeyQuoted = \in_array($mapping[$i], ['"', "'"], \true);
401 $key = self::parseScalar($mapping, $flags, [':', ' '], $i, \false);
402 if ($offsetBeforeKeyParsing === $i) {
403 throw new ParseException('Missing mapping key.', self::$parsedLineNumber + 1, $mapping);
404 }
405 if ('!php/const' === $key) {
406 $key .= ' ' . self::parseScalar($mapping, $flags, [':'], $i, \false);
407 $key = self::evaluateScalar($state, $key, $flags);
408 }
409 if (\false === $i = strpos($mapping, ':', $i)) {
410 break;
411 }
412 if (!$isKeyQuoted) {
413 $evaluatedKey = self::evaluateScalar($state, $key, $flags, $references);
414 if ('' !== $key && $evaluatedKey !== $key && !\is_string($evaluatedKey) && !\is_int($evaluatedKey)) {
415 throw new ParseException('Implicit casting of incompatible mapping keys to strings is not supported. Quote your evaluable mapping keys instead.', self::$parsedLineNumber + 1, $mapping);
416 }
417 }
418 if (!$isKeyQuoted && (!isset($mapping[$i + 1]) || !\in_array($mapping[$i + 1], [' ', ',', '[', ']', '{', '}', "\n"], \true))) {
419 throw new ParseException('Colons must be followed by a space or an indication character (i.e. " ", ",", "[", "]", "{", "}").', self::$parsedLineNumber + 1, $mapping);
420 }
421 if ('<<' === $key) {
422 $allowOverwrite = \true;
423 }
424 while ($i < $len) {
425 if (':' === $mapping[$i] || ' ' === $mapping[$i] || "\n" === $mapping[$i]) {
426 ++$i;
427 continue;
428 }
429 $tag = self::parseTag($mapping, $i, $flags);
430 switch ($mapping[$i]) {
431 case '[':
432 // nested sequence
433 $value = self::parseSequence($state, $mapping, $flags, $i, $references);
434 // Spec: Keys MUST be unique; first one wins.
435 // Parser cannot abort this mapping earlier, since lines
436 // are processed sequentially.
437 // But overwriting is allowed when a merge node is used in current block.
438 if ('<<' === $key) {
439 foreach ($value as $parsedValue) {
440 $output += $parsedValue;
441 }
442 } elseif ($allowOverwrite || !isset($output[$key])) {
443 if (null !== $tag) {
444 $output[$key] = new TaggedValue($tag, $value);
445 } else {
446 $output[$key] = $value;
447 }
448 } elseif (isset($output[$key])) {
449 throw new ParseException(sprintf('Duplicate key "%s" detected.', $key), self::$parsedLineNumber + 1, $mapping);
450 }
451 break;
452 case '{':
453 // nested mapping
454 $value = self::parseMapping($state, $mapping, $flags, $i, $references);
455 // Spec: Keys MUST be unique; first one wins.
456 // Parser cannot abort this mapping earlier, since lines
457 // are processed sequentially.
458 // But overwriting is allowed when a merge node is used in current block.
459 if ('<<' === $key) {
460 $output += $value;
461 } elseif ($allowOverwrite || !isset($output[$key])) {
462 if (null !== $tag) {
463 $output[$key] = new TaggedValue($tag, $value);
464 } else {
465 $output[$key] = $value;
466 }
467 } elseif (isset($output[$key])) {
468 throw new ParseException(sprintf('Duplicate key "%s" detected.', $key), self::$parsedLineNumber + 1, $mapping);
469 }
470 break;
471 default:
472 $value = self::parseScalar($mapping, $flags, [',', '}', "\n"], $i, null === $tag, $references, $isValueQuoted, $state);
473 // Spec: Keys MUST be unique; first one wins.
474 // Parser cannot abort this mapping earlier, since lines
475 // are processed sequentially.
476 // But overwriting is allowed when a merge node is used in current block.
477 if ('<<' === $key) {
478 $output += $value;
479 } elseif ($allowOverwrite || !isset($output[$key])) {
480 if (!$isValueQuoted && \is_string($value) && '' !== $value && '&' === $value[0] && !self::isBinaryString($value) && Parser::preg_match(Parser::REFERENCE_PATTERN, $value, $matches)) {
481 $references[$matches['ref']] = $matches['value'];
482 $value = $matches['value'];
483 }
484 if (null !== $tag) {
485 $output[$key] = new TaggedValue($tag, $value);
486 } else {
487 $output[$key] = $value;
488 }
489 } elseif (isset($output[$key])) {
490 throw new ParseException(sprintf('Duplicate key "%s" detected.', $key), self::$parsedLineNumber + 1, $mapping);
491 }
492 --$i;
493 }
494 ++$i;
495 continue 2;
496 }
497 }
498 throw new ParseException(sprintf('Malformed inline YAML string: "%s".', $mapping), self::$parsedLineNumber + 1, null, self::$parsedFilename);
499 } finally {
500 $state->leaveNestingLevel();
501 }
502 }
503 /**
504 * Evaluates scalars and replaces magic values.
505 *
506 * @return mixed
507 *
508 * @throws ParseException when object parsing support was disabled and the parser detected a PHP object or when a reference could not be resolved
509 */
510 private static function evaluateScalar(ParserState $state, string $scalar, int $flags, array &$references = [], ?bool &$isQuotedString = null)
511 {
512 $isQuotedString = \false;
513 $scalar = trim($scalar);
514 if (0 === strpos($scalar, '*')) {
515 if (\false !== $pos = strpos($scalar, '#')) {
516 $value = substr($scalar, 1, $pos - 2);
517 } else {
518 $value = substr($scalar, 1);
519 }
520 // an unquoted *
521 if (\false === $value || '' === $value) {
522 throw new ParseException('A reference must contain at least one character.', self::$parsedLineNumber + 1, $value, self::$parsedFilename);
523 }
524 if (!\array_key_exists($value, $references)) {
525 throw new ParseException(sprintf('Reference "%s" does not exist.', $value), self::$parsedLineNumber + 1, $value, self::$parsedFilename);
526 }
527 $state->countAlias($references[$value], self::$parsedLineNumber + 1, null, self::$parsedFilename);
528 return $references[$value];
529 }
530 $scalarLower = strtolower($scalar);
531 switch (\true) {
532 case 'null' === $scalarLower:
533 case '' === $scalar:
534 case '~' === $scalar:
535 return null;
536 case 'true' === $scalarLower:
537 return \true;
538 case 'false' === $scalarLower:
539 return \false;
540 case '!' === $scalar[0]:
541 switch (\true) {
542 case 0 === strpos($scalar, '!!str '):
543 $s = (string) substr($scalar, 6);
544 if (\in_array($s[0] ?? '', ['"', "'"], \true)) {
545 $isQuotedString = \true;
546 $s = self::parseQuotedScalar($s);
547 }
548 return $s;
549 case 0 === strpos($scalar, '! '):
550 return substr($scalar, 2);
551 case 0 === strpos($scalar, '!php/object'):
552 if (self::$objectSupport) {
553 if (!isset($scalar[12])) {
554 trigger_deprecation('symfony/yaml', '5.1', 'Using the !php/object tag without a value is deprecated.');
555 return \false;
556 }
557 return unserialize(self::parseScalar(substr($scalar, 12)));
558 }
559 if (self::$exceptionOnInvalidType) {
560 throw new ParseException('Object support when parsing a YAML file has been disabled.', self::$parsedLineNumber + 1, $scalar, self::$parsedFilename);
561 }
562 return null;
563 case 0 === strpos($scalar, '!php/const'):
564 if (self::$constantSupport) {
565 if (!isset($scalar[11])) {
566 trigger_deprecation('symfony/yaml', '5.1', 'Using the !php/const tag without a value is deprecated.');
567 return '';
568 }
569 $i = 0;
570 if (\defined($const = self::parseScalar(substr($scalar, 11), 0, null, $i, \false))) {
571 return \constant($const);
572 }
573 throw new ParseException(sprintf('The constant "%s" is not defined.', $const), self::$parsedLineNumber + 1, $scalar, self::$parsedFilename);
574 }
575 if (self::$exceptionOnInvalidType) {
576 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);
577 }
578 return null;
579 case 0 === strpos($scalar, '!!float '):
580 return (float) substr($scalar, 8);
581 case 0 === strpos($scalar, '!!binary '):
582 return self::evaluateBinaryScalar(substr($scalar, 9));
583 }
584 throw new ParseException(sprintf('The string "%s" could not be parsed as it uses an unsupported built-in tag.', $scalar), self::$parsedLineNumber, $scalar, self::$parsedFilename);
585 case preg_match('/^(?:\+|-)?0o(?P<value>[0-7_]++)$/', $scalar, $matches):
586 $value = str_replace('_', '', $matches['value']);
587 if ('-' === $scalar[0]) {
588 return -octdec($value);
589 }
590 return octdec($value);
591 case \in_array($scalar[0], ['+', '-', '.'], \true) || is_numeric($scalar[0]):
592 if (Parser::preg_match('{^[+-]?[0-9][0-9_]*$}', $scalar)) {
593 $scalar = str_replace('_', '', $scalar);
594 }
595 switch (\true) {
596 case ctype_digit($scalar):
597 if (preg_match('/^0[0-7]+$/', $scalar)) {
598 trigger_deprecation('symfony/yaml', '5.1', 'Support for parsing numbers prefixed with 0 as octal numbers. They will be parsed as strings as of 6.0. Use "%s" to represent the octal number.', '0o' . substr($scalar, 1));
599 return octdec($scalar);
600 }
601 $cast = (int) $scalar;
602 return $scalar === (string) $cast ? $cast : $scalar;
603 case '-' === $scalar[0] && ctype_digit(substr($scalar, 1)):
604 if (preg_match('/^-0[0-7]+$/', $scalar)) {
605 trigger_deprecation('symfony/yaml', '5.1', 'Support for parsing numbers prefixed with 0 as octal numbers. They will be parsed as strings as of 6.0. Use "%s" to represent the octal number.', '-0o' . substr($scalar, 2));
606 return -octdec(substr($scalar, 1));
607 }
608 $cast = (int) $scalar;
609 return $scalar === (string) $cast ? $cast : $scalar;
610 case is_numeric($scalar):
611 case Parser::preg_match(self::getHexRegex(), $scalar):
612 $scalar = str_replace('_', '', $scalar);
613 return '0x' === $scalar[0] . $scalar[1] ? hexdec($scalar) : (float) $scalar;
614 case '.inf' === $scalarLower:
615 case '.nan' === $scalarLower:
616 return -log(0);
617 case '-.inf' === $scalarLower:
618 return log(0);
619 case Parser::preg_match('/^(-|\+)?[0-9][0-9_]*(\.[0-9_]+)?$/', $scalar):
620 return (float) str_replace('_', '', $scalar);
621 case Parser::preg_match(self::getTimestampRegex(), $scalar):
622 try {
623 // When no timezone is provided in the parsed date, YAML spec says we must assume UTC.
624 $time = new \DateTime($scalar, new \DateTimeZone('UTC'));
625 } catch (\Exception $e) {
626 // Some dates accepted by the regex are not valid dates.
627 throw new ParseException(\sprintf('The date "%s" could not be parsed as it is an invalid date.', $scalar), self::$parsedLineNumber + 1, $scalar, self::$parsedFilename, $e);
628 }
629 if (Yaml::PARSE_DATETIME & $flags) {
630 return $time;
631 }
632 try {
633 if (\false !== $scalar = $time->getTimestamp()) {
634 return $scalar;
635 }
636 } catch (\ValueError $e) {
637 // no-op
638 }
639 return $time->format('U');
640 }
641 }
642 return (string) $scalar;
643 }
644 private static function parseTag(string $value, int &$i, int $flags): ?string
645 {
646 if ('!' !== $value[$i]) {
647 return null;
648 }
649 $tagLength = strcspn($value, " \t\n[]{},", $i + 1);
650 $tag = substr($value, $i + 1, $tagLength);
651 $nextOffset = $i + $tagLength + 1;
652 $nextOffset += strspn($value, ' ', $nextOffset);
653 if ('' === $tag && (!isset($value[$nextOffset]) || \in_array($value[$nextOffset], [']', '}', ','], \true))) {
654 throw new ParseException('Using the unquoted scalar value "!" is not supported. You must quote it.', self::$parsedLineNumber + 1, $value, self::$parsedFilename);
655 }
656 // Is followed by a scalar and is a built-in tag
657 if ('' !== $tag && (!isset($value[$nextOffset]) || !\in_array($value[$nextOffset], ['[', '{'], \true)) && ('!' === $tag[0] || 'str' === $tag || 'php/const' === $tag || 'php/object' === $tag)) {
658 // Manage in {@link self::evaluateScalar()}
659 return null;
660 }
661 $i = $nextOffset;
662 // Built-in tags
663 if ('' !== $tag && '!' === $tag[0]) {
664 throw new ParseException(sprintf('The built-in tag "!%s" is not implemented.', $tag), self::$parsedLineNumber + 1, $value, self::$parsedFilename);
665 }
666 if ('' !== $tag && !isset($value[$i])) {
667 throw new ParseException(sprintf('Missing value for tag "%s".', $tag), self::$parsedLineNumber + 1, $value, self::$parsedFilename);
668 }
669 if ('' === $tag || Yaml::PARSE_CUSTOM_TAGS & $flags) {
670 return $tag;
671 }
672 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);
673 }
674 public static function evaluateBinaryScalar(string $scalar): string
675 {
676 $parsedBinaryData = self::parseScalar(preg_replace('/\s/', '', $scalar));
677 if (0 !== \strlen($parsedBinaryData) % 4) {
678 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);
679 }
680 if (!Parser::preg_match('#^[A-Z0-9+/]+={0,2}$#i', $parsedBinaryData)) {
681 throw new ParseException(sprintf('The base64 encoded data (%s) contains invalid characters.', $parsedBinaryData), self::$parsedLineNumber + 1, $scalar, self::$parsedFilename);
682 }
683 return base64_decode($parsedBinaryData, \true);
684 }
685 private static function isBinaryString(string $value): bool
686 {
687 return !preg_match('//u', $value) || preg_match('/[^\x00\x07-\x0d\x1B\x20-\xff]/', $value);
688 }
689 /**
690 * Gets a regex that matches a YAML date.
691 *
692 * @see http://www.yaml.org/spec/1.2/spec.html#id2761573
693 */
694 private static function getTimestampRegex(): string
695 {
696 return <<<EOF
697 ~^
698 (?P<year>[0-9][0-9][0-9][0-9])
699 -(?P<month>[0-9][0-9]?)
700 -(?P<day>[0-9][0-9]?)
701 (?:(?:[Tt]|[ \t]+)
702 (?P<hour>[0-9][0-9]?)
703 :(?P<minute>[0-9][0-9])
704 :(?P<second>[0-9][0-9])
705 (?:\\.(?P<fraction>[0-9]*))?
706 (?:[ \t]*(?P<tz>Z|(?P<tz_sign>[-+])(?P<tz_hour>[0-9][0-9]?)
707 (?::(?P<tz_minute>[0-9][0-9]))?))?)?
708 \$~x
709 EOF;
710 }
711 /**
712 * Gets a regex that matches a YAML number in hexadecimal notation.
713 */
714 private static function getHexRegex(): string
715 {
716 return '~^0x[0-9a-f_]++$~i';
717 }
718 }
719