From 364a89703b924655f89a13c7071f004e7417b111 Mon Sep 17 00:00:00 2001 From: Gocha Ossinkine Date: Thu, 11 Feb 2016 09:56:25 +0500 Subject: [PATCH 1/4] Work with array instead of string --- lib/Sabberworm/CSS/Parser.php | 36 ++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/lib/Sabberworm/CSS/Parser.php b/lib/Sabberworm/CSS/Parser.php index fd9f7bca..7e4f7583 100644 --- a/lib/Sabberworm/CSS/Parser.php +++ b/lib/Sabberworm/CSS/Parser.php @@ -26,7 +26,7 @@ */ class Parser { - private $sText; + private $aText; private $iCurrentPosition; private $oParserSettings; private $sCharset; @@ -36,12 +36,16 @@ class Parser { private $aSizeUnits; public function __construct($sText, Settings $oParserSettings = null) { - $this->sText = $sText; $this->iCurrentPosition = 0; if ($oParserSettings === null) { $oParserSettings = Settings::create(); } $this->oParserSettings = $oParserSettings; + if ($this->oParserSettings->bMultibyteSupport) { + $this->aText = preg_split('//u', $sText, null, PREG_SPLIT_NO_EMPTY); + } else { + $this->aText = str_split($sText); + } $this->blockRules = explode('/', AtRule::BLOCK_RULES); foreach (explode('/', Size::ABSOLUTE_SIZE_UNITS.'/'.Size::RELATIVE_SIZE_UNITS.'/'.Size::NON_SIZE_UNITS) as $val) { @@ -56,7 +60,7 @@ public function __construct($sText, Settings $oParserSettings = null) { public function setCharset($sCharset) { $this->sCharset = $sCharset; - $this->iLength = $this->strlen($this->sText); + $this->iLength = count($this->aText); } public function getCharset() { @@ -284,7 +288,7 @@ private function parseRuleSet($oRuleSet) { try { $sConsume = $this->consumeUntil(array("\n", ";", '}'), true); // We need to “unfind” the matches to the end of the ruleSet as this will be matched later - if($this->streql($this->substr($sConsume, $this->strlen($sConsume)-1, 1), '}')) { + if($this->streql(substr($sConsume, -1), '}')) { --$this->iCurrentPosition; $this->peekCache = null; } else { @@ -469,8 +473,8 @@ private function parseURLValue() { } /** - * Tests an identifier for a given value. Since identifiers are all keywords, they can be vendor-prefixed. We need to check for these versions too. - */ + * Tests an identifier for a given value. Since identifiers are all keywords, they can be vendor-prefixed. We need to check for these versions too. + */ private function identifierIs($sIdentifier, $sMatch) { return (strcasecmp($sIdentifier, $sMatch) === 0) ?: preg_match("/^(-\\w+-)?$sMatch$/i", $sIdentifier) === 1; @@ -493,7 +497,7 @@ private function peek($iLength = 1, $iOffset = 0) { return ''; } $iLength = min($iLength, $this->iLength-$iOffset); - $out = $this->substr($this->sText, $iOffset, $iLength); + $out = $this->substr($iOffset, $iLength); if ($peek) { $this->peekCache = $out; } @@ -503,7 +507,7 @@ private function peek($iLength = 1, $iOffset = 0) { private function consume($mValue = 1) { if (is_string($mValue)) { $iLength = $this->strlen($mValue); - if (!$this->streql($this->substr($this->sText, $this->iCurrentPosition, $iLength), $mValue)) { + if (!$this->streql($this->substr($this->iCurrentPosition, $iLength), $mValue)) { throw new UnexpectedTokenException($mValue, $this->peek(max($iLength, 5))); } $this->iCurrentPosition += $this->strlen($mValue); @@ -513,7 +517,7 @@ private function consume($mValue = 1) { if ($this->iCurrentPosition + $mValue > $this->iLength) { throw new UnexpectedTokenException($mValue, $this->peek(5), 'count'); } - $sResult = $this->substr($this->sText, $this->iCurrentPosition, $mValue); + $sResult = $this->substr($this->iCurrentPosition, $mValue); $this->iCurrentPosition += $mValue; $this->peekCache = null; return $sResult; @@ -587,15 +591,17 @@ private function consumeUntil($aEnd, $bIncludeEnd = false, $consumeEnd = false) } private function inputLeft() { - return $this->substr($this->sText, $this->iCurrentPosition, -1); + return $this->substr($this->iCurrentPosition, -1); } - private function substr($sString, $iStart, $iLength) { - if ($this->oParserSettings->bMultibyteSupport) { - return mb_substr($sString, $iStart, $iLength, $this->sCharset); - } else { - return substr($sString, $iStart, $iLength); + private function substr($iStart, $iLength) { + $out = ''; + while ($iLength > 0) { + $out .= $this->aText[$iStart]; + $iStart++; + $iLength--; } + return $out; } private function strlen($sString) { From dfd8374e45122cda8f258e4ca8a125436e89f6fe Mon Sep 17 00:00:00 2001 From: Gocha Ossinkine Date: Thu, 11 Feb 2016 09:58:20 +0500 Subject: [PATCH 2/4] Remove unnecessary peek cache --- lib/Sabberworm/CSS/Parser.php | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/lib/Sabberworm/CSS/Parser.php b/lib/Sabberworm/CSS/Parser.php index 7e4f7583..df0affdc 100644 --- a/lib/Sabberworm/CSS/Parser.php +++ b/lib/Sabberworm/CSS/Parser.php @@ -31,7 +31,6 @@ class Parser { private $oParserSettings; private $sCharset; private $iLength; - private $peekCache = null; private $blockRules; private $aSizeUnits; @@ -290,7 +289,6 @@ private function parseRuleSet($oRuleSet) { // We need to “unfind” the matches to the end of the ruleSet as this will be matched later if($this->streql(substr($sConsume, -1), '}')) { --$this->iCurrentPosition; - $this->peekCache = null; } else { $this->consumeWhiteSpace(); while ($this->comes(';')) { @@ -488,19 +486,12 @@ private function comes($sString, $bCaseInsensitive = false) { } private function peek($iLength = 1, $iOffset = 0) { - if (($peek = (!$iOffset && ($iLength === 1))) && - !is_null($this->peekCache)) { - return $this->peekCache; - } $iOffset += $this->iCurrentPosition; if ($iOffset >= $this->iLength) { return ''; } $iLength = min($iLength, $this->iLength-$iOffset); $out = $this->substr($iOffset, $iLength); - if ($peek) { - $this->peekCache = $out; - } return $out; } @@ -511,7 +502,6 @@ private function consume($mValue = 1) { throw new UnexpectedTokenException($mValue, $this->peek(max($iLength, 5))); } $this->iCurrentPosition += $this->strlen($mValue); - $this->peekCache = null; return $mValue; } else { if ($this->iCurrentPosition + $mValue > $this->iLength) { @@ -519,7 +509,6 @@ private function consume($mValue = 1) { } $sResult = $this->substr($this->iCurrentPosition, $mValue); $this->iCurrentPosition += $mValue; - $this->peekCache = null; return $sResult; } } From 9db72a0002614b9732e3b32c5623ce030b030155 Mon Sep 17 00:00:00 2001 From: Gocha Ossinkine Date: Thu, 11 Feb 2016 09:59:24 +0500 Subject: [PATCH 3/4] Minor optimization --- lib/Sabberworm/CSS/Parser.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/Sabberworm/CSS/Parser.php b/lib/Sabberworm/CSS/Parser.php index df0affdc..1e95e889 100644 --- a/lib/Sabberworm/CSS/Parser.php +++ b/lib/Sabberworm/CSS/Parser.php @@ -490,7 +490,6 @@ private function peek($iLength = 1, $iOffset = 0) { if ($iOffset >= $this->iLength) { return ''; } - $iLength = min($iLength, $this->iLength-$iOffset); $out = $this->substr($iOffset, $iLength); return $out; } @@ -585,7 +584,7 @@ private function inputLeft() { private function substr($iStart, $iLength) { $out = ''; - while ($iLength > 0) { + while ($iLength > 0 && $iStart < $this->iLength) { $out .= $this->aText[$iStart]; $iStart++; $iLength--; From c5a44a9697e68062b446827a881c110407c7d0ec Mon Sep 17 00:00:00 2001 From: Gocha Ossinkine Date: Thu, 11 Feb 2016 11:11:07 +0500 Subject: [PATCH 4/4] Fix substr with negative length --- lib/Sabberworm/CSS/Parser.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/Sabberworm/CSS/Parser.php b/lib/Sabberworm/CSS/Parser.php index 1e95e889..9c46c562 100644 --- a/lib/Sabberworm/CSS/Parser.php +++ b/lib/Sabberworm/CSS/Parser.php @@ -583,8 +583,14 @@ private function inputLeft() { } private function substr($iStart, $iLength) { + if ($iLength < 0) { + $iLength = $this->iLength - $iStart + $iLength; + } + if ($iStart + $iLength > $this->iLength) { + $iLength = $this->iLength - $iStart; + } $out = ''; - while ($iLength > 0 && $iStart < $this->iLength) { + while ($iLength > 0) { $out .= $this->aText[$iStart]; $iStart++; $iLength--;