@@ -20,8 +20,7 @@ public static function parseDictionary(string $string): Dictionary
20
20
while (true ) {
21
21
$ key = self ::parseKey ($ input );
22
22
23
- if ($ input ->isChar ('= ' )) {
24
- $ input ->consumeChar ();
23
+ if ($ input ->skipNextCharIf ('= ' )) {
25
24
$ value ->{$ key } = self ::parseItemOrInnerList ($ input );
26
25
} else {
27
26
// Bare boolean true value.
@@ -85,7 +84,7 @@ public static function parseList(string $string): OuterList
85
84
86
85
private static function parseItemOrInnerList (ParsingInput $ input ): TupleInterface
87
86
{
88
- if ($ input ->isChar ('( ' )) {
87
+ if ($ input ->isNextChar ('( ' )) {
89
88
return self ::parseInnerList ($ input );
90
89
} else {
91
90
return self ::doParseItem ($ input );
@@ -104,8 +103,7 @@ private static function parseInnerList(ParsingInput $input): InnerList
104
103
while (!$ input ->empty ()) {
105
104
$ input ->trim ();
106
105
107
- if ($ input ->isChar (') ' )) {
108
- $ input ->consumeChar ();
106
+ if ($ input ->skipNextCharIf (') ' )) {
109
107
return new InnerList (
110
108
$ value ,
111
109
self ::parseParameters ($ input )
@@ -114,7 +112,7 @@ private static function parseInnerList(ParsingInput $input): InnerList
114
112
115
113
$ value [] = self ::doParseItem ($ input );
116
114
117
- if (!($ input ->isChar (' ' ) || $ input ->isChar (') ' ))) {
115
+ if (!($ input ->isNextChar (' ' ) || $ input ->isNextChar (') ' ))) {
118
116
if ($ input ->empty ()) {
119
117
break ;
120
118
}
@@ -126,8 +124,6 @@ private static function parseInnerList(ParsingInput $input): InnerList
126
124
}
127
125
128
126
/**
129
- * @param string $string
130
- *
131
127
* @return Item
132
128
* A [value, parameters] tuple.
133
129
*/
@@ -190,16 +186,15 @@ private static function parseBareItem(ParsingInput $input): mixed
190
186
private static function parseParameters (ParsingInput $ input ): Parameters
191
187
{
192
188
$ parameters = new Parameters ();
193
- while ($ input ->isChar ('; ' )) {
194
- $ input ->consumeChar ();
189
+ while ($ input ->skipNextCharIf ('; ' )) {
195
190
$ input ->trim ();
196
191
197
192
$ key = self ::parseKey ($ input );
198
- $ parameters ->{$ key } = true ;
199
193
200
- if ($ input ->isChar ('= ' )) {
201
- $ input ->consumeChar ();
194
+ if ($ input ->skipNextCharIf ('= ' )) {
202
195
$ parameters ->{$ key } = self ::parseBareItem ($ input );
196
+ } else {
197
+ $ parameters ->{$ key } = true ;
203
198
}
204
199
}
205
200
@@ -275,7 +270,7 @@ private static function parseString(ParsingInput $input): string
275
270
}
276
271
} elseif ($ char === '" ' ) {
277
272
return $ output ;
278
- } elseif (ord ($ char ) <= 0x1f || ord ( $ char ) >= 0x7f ) {
273
+ } elseif (! ctype_print ($ char )) {
279
274
throw new ParseException ('Invalid character in string at position ' . ($ input ->position () - 1 ));
280
275
}
281
276
@@ -301,18 +296,21 @@ private static function parseDisplayString(ParsingInput $string): DisplayString
301
296
while (!$ string ->empty ()) {
302
297
$ char = $ string ->consumeChar ();
303
298
304
- if (ord ($ char ) <= 0x1f || ord ( $ char ) >= 0x7f ) {
299
+ if (! ctype_print ($ char )) {
305
300
throw new ParseException (
306
301
'Invalid character in display string at position ' . ($ string ->position () - 1 )
307
302
);
308
303
} elseif ($ char === '% ' ) {
309
- try {
310
- $ encodedString .= '% ' . $ string ->consumeRegex ('/^[0-9a-f]{2}/ ' );
311
- } catch (\RuntimeException ) {
304
+ if ($ string ->remainingLength () < 2 ) {
305
+ break ;
306
+ }
307
+ $ encodedChar = $ string ->consume (2 );
308
+ if (!ctype_xdigit ($ encodedChar ) || ctype_upper ($ encodedChar )) {
312
309
throw new ParseException (
313
310
'Invalid hex values in display string at position ' . ($ string ->position () - 1 )
314
311
);
315
312
}
313
+ $ encodedString .= '% ' . $ encodedChar ;
316
314
} elseif ($ char === '" ' ) {
317
315
$ displayString = new DisplayString (rawurldecode ($ encodedString ));
318
316
// An invalid UTF-8 subject will cause the preg_* function to match nothing.
@@ -334,16 +332,19 @@ private static function parseDisplayString(ParsingInput $string): DisplayString
334
332
*/
335
333
private static function parseToken (ParsingInput $ input ): Token
336
334
{
337
- // Hypertext Transfer Protocol (HTTP/1.1): Message Syntax and Routing
338
- // 3.2.6. Field Value Components
339
- // @see https://tools.ietf.org/html/rfc7230#section-3.2.6
340
- $ tchar = preg_quote ( "!#$%&'*+-.^_`|~ " ) ;
335
+ // RFC 9110: HTTP Semantics (5.6.2. Tokens)
336
+ // @see https://www.rfc-editor.org/rfc/rfc9110.html#name-tokens
337
+ // $tchar = preg_quote("!#$%&'*+-.^_`|~");
338
+ $ tchar = "!#$%&'*+\ -.^_`|~ " ;
341
339
342
340
// parseToken is only called by parseBareItem if the initial character
343
341
// is valid, so a Token object is always returned. If there is an
344
342
// invalid character in the token, the public function that was called
345
343
// will detect that the remainder of the input string is invalid.
346
- return new Token ($ input ->consumeRegex ('/^([a-z*][a-z0-9:\/ ' . $ tchar . ']*)/i ' ));
344
+ return new Token ($ input ->consumeRegex ('/^(
345
+ (?:\*|[a-z]) # an alphabetic character or "*"
346
+ [a-z0-9:\/ ' . $ tchar . ']* # zero to many token characters
347
+ )/ix ' ));
347
348
}
348
349
349
350
/**
0 commit comments