Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 308231a

Browse filesBrowse files
committed
bug #33763 [Yaml] fix lexing nested sequences/mappings (xabbuh)
This PR was merged into the 4.4 branch. Discussion ---------- [Yaml] fix lexing nested sequences/mappings | Q | A | ------------- | --- | Branch? | 4.4 | Bug fix? | yes | New feature? | no | Deprecations? | no | Tickets | #34805, #37788, #37876, #39011, #39013, #39064 | License | MIT | Doc PR | Commits ------- 4c15f80 fix lexing nested sequences/mappings
2 parents 1f0a27a + 4c15f80 commit 308231a
Copy full SHA for 308231a

File tree

Expand file treeCollapse file tree

2 files changed

+303
-68
lines changed
Filter options
Expand file treeCollapse file tree

2 files changed

+303
-68
lines changed

‎src/Symfony/Component/Yaml/Parser.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/Yaml/Parser.php
+119-68Lines changed: 119 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -355,7 +355,7 @@ private function doParse(string $value, int $flags)
355355
}
356356

357357
try {
358-
return Inline::parse($this->parseQuotedString($this->currentLine), $flags, $this->refs);
358+
return Inline::parse($this->lexInlineQuotedString(), $flags, $this->refs);
359359
} catch (ParseException $e) {
360360
$e->setParsedLine($this->getRealCurrentLineNb() + 1);
361361
$e->setSnippet($this->currentLine);
@@ -368,7 +368,7 @@ private function doParse(string $value, int $flags)
368368
}
369369

