@@ -20,8 +20,7 @@ public static function parseDictionary(string $string): Dictionary
2020 while (true ) {
2121 $ key = self ::parseKey ($ input );
2222
23- if ($ input ->isChar ('= ' )) {
24- $ input ->consumeChar ();
23+ if ($ input ->skipNextCharIf ('= ' )) {
2524 $ value ->{$ key } = self ::parseItemOrInnerList ($ input );
2625 } else {
2726 // Bare boolean true value.
@@ -85,7 +84,7 @@ public static function parseList(string $string): OuterList
8584
8685 private static function parseItemOrInnerList (ParsingInput $ input ): TupleInterface
8786 {
88- if ($ input ->isChar ('( ' )) {
87+ if ($ input ->isNextChar ('( ' )) {
8988 return self ::parseInnerList ($ input );
9089 } else {
9190 return self ::doParseItem ($ input );
@@ -104,8 +103,7 @@ private static function parseInnerList(ParsingInput $input): InnerList
104103 while (!$ input ->empty ()) {
105104 $ input ->trim ();
106105
107- if ($ input ->isChar (') ' )) {
108- $ input ->consumeChar ();
106+ if ($ input ->skipNextCharIf (') ' )) {
109107 return new InnerList (
110108 $ value ,
111109 self ::parseParameters ($ input )
@@ -114,7 +112,7 @@ private static function parseInnerList(ParsingInput $input): InnerList
114112
115113 $ value [] = self ::doParseItem ($ input );
116114
117- if (!($ input ->isChar (' ' ) || $ input ->isChar (') ' ))) {
115+ if (!($ input ->isNextChar (' ' ) || $ input ->isNextChar (') ' ))) {
118116 if ($ input ->empty ()) {
119117 break ;
120118 }
@@ -126,8 +124,6 @@ private static function parseInnerList(ParsingInput $input): InnerList
126124 }
127125
128126 /**
129- * @param string $string
130- *
131127 * @return Item
132128 * A [value, parameters] tuple.
133129 */
@@ -190,16 +186,15 @@ private static function parseBareItem(ParsingInput $input): mixed
190186 private static function parseParameters (ParsingInput $ input ): Parameters
191187 {
192188 $ parameters = new Parameters ();
193- while ($ input ->isChar ('; ' )) {
194- $ input ->consumeChar ();
189+ while ($ input ->skipNextCharIf ('; ' )) {
195190 $ input ->trim ();
196191
197192 $ key = self ::parseKey ($ input );
198- $ parameters ->{$ key } = true ;
199193
200- if ($ input ->isChar ('= ' )) {
201- $ input ->consumeChar ();
194+ if ($ input ->skipNextCharIf ('= ' )) {
202195 $ parameters ->{$ key } = self ::parseBareItem ($ input );
196+ } else {
197+ $ parameters ->{$ key } = true ;
203198 }
204199 }
205200
@@ -275,7 +270,7 @@ private static function parseString(ParsingInput $input): string
275270 }
276271 } elseif ($ char === '" ' ) {
277272 return $ output ;
278- } elseif (ord ($ char ) <= 0x1f || ord ( $ char ) >= 0x7f ) {
273+ } elseif (! ctype_print ($ char )) {
279274 throw new ParseException ('Invalid character in string at position ' . ($ input ->position () - 1 ));
280275 }
281276
@@ -301,18 +296,21 @@ private static function parseDisplayString(ParsingInput $string): DisplayString
301296 while (!$ string ->empty ()) {
302297 $ char = $ string ->consumeChar ();
303298
304- if (ord ($ char ) <= 0x1f || ord ( $ char ) >= 0x7f ) {
299+ if (! ctype_print ($ char )) {
305300 throw new ParseException (
306301 'Invalid character in display string at position ' . ($ string ->position () - 1 )
307302 );
308303 } 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 )) {
312309 throw new ParseException (
313310 'Invalid hex values in display string at position ' . ($ string ->position () - 1 )
314311 );
315312 }
313+ $ encodedString .= '% ' . $ encodedChar ;
316314 } elseif ($ char === '" ' ) {
317315 $ displayString = new DisplayString (rawurldecode ($ encodedString ));
318316 // An invalid UTF-8 subject will cause the preg_* function to match nothing.
@@ -334,16 +332,19 @@ private static function parseDisplayString(ParsingInput $string): DisplayString
334332 */
335333 private static function parseToken (ParsingInput $ input ): Token
336334 {
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 = "!#$%&'*+\ -.^_`|~ " ;
341339
342340 // parseToken is only called by parseBareItem if the initial character
343341 // is valid, so a Token object is always returned. If there is an
344342 // invalid character in the token, the public function that was called
345343 // 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 ' ));
347348 }
348349
349350 /**
0 commit comments