Merge "Add CollationFa"
[lhc/web/wiklou.git] / includes / parser / Preprocessor_DOM.php
index 4c94b2a..5da7cd7 100644 (file)
@@ -196,6 +196,7 @@ class Preprocessor_DOM extends Preprocessor {
                $forInclusion = $flags & Parser::PTD_FOR_INCLUSION;
 
                $xmlishElements = $this->parser->getStripList();
+               $xmlishAllowMissingEndTag = [ 'includeonly', 'noinclude', 'onlyinclude' ];
                $enableOnlyinclude = false;
                if ( $forInclusion ) {
                        $ignoredTags = [ 'includeonly', '/includeonly' ];
@@ -237,6 +238,8 @@ class Preprocessor_DOM extends Preprocessor {
                $inHeading = false;
                // True if there are no more greater-than (>) signs right of $i
                $noMoreGT = false;
+               // Map of tag name => true if there are no more closing tags of given type right of $i
+               $noMoreClosingTag = [];
                // True to ignore all input up to the next <onlyinclude>
                $findOnlyinclude = $enableOnlyinclude;
                // Do a line-start run without outputting an LF character
@@ -457,17 +460,29 @@ class Preprocessor_DOM extends Preprocessor {
                                } else {
                                        $attrEnd = $tagEndPos;
                                        // Find closing tag
-                                       if ( preg_match( "/<\/" . preg_quote( $name, '/' ) . "\s*>/i",
+                                       if (
+                                               !isset( $noMoreClosingTag[$name] ) &&
+                                               preg_match( "/<\/" . preg_quote( $name, '/' ) . "\s*>/i",
                                                        $text, $matches, PREG_OFFSET_CAPTURE, $tagEndPos + 1 )
                                        ) {
                                                $inner = substr( $text, $tagEndPos + 1, $matches[0][1] - $tagEndPos - 1 );
                                                $i = $matches[0][1] + strlen( $matches[0][0] );
                                                $close = '<close>' . htmlspecialchars( $matches[0][0] ) . '</close>';
                                        } else {
-                                               // No end tag -- let it run out to the end of the text.
-                                               $inner = substr( $text, $tagEndPos + 1 );
-                                               $i = $lengthText;
-                                               $close = '';
+                                               // No end tag
+                                               if ( in_array( $name, $xmlishAllowMissingEndTag ) ) {
+                                                       // Let it run out to the end of the text.
+                                                       $inner = substr( $text, $tagEndPos + 1 );
+                                                       $i = $lengthText;
+                                                       $close = '';
+                                               } else {
+                                                       // Don't match the tag, treat opening tag as literal and resume parsing.
+                                                       $i = $tagEndPos + 1;
+                                                       $accum .= htmlspecialchars( substr( $text, $tagStartPos, $tagEndPos + 1 - $tagStartPos ) );
+                                                       // Cache results, otherwise we have O(N^2) performance for input like <foo><foo><foo>...
+                                                       $noMoreClosingTag[$name] = true;
+                                                       continue;
+                                               }
                                        }
                                }
                                // <includeonly> and <noinclude> just become <ignore> tags
@@ -524,7 +539,7 @@ class Preprocessor_DOM extends Preprocessor {
                        } elseif ( $found == 'line-end' ) {
                                $piece = $stack->top;
                                // A heading must be open, otherwise \n wouldn't have been in the search list
-                               assert( '$piece->open == "\n"' );
+                               assert( $piece->open === "\n" );
                                $part = $piece->getCurrentPart();
                                // Search back through the input to see if it has a proper close.
                                // Do this using the reversed string since the other solutions