8000 [Yaml] add support for parsing the !!binary tag · symfony/symfony@ae6f141 · GitHub
[go: up one dir, main page]

Skip to content

Commit ae6f141

Browse files
committed
[Yaml] add support for parsing the !!binary tag
1 parent ff87f30 commit ae6f141

File tree

5 files changed

+154
-2
lines changed

5 files changed

+154
-2
lines changed

src/Symfony/Component/Yaml/CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ CHANGELOG
44
3.1.0
55
-----
66

7+
* Added support for parsing base64 encoded binary data when they are tagged
8+
with the `!!binary` tag.
9+
710
* Added support for parsing timestamps as `\DateTime` objects:
811

912
```php

src/Symfony/Component/Yaml/Inline.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -576,6 +576,8 @@ private static function evaluateScalar($scalar, $flags, $references = array())
576576
return -log(0);
577577
case '-.inf' === $scalarLower:
578578
return log(0);
579+
case 0 === strpos($scalar, '!!binary '):
580+
return self::evaluateBinaryScalar(substr($scalar, 9));
579581
case preg_match('/^(-|\+)?[0-9,]+(\.[0-9]+)?$/', $scalar):
580582
return (float) str_replace(',', '', $scalar);
581583
case preg_match(self::getTimestampRegex(), $scalar):
@@ -595,6 +597,28 @@ private static function evaluateScalar($scalar, $flags, $references = array())
595597
}
596598
}
597599

600+
/**
601+
* @param string $scalar
602+
*
603+
* @return string
604+
*
605+
* @internal
606+
*/
607+
public static function evaluateBinaryScalar($scalar)
608+
{
609+
$parsedBinaryData = self::parseScalar(preg_replace('/\s/', '', $scalar));
610+
611+
if (0 !== (strlen($parsedBinaryData) % 4)) {
612+
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)));
613+
}
614+
615+
if (!preg_match('#^[A-Z0-9+/]+={0,2}$#i', $parsedBinaryData)) {
616+
throw new ParseException(sprintf('The base64 encoded data (%s) contains invalid characters.', $parsedBinaryData));
617+
}
618+
619+
return base64_decode($parsedBinaryData, true);
620+
}
621+
598622
/**
599623
* Gets a regex that matches a YAML date.
600624
*

src/Symfony/Component/Yaml/Parser.php

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
*/
2121
class Parser
2222
{
23+
const TAG_PATTERN = '((?P<tag>![\w!.\/:-]+) +)?';
2324
const BLOCK_SCALAR_HEADER_PATTERN = '(?P<separator>\||>)(?P<modifiers>\+|\-|\d+|\+\d+|\-\d+|\d+\+|\d+\-)?(?P<comments> +#.*)?';
2425

2526
private $offset = 0;
@@ -516,10 +517,16 @@ private function parseValue($value, $flags, $context)
516517
return $this->refs[$value];
517518
}
518519

519-
if (preg_match('/^'.self::BLOCK_SCALAR_HEADER_PATTERN.'$/', $value, $matches)) {
520+
if (preg_match('/^'.self::TAG_PATTERN.self::BLOCK_SCALAR_HEADER_PATTERN.'$/', $value, $matches)) {
520521
$modifiers = isset($matches['modifiers']) ? $matches['modifiers'] : '';
521522

522-
return $this->parseBlockScalar($matches['separator'], preg_replace('#\d+#', '', $modifiers), (int) abs($modifiers));
523+
$data = $this->parseBlockScalar($matches['separator'], preg_replace('#\d+#', '', $modifiers), (int) abs($modifiers));
524+
525+
if (isset($matches['tag']) && '!!binary' === $matches['tag']) {
526+
return Inline::evaluateBinaryScalar($data);
527+
}
528+
529+
return $data;
523530
}
524531

525532
try {

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

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -532,4 +532,41 @@ public function getDateTimeDumpTests()
532532

533533
return $tests;
534534
}
535+
536+
/**
537+
* @dataProvider getBinaryData
538+
*/
539+
public function testParseBinaryData($data)
540+
{
541+
$this->assertSame('Hello world', Inline::parse($data));
542+
}
543+
544+
public function getBinaryData()
545+
{
546+
return array(
547+
'enclosed with double quotes' => array('!!binary "SGVsbG8gd29ybGQ="'),
548+
'enclosed with single quotes' => array("!!binary 'SGVsbG8gd29ybGQ='"),
549+
'containing spaces' => array('!!binary "SGVs bG8gd 29ybGQ="'),
550+
);
551+
}
552+
553+
/**
554+
* @dataProvider getInvalidBinaryData
555+
*/
556+
public function testParseInvalidBinaryData($data, $expectedMessage)
557+
{
558+
$this->setExpectedExceptionRegExp('\Symfony\Component\Yaml\Exception\ParseException', $expectedMessage);
559+
560+
Inline::parse($data);
561+
}
562+
563+
public function getInvalidBinaryData()
564+
{
565+
return array(
566+
'length not a multiple of four' => array('!!binary "SGVsbG8d29ybGQ="', '/The normalized base64 encoded data \(data without whitespace characters\) length must be a multiple of four \(\d+ bytes given\)/'),
567+
'invalid characters' => array('!!binary "SGVsbG8#d29ybGQ="', '/The base64 encoded data \(.*\) contains invalid characters/'),
568+
'too many equals characters' => array('!!binary "SGVsbG8gd29yb==="', '/The base64 encoded data \(.*\) contains invalid characters/'),
569+
'misplaced equals character' => array('!!binary "SGVsbG8gd29ybG=Q"', '/The base64 encoded data \(.*\) contains invalid characters/'),
570+
);
571+
}
535572
}

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

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1120,6 +1120,87 @@ public function testAdditionallyIndentedLinesAreParsedAsNewLinesInFoldedBlocks()
11201120
$this->parser->parse($yaml)
11211121
);
11221122
}
1123+
1124+
/**
1125+
* @dataProvider getBinaryData
1126+
*/
1127+
public function testParseBinaryData($data)
1128+
{
1129+
$this->assertSame(array('data' => 'Hello world'), $this->parser->parse($data));
1130+
}
1131+
1132+
public function getBinaryData()
1133+
{
1134+
return array(
1135+
'enclosed with double quotes' => array('data: !!binary "SGVsbG8gd29ybGQ="'),
1136+
'enclosed with single quotes' => array("data: !!binary 'SGVsbG8gd29ybGQ='"),
1137+
'containing spaces' => array('data: !!binary "SGVs bG8gd 29ybGQ="'),
1138+
'in block scalar' => array(
1139+
<<<EOT
1140+
data: !!binary |
1141+
SGVsbG8gd29ybGQ=
1142+
EOT
1143+
),
1144+
'containing spaces in block scalar' => array(
1145+
<<<EOT
1146+
data: !!binary |
1147+
SGVs bG8gd 29ybGQ=
1148+
EOT
1149+
),
1150+
);
1151+
}
1152+
1153+
/**
1154+
* @dataProvider getInvalidBinaryData
1155+
*/
1156+
public function testParseInvalidBinaryData($data, $expectedMessage)
1157+
{
1158+
$this->setExpectedExceptionRegExp('\Symfony\Component\Yaml\Exception\ParseException', $expectedMessage);
1159+
1160+
$this->parser->parse($data);
1161+
}
1162+
1163+
public function getInvalidBinaryData()
1164+
{
1165+
return array(
1166+
'length not a multiple of four' => array('data: !!binary "SGVsbG8d29ybGQ="', '/The normalized base64 encoded data \(data without whitespace characters\) length must be a multiple of four \(\d+ bytes given\)/'),
1167+
'invalid characters' => array('!!binary "SGVsbG8#d29ybGQ="', '/The base64 encoded data \(.*\) contains invalid characters/'),
1168+
'too many equals characters' => array('data: !!binary "SGVsbG8gd29yb==="', '/The base64 encoded data \(.*\) contains invalid characters/'),
1169+
'misplaced equals character' => array('data: !!binary "SGVsbG8gd29ybG=Q"', '/The base64 encoded data \(.*\) contains invalid characters/'),
1170+
'length not a multiple of four in block scalar' => array(
1171+
<<<EOT
1172+
data: !!binary |
1173+
SGVsbG8d29ybGQ=
1174+
EOT
1175+
,
1176+
'/The normalized base64 encoded data \(data without whitespace characters\) length must be a multiple of four \(\d+ bytes given\)/',
1177+
),
1178+
'invalid characters in block scalar' => array(
1179+
<<<EOT
1180+
data: !!binary |
1181+
SGVsbG8#d29ybGQ=
1182+
EOT
1183+
,
1184+
'/The base64 encoded data \(.*\) contains invalid characters/',
1185+
),
1186+
'too many equals characters in block scalar' => array(
1187+
<<<EOT
1188+
data: !!binary |
1189+
SGVsbG8gd29yb===
1190+
EOT
1191+
,
1192+
'/The base64 encoded data \(.*\) contains invalid characters/',
1193+
),
1194+
'misplaced equals character in block scalar' => array(
1195+
<<<EOT
1196+
data: !!binary |
1197+
SGVsbG8gd29ybG=Q
1198+
EOT
1199+
,
1200+
'/The base64 encoded data \(.*\) contains invalid characters/',
1201+
),
1202+
);
1203+
}
11231204
}
11241205

11251206
class B

0 commit comments

Comments
 (0)
0