diff --git a/src/DisplayString.php b/src/DisplayString.php new file mode 100644 index 0000000..4ff996c --- /dev/null +++ b/src/DisplayString.php @@ -0,0 +1,21 @@ +value = $value; + } + + public function __toString(): string + { + return $this->value; + } +} diff --git a/src/Parser.php b/src/Parser.php index f2e6a4a..38cbf35 100644 --- a/src/Parser.php +++ b/src/Parser.php @@ -169,6 +169,8 @@ private static function parseBareItem(string &$string) $value = self::parseBoolean($string); } elseif ($string[0] == '@') { $value = self::parseDate($string); + } elseif ($string[0] == '%') { + $value = self::parseDisplayString($string); } elseif (preg_match('/^([a-z*])/i', $string)) { $value = self::parseToken($string); } else { @@ -276,6 +278,39 @@ private static function parseString(string &$string): string throw new ParseException("Invalid end of string"); } + private static function parseDisplayString(string &$string): DisplayString + { + $string = substr($string, 1); + + $output_string = ''; + while (strlen($string)) { + $char = $string[0]; + $string = substr($string, 1); + + // @todo properly parse value + + if ($char == '\\') { + if ($string == '') { + throw new ParseException("Invalid end of string"); + } + + $char = $string[0]; + $string = substr($string, 1); + if ($char != '"' && $char != '\\') { + throw new ParseException('Invalid escaped character in string'); + } + } elseif ($char == '"') { + return new DisplayString($output_string); + } elseif (ord($char) <= 0x1f || ord($char) >= 0x7f) { + throw new ParseException('Invalid character in string'); + } + + $output_string .= $char; + } + + throw new ParseException("Invalid end of display string"); + } + private static function parseToken(string &$string): Token { // Hypertext Transfer Protocol (HTTP/1.1): Message Syntax and Routing diff --git a/src/Serializer.php b/src/Serializer.php index 87f9f7e..9ec8c03 100644 --- a/src/Serializer.php +++ b/src/Serializer.php @@ -162,6 +162,8 @@ private static function serializeBareItem($value): string return self::serializeByteSequence($value); } elseif ($value instanceof Date) { return self::serializeDate($value); + } elseif ($value instanceof DisplayString) { + return self::serializeDisplayString($value); } elseif (is_string($value) || (is_object($value) && method_exists($value, '__toString'))) { return self::serializeString((string) $value); } @@ -209,6 +211,12 @@ private static function serializeString(string $value): string return '"' . preg_replace('/(["\\\])/', '\\\$1', $value) . '"'; } + private static function serializeDisplayString(string $value): string + { + // @todo properly encode value. + return '%"' . $value . '"'; + } + private static function serializeToken(Token $value): string { // Hypertext Transfer Protocol (HTTP/1.1): Message Syntax and Routing diff --git a/tests/Httpwg/DisplayStringTest.php b/tests/Httpwg/DisplayStringTest.php new file mode 100644 index 0000000..f7b933e --- /dev/null +++ b/tests/Httpwg/DisplayStringTest.php @@ -0,0 +1,8 @@ +value)); case 'date': return new Date($data->value); + case 'displaystring': + return new DisplayString($data->value); } }