@@ -50,6 +50,7 @@ class ParserState
50
50
* @var int
51
51
*/
52
52
private $ iLineNo ;
53
+ private $ sSelectorBuffer ;
53
54
54
55
/**
55
56
* @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)
62
63
$ this ->iCurrentPosition = 0 ;
63
64
$ this ->iLineNo = $ iLineNo ;
64
65
$ this ->setCharset ($ this ->oParserSettings ->sDefaultCharset );
66
+ $ this ->sSelectorBuffer = "" ;
65
67
}
66
68
67
69
/**
@@ -126,6 +128,26 @@ public function setPosition($iPosition): void
126
128
$ this ->iCurrentPosition = $ iPosition ;
127
129
}
128
130
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
+
129
151
/**
130
152
* @param bool $bIgnoreCase
131
153
*
@@ -166,7 +188,8 @@ public function parseIdentifier($bIgnoreCase = true)
166
188
*/
167
189
public function parseCharacter ($ bIsForIdentifier )
168
190
{
169
- if ($ this ->peek () === '\\' ) {
191
+ $ sPeekChar = $ this ->peek ();
192
+ if ($ sPeekChar === '\\' ) {
170
193
if (
171
194
$ bIsForIdentifier && $ this ->oParserSettings ->bLenientParsing
172
195
&& ($ this ->comes ('\\0 ' ) || $ this ->comes ('\\9 ' ))
@@ -200,22 +223,25 @@ public function parseCharacter($bIsForIdentifier)
200
223
}
201
224
return \iconv ('utf-32le ' , $ this ->sCharset , $ sUtf32 );
202
225
}
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 ) {
217
228
return $ this ->consume (1 );
218
229
}
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
+
219
245
return null ;
220
246
}
221
247
@@ -232,15 +258,19 @@ public function consumeWhiteSpace(): array
232
258
while (\preg_match ('/ \\s/isSu ' , $ this ->peek ()) === 1 ) {
233
259
$ this ->consume (1 );
234
260
}
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 {
237
272
$ oComment = $ this ->consumeComment ();
238
- } catch (UnexpectedEOFException $ e ) {
239
- $ this ->iCurrentPosition = $ this ->iLength ;
240
- return $ aComments ;
241
273
}
242
- } else {
243
- $ oComment = $ this ->consumeComment ();
244
274
}
245
275
if ($ oComment !== false ) {
246
276
$ aComments [] = $ oComment ;
@@ -255,7 +285,17 @@ public function consumeWhiteSpace(): array
255
285
*/
256
286
public function comes ($ sString , $ bCaseInsensitive = false ): bool
257
287
{
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
+
259
299
return ($ sPeek == '' )
260
300
? false
261
301
: $ this ->streql ($ sPeek , $ sString , $ bCaseInsensitive );
@@ -271,7 +311,12 @@ public function peek($iLength = 1, $iOffset = 0): string
271
311
if ($ iOffset >= $ this ->iLength ) {
272
312
return '' ;
273
313
}
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
+ }
275
320
}
276
321
277
322
/**
@@ -283,19 +328,24 @@ public function peek($iLength = 1, $iOffset = 0): string
283
328
public function consume ($ mValue = 1 ): string
284
329
{
285
330
if (\is_string ($ mValue )) {
286
- $ iLineCount = \substr_count ($ mValue , "\n" );
287
331
$ iLength = $ this ->strlen ($ mValue );
288
332
if (!$ this ->streql ($ this ->substr ($ this ->iCurrentPosition , $ iLength ), $ mValue )) {
289
333
throw new UnexpectedTokenException ($ mValue , $ this ->peek (\max ($ iLength , 5 )), $ this ->iLineNo );
290
334
}
291
- $ this ->iLineNo += $ iLineCount ;
335
+ $ this ->iLineNo += \substr_count ( $ mValue , "\n" ) ;
292
336
$ this ->iCurrentPosition += $ this ->strlen ($ mValue );
293
337
return $ mValue ;
294
338
} else {
295
339
if ($ this ->iCurrentPosition + $ mValue > $ this ->iLength ) {
296
340
throw new UnexpectedEOFException ($ mValue , $ this ->peek (5 ), 'count ' , $ this ->iLineNo );
297
341
}
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
+
299
349
$ iLineCount = \substr_count ($ sResult , "\n" );
300
350
$ this ->iLineNo += $ iLineCount ;
301
351
$ this ->iCurrentPosition += $ mValue ;
@@ -325,26 +375,27 @@ public function consumeExpression($mExpression, $iMaxLength = null): string
325
375
*/
326
376
public function consumeComment ()
327
377
{
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 ;
339
389
}
390
+ $ sComment .= $ char ;
340
391
}
341
392
342
- if ($ mComment !== false ) {
393
+ if ($ sComment !== '' ) {
343
394
// 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 );
345
396
}
346
397
347
- return $ mComment ;
398
+ return false ;
348
399
}
349
400
350
401
public function isEnd (): bool
@@ -380,8 +431,10 @@ public function consumeUntil($aEnd, $bIncludeEnd = false, $consumeEnd = false, a
380
431
return $ out ;
381
432
}
382
433
$ 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
+ }
385
438
}
386
439
}
387
440
@@ -479,7 +532,17 @@ private function strsplit($sString)
479
532
{
480
533
if ($ this ->oParserSettings ->bMultibyteSupport ) {
481
534
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 ;
483
546
} else {
484
547
$ iLength = \mb_strlen ($ sString , $ this ->sCharset );
485
548
$ aResult = [];
0 commit comments