Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 749dfad

Browse files
committed
fix lexing strings containing escaped quotation characters
1 parent b60bb6e commit 749dfad

File tree

2 files changed

+89
-38
lines changed

2 files changed

+89
-38
lines changed

src/Symfony/Component/Yaml/Parser.php

Lines changed: 43 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -750,54 +750,54 @@ private function parseValue(string $value, int $flags, string $context)
750750
return Inline::parse($this->lexInlineSequence($cursor), $flags, $this->refs);
751751
}
752752

753-
$quotation = '' !== $value && ('"' === $value[0] || "'" === $value[0]) ? $value[0] : null;
754-
755-
// do not take following lines into account when the current line is a quoted single line value
756-
if (null !== $quotation && self::preg_match('/^'.$quotation.'.*'.$quotation.'(\s*#.*)?$/', $value)) {
757-
return Inline::parse($value, $flags, $this->refs);
758-
}
753+
switch ($value[0]) {
754+
case '"':
755+
case "'":
756+
$cursor = \strlen($this->currentLine) - \strlen($value);
757+
$parsedValue = Inline::parse($this->lexInlineQuotedString($cursor), $flags, $this->refs);
758+
759+
if (isset($this->currentLine[$cursor]) && preg_replace('/\s*#.*$/A', '', substr($this->currentLine, $cursor))) {
760+
throw new ParseException(sprintf('Unexpected characters near "%s".', substr($this->currentLine, $cursor)));
761+
}
759762

760-
$lines = [];
763+
return $parsedValue;
764+
default:
765+
$lines = [];
761766

762-
while ($this->moveToNextLine()) {
763-
// unquoted strings end before the first unindented line
764-
if (null === $quotation && 0 === $this->getCurrentLineIndentation()) {
765-
$this->moveToPreviousLine();
767+
while ($this->moveToNextLine()) {
768+
// unquoted strings end before the first unindented line
769+
if (0 === $this->getCurrentLineIndentation()) {
770+
$this->moveToPreviousLine();
766771

767-
break;
768-
}
772+
break;
773+
}
769774

770-
$lines[] = trim($this->currentLine);
775+
$lines[] = trim($this->currentLine);
776+
}
771777

772-
// quoted string values end with a line that is terminated with the quotation character
773-
$escapedLine = str_replace(['\\\\', '\\"'], '', $this->currentLine);
774-
if ('' !== $escapedLine && substr($escapedLine, -1) === $quotation) {
775-
break;
776-
}
777-
}
778+
for ($i = 0, $linesCount = \count($lines), $previousLineBlank = false; $i < $linesCount; ++$i) {
779+
if ('' === $lines[$i]) {
780+
$value .= "\n";
781+
$previousLineBlank = true;
782+
} elseif ($previousLineBlank) {
783+
$value .= $lines[$i];
784+
$previousLineBlank = false;
785+
} else {
786+
$value .= ' '.$lines[$i];
787+
$previousLineBlank = false;
788+
}
789+
}
778790

779-
for ($i = 0, $linesCount = \count($lines), $previousLineBlank = false; $i < $linesCount; ++$i) {
780-
if ('' === $lines[$i]) {
781-
$value .= "\n";
782-
$previousLineBlank = true;
783-
} elseif ($previousLineBlank) {
784-
$value .= $lines[$i];
785-
$previousLineBlank = false;
786-
} else {
787-
$value .= ' '.$lines[$i];
788-
$previousLineBlank = false;
789-
}
790-
}
791+
Inline::$parsedLineNumber = $this->getRealCurrentLineNb();
791792

792-
Inline::$parsedLineNumber = $this->getRealCurrentLineNb();
793+
$parsedValue = Inline::parse($value, $flags, $this->refs);
793794

794-
$parsedValue = Inline::parse($value, $flags, $this->refs);
795+
if ('mapping' === $context && \is_string($parsedValue) && '"' !== $value[0] && "'" !== $value[0] && '[' !== $value[0] && '{' !== $value[0] && '!' !== $value[0] && false !== strpos($parsedValue, ': ')) {
796+
throw new ParseException('A colon cannot be used in an unquoted mapping value.', $this->getRealCurrentLineNb() + 1, $value, $this->filename);
797+
}
795798

796-
if ('mapping' === $context && \is_string($parsedValue) && '"' !== $value[0] && "'" !== $value[0] && '[' !== $value[0] && '{' !== $value[0] && '!' !== $value[0] && false !== strpos($parsedValue, ': ')) {
797-
throw new ParseException('A colon cannot be used in an unquoted mapping value.', $this->getRealCurrentLineNb() + 1, $value, $this->filename);
799+
return $parsedValue;
798800
}
799-
800-
return $parsedValue;
801801
} catch (ParseException $e) {
802802
$e->setParsedLine($this->getRealCurrentLineNb() + 1);
803803
$e->setSnippet($this->currentLine);
@@ -1154,8 +1154,13 @@ private function lexInlineQuotedString(int &$cursor = 0): string
11541154

11551155
$previousLineWasNewline = true;
11561156
$previousLineWasTerminatedWithBackslash = false;
1157+
$lineNumber = 0;
11571158

11581159
do {
1160+
if (++$lineNumber > 1) {
1161+
$cursor += strspn($this->currentLine, ' ', $cursor);
1162+
}
1163+
11591164
if ($this->isCurrentLineBlank()) {
11601165
$value .= "\n";
11611166
} elseif (!$previousLineWasNewline && !$previousLineWasTerminatedWithBackslash) {

src/Symfony/Component/Yaml/Tests/ParserTest.php

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1570,6 +1570,52 @@ public function testParseMultiLineUnquotedString()
15701570
$this->assertSame(['foo' => 'bar baz foobar foo', 'bar' => 'baz'], $this->parser->parse($yaml));
15711571
}
15721572

1573+
/**
1574+
* @dataProvider escapedQuotationCharactersInQuotedStrings
1575+
*/
1576+
public function testParseQuotedStringContainingEscapedQuotationCharacters(string $yaml, array $expected)
1577+
{
1578+
$this->assertSame($expected, $this->parser->parse($yaml));
1579+
}
1580+
1581+
public function escapedQuotationCharactersInQuotedStrings()
1582+
{
1583+
return [
1584+
'single quoted string' => [
1585+
<<<YAML
1586+
entries:
1587+
- message: 'No emails received before timeout - Address: ''[email protected]''
1588+
Keyword: ''Your Order confirmation'' ttl: 50'
1589+
outcome: failed
1590+
YAML,
1591+
[
1592+
'entries' => [
1593+
[
1594+
'message' => 'No emails received before timeout - Address: \'[email protected]\' Keyword: \'Your Order confirmation\' ttl: 50',
1595+
'outcome' => 'failed',
1596+
],
1597+
],
1598+
],
1599+
],
1600+
'double quoted string' => [
1601+
<<<YAML
1602+
entries:
1603+
- message: "No emails received before timeout - Address: \"[email protected]\"
1604+
Keyword: \"Your Order confirmation\" ttl: 50"
1605+
outcome: failed
1606+
YAML,
1607+
[
1608+
'entries' => [
1609+
[
1610+
'message' => 'No emails received before timeout - Address: "[email protected]" Keyword: "Your Order confirmation" ttl: 50',
1611+
'outcome' => 'failed',
1612+
],
1613+
],
1614+
],
1615+
],
1616+
];
1617+
}
1618+
15731619
public function testParseMultiLineString()
15741620
{
15751621
$this->assertEquals("foo bar\nbaz", $this->parser->parse("foo\nbar\n\nbaz"));

0 commit comments

Comments
 (0)