@@ -50,6 +50,7 @@ class ParserState
5050 * @var int
5151 */
5252 private $ iLineNo ;
53+ private $ sSelectorBuffer ;
5354
5455 /**
5556 * @param string $sText the complete CSS as text (i.e., usually the contents of a CSS file)
@@ -62,6 +63,7 @@ public function __construct($sText, Settings $oParserSettings, $iLineNo = 1)
6263 $ this ->iCurrentPosition = 0 ;
6364 $ this ->iLineNo = $ iLineNo ;
6465 $ this ->setCharset ($ this ->oParserSettings ->sDefaultCharset );
66+ $ this ->sSelectorBuffer = "" ;
6567 }
6668
6769 /**
@@ -126,6 +128,26 @@ public function setPosition($iPosition): void
126128 $ this ->iCurrentPosition = $ iPosition ;
127129 }
128130
131+ /**
132+ * @param int $iCount
133+ *
134+ * @return void
135+ */
136+ public function bufferForSelector ($ iCount )
137+ {
138+ $ this ->sSelectorBuffer .= $ this ->consume ($ iCount );
139+ }
140+
141+ /**
142+ * @return string
143+ */
144+ public function consumeSelectorBuffer ()
145+ {
146+ $ sResult = $ this ->sSelectorBuffer ;
147+ $ this ->sSelectorBuffer = "" ;
148+ return $ sResult ;
149+ }
150+
129151 /**
130152 * @param bool $bIgnoreCase
131153 *
@@ -166,7 +188,8 @@ public function parseIdentifier($bIgnoreCase = true)
166188 */
167189 public function parseCharacter ($ bIsForIdentifier )
168190 {
169- if ($ this ->peek () === '\\' ) {
191+ $ sPeekChar = $ this ->peek ();
192+ if ($ sPeekChar === '\\' ) {
170193 if (
171194 $ bIsForIdentifier && $ this ->oParserSettings ->bLenientParsing
172195 && ($ this ->comes ('\\0 ' ) || $ this ->comes ('\\9 ' ))
@@ -200,22 +223,25 @@ public function parseCharacter($bIsForIdentifier)
200223 }
201224 return \iconv ('utf-32le ' , $ this ->sCharset , $ sUtf32 );
202225 }
203- if ($ bIsForIdentifier ) {
204- $ peek = \ord ($ this ->peek ());
205- // Ranges: a-z A-Z 0-9 - _
206- if (
207- ($ peek >= 97 && $ peek <= 122 )
208- || ($ peek >= 65 && $ peek <= 90 )
209- || ($ peek >= 48 && $ peek <= 57 )
210- || ($ peek === 45 )
211- || ($ peek === 95 )
212- || ($ peek > 0xa1 )
213- ) {
214- return $ this ->consume (1 );
215- }
216- } else {
226+
227+ if (!$ bIsForIdentifier ) {
217228 return $ this ->consume (1 );
218229 }
230+
231+ $ peek = \ord ($ sPeekChar );
232+ // Ranges: a-z A-Z 0-9 - _
233+ //if (\preg_match('/[a-zA-Z0-9\-_]/', $sPeekChar) || \ord($sPeekChar) > 0xa1) {
234+ if (
235+ ($ peek >= 97 && $ peek <= 122 )
236+ || ($ peek >= 65 && $ peek <= 90 )
237+ || ($ peek >= 48 && $ peek <= 57 )
238+ || ($ peek === 45 )
239+ || ($ peek === 95 )
240+ || ($ peek > 0xa1 )
241+ ) {
242+ return $ this ->consume (1 );
243+ }
244+
219245 return null ;
220246 }
221247
@@ -232,15 +258,19 @@ public function consumeWhiteSpace(): array
232258 while (\preg_match ('/ \\s/isSu ' , $ this ->peek ()) === 1 ) {
233259 $ this ->consume (1 );
234260 }
235- if ($ this ->oParserSettings ->bLenientParsing ) {
236- try {
261+
262+ $ oComment = false ;
263+ if ($ this ->peek (1 ) == '/ ' && $ this ->peek (1 , 1 ) == '* ' ) {
264+ if ($ this ->oParserSettings ->bLenientParsing ) {
265+ try {
266+ $ oComment = $ this ->consumeComment ();
267+ } catch (UnexpectedEOFException $ e ) {
268+ $ this ->iCurrentPosition = $ this ->iLength ;
269+ return $ aComments ;
270+ }
271+ } else {
237272 $ oComment = $ this ->consumeComment ();
238- } catch (UnexpectedEOFException $ e ) {
239- $ this ->iCurrentPosition = $ this ->iLength ;
240- return $ aComments ;
241273 }
242- } else {
243- $ oComment = $ this ->consumeComment ();
244274 }
245275 if ($ oComment !== false ) {
246276 $ aComments [] = $ oComment ;
@@ -255,7 +285,17 @@ public function consumeWhiteSpace(): array
255285 */
256286 public function comes ($ sString , $ bCaseInsensitive = false ): bool
257287 {
258- $ sPeek = $ this ->peek (\strlen ($ sString ));
288+ if (!$ sString ) return false ;
289+
290+ $ sPeek1 = $ this ->peek ();
291+ if ($ bCaseInsensitive ) {
292+ if (\strtolower ($ sPeek1 ) !== \strtolower ($ sString [0 ])) return false ;
293+ } else {
294+ if ($ sPeek1 !== $ sString [0 ]) return false ;
295+ }
296+
297+ $ sPeek = \strlen ($ sString ) == 1 ? $ sPeek1 : $ this ->peek (\strlen ($ sString ));
298+
259299 return ($ sPeek == '' )
260300 ? false
261301 : $ this ->streql ($ sPeek , $ sString , $ bCaseInsensitive );
@@ -271,7 +311,12 @@ public function peek($iLength = 1, $iOffset = 0): string
271311 if ($ iOffset >= $ this ->iLength ) {
272312 return '' ;
273313 }
274- return $ this ->substr ($ iOffset , $ iLength );
314+
315+ if ($ iLength == 1 && $ iOffset + 1 <= $ this ->iLength ) {
316+ return $ this ->aText [$ iOffset ];
317+ } else {
318+ return $ this ->substr ($ iOffset , $ iLength );
319+ }
275320 }
276321
277322 /**
@@ -283,19 +328,24 @@ public function peek($iLength = 1, $iOffset = 0): string
283328 public function consume ($ mValue = 1 ): string
284329 {
285330 if (\is_string ($ mValue )) {
286- $ iLineCount = \substr_count ($ mValue , "\n" );
287331 $ iLength = $ this ->strlen ($ mValue );
288332 if (!$ this ->streql ($ this ->substr ($ this ->iCurrentPosition , $ iLength ), $ mValue )) {
289333 throw new UnexpectedTokenException ($ mValue , $ this ->peek (\max ($ iLength , 5 )), $ this ->iLineNo );
290334 }
291- $ this ->iLineNo += $ iLineCount ;
335+ $ this ->iLineNo += \substr_count ( $ mValue , "\n" ) ;
292336 $ this ->iCurrentPosition += $ this ->strlen ($ mValue );
293337 return $ mValue ;
294338 } else {
295339 if ($ this ->iCurrentPosition + $ mValue > $ this ->iLength ) {
296340 throw new UnexpectedEOFException ($ mValue , $ this ->peek (5 ), 'count ' , $ this ->iLineNo );
297341 }
298- $ sResult = $ this ->substr ($ this ->iCurrentPosition , $ mValue );
342+
343+ if ($ mValue == 1 && $ this ->iCurrentPosition + 1 <= $ this ->iLength ) {
344+ $ sResult = $ this ->aText [$ this ->iCurrentPosition ];
345+ } else {
346+ $ sResult = $ this ->substr ($ this ->iCurrentPosition , $ mValue );
347+ }
348+
299349 $ iLineCount = \substr_count ($ sResult , "\n" );
300350 $ this ->iLineNo += $ iLineCount ;
301351 $ this ->iCurrentPosition += $ mValue ;
@@ -325,26 +375,27 @@ public function consumeExpression($mExpression, $iMaxLength = null): string
325375 */
326376 public function consumeComment ()
327377 {
328- $ mComment = false ;
329- if ( $ this -> comes ( ' /* ' )) {
330- $ iLineNo = $ this -> iLineNo ;
331- $ this -> consume ( 1 );
332- $ mComment = '' ;
333- while (( $ char = $ this ->consume ( 1 )) !== '' ) {
334- $ mComment .= $ char ;
335- if ( $ this ->comes ( ' */ ' ) ) {
336- $ this ->consume ( 2 );
337- break ;
338- }
378+ if ( $ this -> peek () != ' / ' || $ this -> peek ( 1 , 1 ) != ' * ' ) {
379+ return false ;
380+ }
381+
382+ $ sComment = '' ;
383+ $ iLineNo = $ this ->iLineNo ;
384+ $ this -> consume ( 1 ) ;
385+ while (( $ char = $ this ->consume ( 1 )) !== '' ) {
386+ if ( $ char == ' * ' && $ this ->peek () == ' / ' ) {
387+ $ this -> consume ( 1 ) ;
388+ break ;
339389 }
390+ $ sComment .= $ char ;
340391 }
341392
342- if ($ mComment !== false ) {
393+ if ($ sComment !== '' ) {
343394 // We skip the * which was included in the comment.
344- return new Comment (\substr ($ mComment , 1 ), $ iLineNo );
395+ return new Comment (\substr ($ sComment , 1 ), $ iLineNo );
345396 }
346397
347- return $ mComment ;
398+ return false ;
348399 }
349400
350401 public function isEnd (): bool
@@ -380,8 +431,10 @@ public function consumeUntil($aEnd, $bIncludeEnd = false, $consumeEnd = false, a
380431 return $ out ;
381432 }
382433 $ out .= $ char ;
383- if ($ comment = $ this ->consumeComment ()) {
384- $ comments [] = $ comment ;
434+ if ($ this ->peek (1 ) == '/ ' && $ this ->peek (1 , 1 ) == '* ' ) {
435+ if ($ comment = $ this ->consumeComment ()) {
436+ $ comments [] = $ comment ;
437+ }
385438 }
386439 }
387440
@@ -479,7 +532,17 @@ private function strsplit($sString)
479532 {
480533 if ($ this ->oParserSettings ->bMultibyteSupport ) {
481534 if ($ this ->streql ($ this ->sCharset , 'utf-8 ' )) {
482- return \preg_split ('//u ' , $ sString , -1 , PREG_SPLIT_NO_EMPTY );
535+ $ iLimit = 1024 * 1024 ;
536+ $ iLength = \mb_strlen ($ sString , $ this ->sCharset );
537+ $ iOffset = 0 ;
538+ $ aResult = [];
539+ for ($ iOffset = 0 ; $ iOffset < $ iLength ; $ iOffset += $ iLimit ) {
540+ $ sChunk = \mb_substr ($ sString , $ iOffset , $ iLimit , 'utf-8 ' );
541+ foreach (\preg_split ('//u ' , $ sChunk , -1 , PREG_SPLIT_NO_EMPTY ) as $ sChar ) {
542+ $ aResult [] = $ sChar ;
543+ }
544+ }
545+ return $ aResult ;
483546 } else {
484547 $ iLength = \mb_strlen ($ sString , $ this ->sCharset );
485548 $ aResult = [];
0 commit comments