370370
try {
371-
$parsedMapping = Inline::parse($this->lexInlineMapping($this->currentLine), $flags, $this->refs);
371+
$parsedMapping = Inline::parse($this->lexInlineMapping(), $flags, $this->refs);
372372

373373
while ($this->moveToNextLine()) {
374374
if (!$this->isCurrentLineEmpty()) {
@@ -389,7 +389,7 @@ private function doParse(string $value, int $flags)
389389
}
390390

391391
try {
392-
$parsedSequence = Inline::parse($this->lexInlineSequence($this->currentLine), $flags, $this->refs);
392+
$parsedSequence = Inline::parse($this->lexInlineSequence(), $flags, $this->refs);
393393

394394
while ($this->moveToNextLine()) {
395395
if (!$this->isCurrentLineEmpty()) {
@@ -659,6 +659,11 @@ private function getNextEmbedBlock(int $indentation = null, bool $inSequence = f
659659
return implode("\n", $data);
660660
}
661661

662+
private function hasMoreLines(): bool
663+
{
664+
return (\count($this->lines) - 1) > $this->currentLineNb;
665+
}
666+
662667
/**
663668
* Moves the parser to the next line.
664669
*/
@@ -736,9 +741,13 @@ private function parseValue(string $value, int $flags, string $context)
736741

737742
try {
738743
if ('' !== $value && '{' === $value[0]) {
739-
return Inline::parse($this->lexInlineMapping($value), $flags, $this->refs);
744+
$cursor = \strlen($this->currentLine) - \strlen($value);
745+
746+
return Inline::parse($this->lexInlineMapping($cursor), $flags, $this->refs);
740747
} elseif ('' !== $value && '[' === $value[0]) {
741-
return Inline::parse($this->lexInlineSequence($value), $flags, $this->refs);
748+
$cursor = \strlen($this->currentLine) - \strlen($value);
749+
750+
return Inline::parse($this->lexInlineSequence($cursor), $flags, $this->refs);
742751
}
743752

744753
$quotation = '' !== $value && ('"' === $value[0] || "'" === $value[0]) ? $value[0] : null;
@@ -1137,106 +1146,148 @@ private function getLineTag(string $value, int $flags, bool $nextLineCheck = tru
11371146
throw new ParseException(sprintf('Tags support is not enabled. You must use the flag "Yaml::PARSE_CUSTOM_TAGS" to use "%s".', $matches['tag']), $this->getRealCurrentLineNb() + 1, $value, $this->filename);
11381147
}
11391148

1140-
private function parseQuotedString(string $yaml): ?string
1149+
private function lexInlineQuotedString(int &$cursor = 0): string
11411150
{
1142-
if ('' === $yaml || ('"' !== $yaml[0] && "'" !== $yaml[0])) {
1143-
throw new \InvalidArgumentException(sprintf('"%s" is not a quoted string.', $yaml));
1144-
}
1151+
$quotation = $this->currentLine[$cursor];
1152+
$value = $quotation;
1153+
++$cursor;
11451154

1146-
$lines = [$yaml];
1147-
1148-
while ($this->moveToNextLine()) {
1149-
$lines[] = $this->currentLine;
1155+
$previousLineWasNewline = true;
1156+
$previousLineWasTerminatedWithBackslash = false;
11501157

1151-
if (!$this->isCurrentLineEmpty() && $yaml[0] === $this->currentLine[-1]) {
1152-
break;
1153-
}
1154-
}
1155-
1156-
$value = '';
1157-
1158-
for ($i = 0, $linesCount = \count($lines), $previousLineWasNewline = false, $previousLineWasTerminatedWithBackslash = false; $i < $linesCount; ++$i) {
1159-
if ('' === trim($lines[$i])) {
1158+
do {
1159+
if ($this->isCurrentLineBlank()) {
11601160
$value .= "\n";
11611161
} elseif (!$previousLineWasNewline && !$previousLineWasTerminatedWithBackslash) {
11621162
$value .= ' ';
11631163
}
11641164

1165-
if ('' !== trim($lines[$i]) && '\\' === substr($lines[$i], -1)) {
1166-
$value .= ltrim(substr($lines[$i], 0, -1));
1167-
} elseif ('' !== trim($lines[$i])) {
1168-
$value .= trim($lines[$i]);
1165+
for (; \strlen($this->currentLine) > $cursor; ++$cursor) {
1166+
switch ($this->currentLine[$cursor]) {
1167+
case '\\':
1168+
if (isset($this->currentLine[++$cursor])) {
1169+
$value .= '\\'.$this->currentLine[$cursor];
1170+
}
1171+
1172+
break;
1173+
case $quotation:
1174+
++$cursor;
1175+
1176+
if ("'" === $quotation && isset($this->currentLine[$cursor]) && "'" === $this->currentLine[$cursor]) {
1177+
$value .= "''";
1178+
break;
1179+
}
1180+
1181+
return $value.$quotation;
1182+
default:
1183+
$value .= $this->currentLine[$cursor];
1184+
}
11691185
}
11701186

1171-
if ('' === trim($lines[$i])) {
1187+
if ($this->isCurrentLineBlank()) {
11721188
$previousLineWasNewline = true;
11731189
$previousLineWasTerminatedWithBackslash = false;
1174-
} elseif ('\\' === substr($lines[$i], -1)) {
1190+
} elseif ('\\' === $this->currentLine[-1]) {
11751191
$previousLineWasNewline = false;
11761192
$previousLineWasTerminatedWithBackslash = true;
11771193
} else {
11781194
$previousLineWasNewline = false;
11791195
$previousLineWasTerminatedWithBackslash = false;
11801196
}
1181-
}
11821197

1183-
return $value;
1198+
if ($this->hasMoreLines()) {
1199+
$cursor = 0;
1200+
}
1201+
} while ($this->moveToNextLine());
1202+
1203+
throw new ParseException('Malformed inline YAML string');
11841204
}
11851205

1186-
private function lexInlineMapping(string $yaml): string
1206+
private function lexUnquotedString(int &$cursor): string
11871207
{
1188-
if ('' === $yaml || '{' !== $yaml[0]) {
1189-
throw new \InvalidArgumentException(sprintf('"%s" is not a sequence.', $yaml));
1190-
}
1191-
1192-
for ($i = 1; isset($yaml[$i]) && '}' !== $yaml[$i]; ++$i) {
1193-
}
1208+
$offset = $cursor;
1209+
$cursor += strcspn($this->currentLine, '[]{},: ', $cursor);
11941210

1195-
if (isset($yaml[$i]) && '}' === $yaml[$i]) {
1196-
return $yaml;
1197-
}
1198-
1199-
$lines = [$yaml];
1200-
1201-
while ($this->moveToNextLine()) {
1202-
$lines[] = $this->currentLine;
1203-
}
1211+
return substr($this->currentLine, $offset, $cursor - $offset);
1212+
}
12041213

1205-
return implode("\n", $lines);
1214+
private function lexInlineMapping(int &$cursor = 0): string
1215+
{
1216+
return $this->lexInlineStructure($cursor, '}');
12061217
}
12071218

1208-
private function lexInlineSequence(string $yaml): string
1219+
private function lexInlineSequence(int &$cursor = 0): string
12091220
{
1210-
if ('' === $yaml || '[' !== $yaml[0]) {
1211-
throw new \InvalidArgumentException(sprintf('"%s" is not a sequence.', $yaml));
1212-
}
1221+
return $this->lexInlineStructure($cursor, ']');
1222+
}
12131223

1214-
for ($i = 1; isset($yaml[$i]) && ']' !== $yaml[$i]; ++$i) {
1215-
}
1224+
private function lexInlineStructure(int &$cursor, string $closingTag): string
1225+
{
1226+
$value = $this->currentLine[$cursor];
1227+
++$cursor;
12161228

1217-
if (isset($yaml[$i]) && ']' === $yaml[$i]) {
1218-
return $yaml;
1219-
}
1229+
do {
1230+
$this->consumeWhitespaces($cursor);
1231+
1232+
while (isset($this->currentLine[$cursor])) {
1233+
switch ($this->currentLine[$cursor]) {
1234+
case '"':
1235+
case "'":
1236+
$value .= $this->lexInlineQuotedString($cursor);
1237+
break;
1238+
case ':':
1239+
case ',':
1240+
$value .= $this->currentLine[$cursor];
1241+
++$cursor;
1242+
break;
1243+
case '{':
1244+
$value .= $this->lexInlineMapping($cursor);
1245+
break;
1246+
case '[':
1247+
$value .= $this->lexInlineSequence($cursor);
1248+
break;
1249+
case $closingTag:
1250+
$value .= $this->currentLine[$cursor];
1251+
++$cursor;
1252+
1253+
return $value;
1254+
case '#':
1255+
break 2;
1256+
default:
1257+
$value .= $this->lexUnquotedString($cursor);
1258+
}
12201259

1221-
$value = $yaml;
1260+
if ($this->consumeWhitespaces($cursor)) {
1261+
$value .= ' ';
1262+
}
1263+
}
12221264

1223-
while ($this->moveToNextLine()) {
1224-
for ($i = 1; isset($this->currentLine[$i]) && ']' !== $this->currentLine[$i]; ++$i) {
1265+
if ($this->hasMoreLines()) {
1266+
$cursor = 0;
12251267
}
1268+
} while ($this->moveToNextLine());
12261269

1227-
$trimmedValue = trim($this->currentLine);
1270+
throw new ParseException('Malformed inline YAML string');
1271+
}
12281272

1229-
if ('' !== $trimmedValue && '#' === $trimmedValue[0]) {
1230-
continue;
1231-
}
1273+
private function consumeWhitespaces(int &$cursor): bool
1274+
{
1275+
$whitespacesConsumed = 0;
12321276

1233-
$value .= $trimmedValue;
1277+
do {
1278+
$whitespaceOnlyTokenLength = strspn($this->currentLine, ' ', $cursor);
1279+
$whitespacesConsumed += $whitespaceOnlyTokenLength;
1280+
$cursor += $whitespaceOnlyTokenLength;
12341281

1235-
if (isset($this->currentLine[$i]) && ']' === $this->currentLine[$i]) {
1236-
break;
1282+
if (isset($this->currentLine[$cursor])) {
1283+
return 0 < $whitespacesConsumed;
12371284
}
1238-
}
12391285

1240-
return $value;
1286+
if ($this->hasMoreLines()) {
1287+
$cursor = 0;
1288+
}
1289+
} while ($this->moveToNextLine());
1290+
1291+
return 0 < $whitespacesConsumed;
12411292
}
12421293
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.