28         return $matches[1] . htmlspecialchars($matches[2], ENT_COMPAT, 
'UTF-8') . $matches[3];
 
   36         if ($config->get(
'HTML.Trusted')) {
 
   37             $html = preg_replace_callback(
'#(<script[^>]*>)(\s*[^<].+?)(</script>)#si',
 
   38                 array($this, 
'scriptCallback'), $html);
 
   41         $html = $this->
normalize($html, $config, $context);
 
   48         $maintain_line_numbers = $config->get(
'Core.MaintainLineNumbers');
 
   50         if ($maintain_line_numbers === null) {
 
   53             $maintain_line_numbers = $config->get(
'Core.CollectErrors');
 
   56         if ($maintain_line_numbers) {
 
   59             $length = strlen($html);
 
   61             $current_line = 
false;
 
   65         $context->register(
'CurrentLine', $current_line);
 
   66         $context->register(
'CurrentCol',  $current_col);
 
   70         $synchronize_interval = $config->get(
'Core.DirectLexLineNumberSyncInterval');
 
   73         if ($config->get(
'Core.CollectErrors')) {
 
   74             $e =& $context->get(
'ErrorCollector');
 
   86             if ($maintain_line_numbers) {
 
   89                 $rcursor = $cursor - (int) $inside_tag;
 
   95                 $nl_pos = strrpos($html, $nl, $rcursor - $length);
 
   96                 $current_col = $rcursor - (is_bool($nl_pos) ? 0 : $nl_pos + 1);
 
  100                     $synchronize_interval &&  
 
  102                     $loops % $synchronize_interval === 0 
 
  104                     $current_line = 1 + $this->
substrCount($html, $nl, 0, $cursor);
 
  109             $position_next_lt = strpos($html, 
'<', $cursor);
 
  110             $position_next_gt = strpos($html, 
'>', $cursor);
 
  114             if ($position_next_lt === $cursor) {
 
  119             if (!$inside_tag && $position_next_lt !== 
false) {
 
  125                                 $html, $cursor, $position_next_lt - $cursor
 
  129                 if ($maintain_line_numbers) {
 
  130                     $token->rawPosition($current_line, $current_col);
 
  131                     $current_line += $this->
substrCount($html, $nl, $cursor, $position_next_lt - $cursor);
 
  134                 $cursor  = $position_next_lt + 1;
 
  137             } elseif (!$inside_tag) {
 
  140                 if ($cursor === strlen($html)) 
break;
 
  150                 if ($maintain_line_numbers) $token->rawPosition($current_line, $current_col);
 
  153             } elseif ($inside_tag && $position_next_gt !== 
false) {
 
  156                 $strlen_segment = $position_next_gt - $cursor;
 
  158                 if ($strlen_segment < 1) {
 
  165                 $segment = substr($html, $cursor, $strlen_segment);
 
  167                 if ($segment === 
false) {
 
  175                     substr($segment, 0, 3) === 
'!--' 
  178                     $position_comment_end = strpos($html, 
'-->', $cursor);
 
  179                     if ($position_comment_end === 
false) {
 
  183                         if ($e) $e->send(E_WARNING, 
'Lexer: Unclosed comment');
 
  184                         $position_comment_end = strlen($html);
 
  189                     $strlen_segment = $position_comment_end - $cursor;
 
  190                     $segment = substr($html, $cursor, $strlen_segment);
 
  194                                 $segment, 3, $strlen_segment - 3
 
  197                     if ($maintain_line_numbers) {
 
  198                         $token->rawPosition($current_line, $current_col);
 
  199                         $current_line += $this->
substrCount($html, $nl, $cursor, $strlen_segment);
 
  202                     $cursor = $end ? $position_comment_end : $position_comment_end + 3;
 
  208                 $is_end_tag = (strpos($segment,
'/') === 0);
 
  210                     $type = substr($segment, 1);
 
  212                     if ($maintain_line_numbers) {
 
  213                         $token->rawPosition($current_line, $current_col);
 
  214                         $current_line += $this->
substrCount($html, $nl, $cursor, $position_next_gt - $cursor);
 
  218                     $cursor = $position_next_gt + 1;
 
  225                 if (!ctype_alpha($segment[0])) {
 
  227                     if ($e) $e->send(E_NOTICE, 
'Lexer: Unescaped lt');
 
  229                     if ($maintain_line_numbers) {
 
  230                         $token->rawPosition($current_line, $current_col);
 
  231                         $current_line += $this->
substrCount($html, $nl, $cursor, $position_next_gt - $cursor);
 
  242                 $is_self_closing = (strrpos($segment,
'/') === $strlen_segment-1);
 
  243                 if ($is_self_closing) {
 
  245                     $segment = substr($segment, 0, $strlen_segment);
 
  249                 $position_first_space = strcspn($segment, $this->_whitespace);
 
  251                 if ($position_first_space >= $strlen_segment) {
 
  252                     if ($is_self_closing) {
 
  257                     if ($maintain_line_numbers) {
 
  258                         $token->rawPosition($current_line, $current_col);
 
  259                         $current_line += $this->
substrCount($html, $nl, $cursor, $position_next_gt - $cursor);
 
  263                     $cursor = $position_next_gt + 1;
 
  268                 $type = substr($segment, 0, $position_first_space);
 
  272                             $segment, $position_first_space
 
  275                 if ($attribute_string) {
 
  284                 if ($is_self_closing) {
 
  289                 if ($maintain_line_numbers) {
 
  290                     $token->rawPosition($current_line, $current_col);
 
  291                     $current_line += $this->
substrCount($html, $nl, $cursor, $position_next_gt - $cursor);
 
  294                 $cursor = $position_next_gt + 1;
 
  299                 if ($e) $e->send(E_WARNING, 
'Lexer: Missing gt');
 
  304                             substr($html, $cursor)
 
  307                 if ($maintain_line_numbers) $token->rawPosition($current_line, $current_col);
 
  315         $context->destroy(
'CurrentLine');
 
  316         $context->destroy(
'CurrentCol');
 
  323     protected function substrCount($haystack, $needle, $offset, $length) {
 
  325         if ($oldVersion === null) {
 
  326             $oldVersion = version_compare(PHP_VERSION, 
'5.1', 
'<');
 
  329             $haystack = substr($haystack, $offset, $length);
 
  330             return substr_count($haystack, $needle);
 
  332             return substr_count($haystack, $needle, $offset, $length);
 
  343         $string = (string) $string; 
 
  345         if ($string == 
'') 
return array(); 
 
  348         if ($config->get(
'Core.CollectErrors')) {
 
  349             $e =& $context->get(
'ErrorCollector');
 
  354         $num_equal = substr_count($string, 
'=');
 
  355         $has_space = strpos($string, 
' ');
 
  356         if ($num_equal === 0 && !$has_space) {
 
  358             return array($string => $string);
 
  359         } elseif ($num_equal === 1 && !$has_space) {
 
  361             list($key, $quoted_value) = explode(
'=', $string);
 
  362             $quoted_value = trim($quoted_value);
 
  364                 if ($e) $e->send(E_ERROR, 
'Lexer: Missing attribute key');
 
  367             if (!$quoted_value) 
return array($key => 
'');
 
  368             $first_char = @$quoted_value[0];
 
  369             $last_char  = @$quoted_value[strlen($quoted_value)-1];
 
  371             $same_quote = ($first_char == $last_char);
 
  372             $open_quote = ($first_char == 
'"' || $first_char == 
"'");
 
  374             if ( $same_quote && $open_quote) {
 
  376                 $value = substr($quoted_value, 1, strlen($quoted_value) - 2);
 
  380                     if ($e) $e->send(E_ERROR, 
'Lexer: Missing end quote');
 
  381                     $value = substr($quoted_value, 1);
 
  383                     $value = $quoted_value;
 
  386             if ($value === 
false) $value = 
'';
 
  387             return array($key => $this->
parseData($value));
 
  393         $size   = strlen($string); 
 
  401             if ($cursor >= 
$size) {
 
  405             $cursor += ($value = strspn($string, $this->_whitespace, $cursor));
 
  408             $key_begin = $cursor; 
 
  411             $cursor += strcspn($string, $this->_whitespace . 
'=', $cursor);
 
  415             $key = substr($string, $key_begin, $key_end - $key_begin);
 
  418                 if ($e) $e->send(E_ERROR, 
'Lexer: Missing attribute key');
 
  419                 $cursor += strcspn($string, $this->_whitespace, $cursor + 1); 
 
  424             $cursor += strspn($string, $this->_whitespace, $cursor);
 
  426             if ($cursor >= 
$size) {
 
  433             $first_char = @$string[$cursor];
 
  435             if ($first_char == 
'=') {
 
  439                 $cursor += strspn($string, $this->_whitespace, $cursor);
 
  441                 if ($cursor === 
false) {
 
  448                 $char = @$string[$cursor];
 
  450                 if ($char == 
'"' || $char == 
"'") {
 
  453                     $value_begin = $cursor;
 
  454                     $cursor = strpos($string, $char, $cursor);
 
  455                     $value_end = $cursor;
 
  458                     $value_begin = $cursor;
 
  459                     $cursor += strcspn($string, $this->_whitespace, $cursor);
 
  460                     $value_end = $cursor;
 
  464                 if ($cursor === 
false) {
 
  466                     $value_end = $cursor;
 
  469                 $value = substr($string, $value_begin, $value_end - $value_begin);
 
  470                 if ($value === 
false) $value = 
'';
 
  480                     if ($e) $e->send(E_ERROR, 
'Lexer: Missing attribute key');