Bug 36785 Special:Shortpages lists only NS_MAIN pages. (pages from all $wgContentName...
[lhc/web/wiklou.git] / includes / parser / Preprocessor_DOM.php
index 2dd3efd..602d88f 100644 (file)
@@ -2,6 +2,21 @@
 /**
  * Preprocessor using PHP's dom extension
  *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
  * @file
  * @ingroup Parser
  */
  * @ingroup Parser
  */
 class Preprocessor_DOM implements Preprocessor {
-       var $parser, $memoryLimit;
+
+       /**
+        * @var Parser
+        */
+       var $parser;
+
+       var $memoryLimit;
 
        const CACHE_VERSION = 1;
 
@@ -42,6 +63,10 @@ class Preprocessor_DOM implements Preprocessor {
                return new PPCustomFrame_DOM( $this, $args );
        }
 
+       /**
+        * @param $values
+        * @return PPNode_DOM
+        */
        function newPartNodeArray( $values ) {
                //NOTE: DOM manipulation is slower than building & parsing XML! (or so Tim sais)
                $xml = "<list>";
@@ -65,9 +90,13 @@ class Preprocessor_DOM implements Preprocessor {
                return $node;
        }
 
+       /**
+        * @throws MWException
+        * @return bool
+        */
        function memCheck() {
                if ( $this->memoryLimit === false ) {
-                       return;
+                       return true;
                }
                $usage = memory_get_usage();
                if ( $usage > $this->memoryLimit * 0.9 ) {
@@ -97,14 +126,15 @@ class Preprocessor_DOM implements Preprocessor {
         * cache may be implemented at a later date which takes further advantage of these strict
         * dependency requirements.
         *
-        * @private
+        * @return PPNode_DOM
         */
        function preprocessToObj( $text, $flags = 0 ) {
                wfProfileIn( __METHOD__ );
                global $wgMemc, $wgPreprocessorCacheThreshold;
 
                $xml = false;
-               $cacheable = $wgPreprocessorCacheThreshold !== false && strlen( $text ) > $wgPreprocessorCacheThreshold;
+               $cacheable = ( $wgPreprocessorCacheThreshold !== false
+                       && strlen( $text ) > $wgPreprocessorCacheThreshold );
                if ( $cacheable ) {
                        wfProfileIn( __METHOD__.'-cacheable' );
 
@@ -140,7 +170,8 @@ class Preprocessor_DOM implements Preprocessor {
                if ( !$result ) {
                        // Try running the XML through UtfNormal to get rid of invalid characters
                        $xml = UtfNormal::cleanUp( $xml );
-                       $result = $dom->loadXML( $xml );
+                       // 1 << 19 == XML_PARSE_HUGE, needed so newer versions of libxml2 don't barf when the XML is >256 levels deep
+                       $result = $dom->loadXML( $xml, 1 << 19 );
                        if ( !$result ) {
                                throw new MWException( __METHOD__.' generated invalid XML' );
                        }
@@ -154,6 +185,11 @@ class Preprocessor_DOM implements Preprocessor {
                return $obj;
        }
 
+       /**
+        * @param $text string
+        * @param $flags int
+        * @return string
+        */
        function preprocessToXml( $text, $flags = 0 ) {
                wfProfileIn( __METHOD__ );
                $rules = array(
@@ -427,9 +463,7 @@ class Preprocessor_DOM implements Preprocessor {
                                        $accum .= '<inner>' . htmlspecialchars( $inner ) . '</inner>';
                                }
                                $accum .= $close . '</ext>';
-                       }
-
-                       elseif ( $found == 'line-start' ) {
+                       } elseif ( $found == 'line-start' ) {
                                // Is this the start of a heading?
                                // Line break belongs before the heading element in any case
                                if ( $fakeLineStart ) {
@@ -457,12 +491,10 @@ class Preprocessor_DOM implements Preprocessor {
                                        extract( $flags );
                                        $i += $count;
                                }
-                       }
-
-                       elseif ( $found == 'line-end' ) {
+                       } 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 (end anchor, etc.) are inefficient
@@ -526,7 +558,7 @@ class Preprocessor_DOM implements Preprocessor {
                                                'open' => $curChar,
                                                'close' => $rule['end'],
                                                'count' => $count,
-                                               'lineStart' => ($i == 0 || $text[$i-1] == "\n"),
+                                               'lineStart' => ($i > 0 && $text[$i-1] == "\n"),
                                        );
 
                                        $stack->push( $piece );
@@ -561,7 +593,7 @@ class Preprocessor_DOM implements Preprocessor {
                                        }
                                }
 
-                               if ($matchingCount <= 0) {
+                               if ( $matchingCount <= 0 ) {
                                        # No matching element found in callback array
                                        # Output a literal closing brace and continue
                                        $accum .= htmlspecialchars( str_repeat( $curChar, $count ) );
@@ -611,7 +643,7 @@ class Preprocessor_DOM implements Preprocessor {
                                $accum =& $stack->getAccum();
 
                                # Re-add the old stack element if it still has unmatched opening characters remaining
-                               if ($matchingCount < $piece->count) {
+                               if ( $matchingCount < $piece->count ) {
                                        $piece->parts = array( new PPDPart );
                                        $piece->count -= $matchingCount;
                                        # do we still qualify for any callback with remaining count?
@@ -634,16 +666,12 @@ class Preprocessor_DOM implements Preprocessor {
 
                                # Add XML element to the enclosing accumulator
                                $accum .= $element;
-                       }
-
-                       elseif ( $found == 'pipe' ) {
+                       } elseif ( $found == 'pipe' ) {
                                $findEquals = true; // shortcut for getFlags()
                                $stack->addPart();
                                $accum =& $stack->getAccum();
                                ++$i;
-                       }
-
-                       elseif ( $found == 'equals' ) {
+                       } elseif ( $found == 'equals' ) {
                                $findEquals = false; // shortcut for getFlags()
                                $stack->getCurrentPart()->eqpos = strlen( $accum );
                                $accum .= '=';
@@ -669,7 +697,12 @@ class Preprocessor_DOM implements Preprocessor {
  * @ingroup Parser
  */
 class PPDStack {
-       var $stack, $rootAccum, $top;
+       var $stack, $rootAccum;
+
+       /**
+        * @var PPDStack
+        */
+       var $top;
        var $out;
        var $elementClass = 'PPDStackElement';
 
@@ -682,6 +715,9 @@ class PPDStack {
                $this->accum =& $this->rootAccum;
        }
 
+       /**
+        * @return int
+        */
        function count() {
                return count( $this->stack );
        }
@@ -730,6 +766,9 @@ class PPDStack {
                $this->accum =& $this->top->getAccum();
        }
 
+       /**
+        * @return array
+        */
        function getFlags() {
                if ( !count( $this->stack ) ) {
                        return array(
@@ -777,6 +816,9 @@ class PPDStackElement {
                return $this->parts[count($this->parts) - 1];
        }
 
+       /**
+        * @return array
+        */
        function getFlags() {
                $partCount = count( $this->parts );
                $findPipe = $this->open != "\n" && $this->open != '[';
@@ -789,6 +831,8 @@ class PPDStackElement {
 
        /**
         * Get the output string that would result if the close is not found.
+        *
+        * @return string
         */
        function breakSyntax( $openingCount = false ) {
                if ( $this->open == "\n" ) {
@@ -833,7 +877,21 @@ class PPDPart {
  * @ingroup Parser
  */
 class PPFrame_DOM implements PPFrame {
-       var $preprocessor, $parser, $title;
+
+       /**
+        * @var Preprocessor
+        */
+       var $preprocessor;
+
+       /**
+        * @var Parser
+        */
+       var $parser;
+
+       /**
+        * @var Title
+        */
+       var $title;
        var $titleCache;
 
        /**
@@ -851,7 +909,7 @@ class PPFrame_DOM implements PPFrame {
 
        /**
         * Construct a new preprocessor frame.
-        * @param $preprocessor Preprocessor: The parent preprocessor
+        * @param $preprocessor Preprocessor The parent preprocessor
         */
        function __construct( $preprocessor ) {
                $this->preprocessor = $preprocessor;
@@ -865,6 +923,8 @@ class PPFrame_DOM implements PPFrame {
        /**
         * Create a new child frame
         * $args is optionally a multi-root PPNode or array containing the template arguments
+        *
+        * @return PPTemplateFrame_DOM
         */
        function newChild( $args = false, $title = false ) {
                $namedArgs = array();
@@ -900,22 +960,38 @@ class PPFrame_DOM implements PPFrame {
                return new PPTemplateFrame_DOM( $this->preprocessor, $this, $numberedArgs, $namedArgs, $title );
        }
 
+       /**
+        * @throws MWException
+        * @param $root
+        * @param $flags int
+        * @return string
+        */
        function expand( $root, $flags = 0 ) {
                static $expansionDepth = 0;
                if ( is_string( $root ) ) {
                        return $root;
                }
 
-               if ( ++$this->parser->mPPNodeCount > $this->parser->mOptions->getMaxPPNodeCount() )
-               {
+               if ( ++$this->parser->mPPNodeCount > $this->parser->mOptions->getMaxPPNodeCount() ) {
+                       $this->parser->limitationWarn( 'node-count-exceeded',
+                               $this->parser->mPPNodeCount,
+                               $this->parser->mOptions->getMaxPPNodeCount()
+                       );
                        return '<span class="error">Node-count limit exceeded</span>';
                }
 
                if ( $expansionDepth > $this->parser->mOptions->getMaxPPExpandDepth() ) {
+                       $this->parser->limitationWarn( 'expansion-depth-exceeded',
+                               $expansionDepth,
+                               $this->parser->mOptions->getMaxPPExpandDepth()
+                       );
                        return '<span class="error">Expansion depth limit exceeded</span>';
                }
                wfProfileIn( __METHOD__ );
                ++$expansionDepth;
+               if ( $expansionDepth > $this->parser->mHighestExpansionDepth ) {
+                       $this->parser->mHighestExpansionDepth = $expansionDepth;
+               }
 
                if ( $root instanceof PPNode_DOM ) {
                        $root = $root->node;
@@ -1111,6 +1187,11 @@ class PPFrame_DOM implements PPFrame {
                return $outStack[0];
        }
 
+       /**
+        * @param $sep
+        * @param $flags
+        * @return string
+        */
        function implodeWithFlags( $sep, $flags /*, ... */ ) {
                $args = array_slice( func_get_args(), 2 );
 
@@ -1136,6 +1217,8 @@ class PPFrame_DOM implements PPFrame {
        /**
         * Implode with no flags specified
         * This previously called implodeWithFlags but has now been inlined to reduce stack depth
+        *
+        * @return string
         */
        function implode( $sep /*, ... */ ) {
                $args = array_slice( func_get_args(), 1 );
@@ -1193,6 +1276,7 @@ class PPFrame_DOM implements PPFrame {
 
        /**
         * Virtual implode with brackets
+        * @return array
         */
        function virtualBracketedImplode( $start, $sep, $end /*, ... */ ) {
                $args = array_slice( func_get_args(), 3 );
@@ -1231,20 +1315,31 @@ class PPFrame_DOM implements PPFrame {
                }
        }
 
+       /**
+        * @return array
+        */
        function getArguments() {
                return array();
        }
 
+       /**
+        * @return array
+        */
        function getNumberedArguments() {
                return array();
        }
 
+       /**
+        * @return array
+        */
        function getNamedArguments() {
                return array();
        }
 
        /**
         * Returns true if there are no arguments in this frame
+        *
+        * @return bool
         */
        function isEmpty() {
                return true;
@@ -1256,6 +1351,8 @@ class PPFrame_DOM implements PPFrame {
 
        /**
         * Returns true if the infinite loop check is OK, false if a loop is detected
+        *
+        * @return bool
         */
        function loopCheck( $title ) {
                return !isset( $this->loopCheckHash[$title->getPrefixedDBkey()] );
@@ -1263,10 +1360,21 @@ class PPFrame_DOM implements PPFrame {
 
        /**
         * Return true if the frame is a template frame
+        *
+        * @return bool
         */
        function isTemplate() {
                return false;
        }
+
+       /**
+        * Get a title of frame
+        *
+        * @return Title
+        */
+       function getTitle() {
+               return $this->title;
+       }
 }
 
 /**
@@ -1274,9 +1382,21 @@ class PPFrame_DOM implements PPFrame {
  * @ingroup Parser
  */
 class PPTemplateFrame_DOM extends PPFrame_DOM {
-       var $numberedArgs, $namedArgs, $parent;
+       var $numberedArgs, $namedArgs;
+
+       /**
+        * @var PPFrame_DOM
+        */
+       var $parent;
        var $numberedExpansionCache, $namedExpansionCache;
 
+       /**
+        * @param $preprocessor
+        * @param $parent PPFrame_DOM
+        * @param $numberedArgs array
+        * @param $namedArgs array
+        * @param $title Title
+        */
        function __construct( $preprocessor, $parent = false, $numberedArgs = array(), $namedArgs = array(), $title = false ) {
                parent::__construct( $preprocessor );
 
@@ -1311,8 +1431,11 @@ class PPTemplateFrame_DOM extends PPFrame_DOM {
                $s .= '}';
                return $s;
        }
+
        /**
         * Returns true if there are no arguments in this frame
+        *
+        * @return bool
         */
        function isEmpty() {
                return !count( $this->numberedArgs ) && !count( $this->namedArgs );
@@ -1377,6 +1500,8 @@ class PPTemplateFrame_DOM extends PPFrame_DOM {
 
        /**
         * Return true if the frame is a template frame
+        *
+        * @return bool
         */
        function isTemplate() {
                return true;
@@ -1411,6 +1536,9 @@ class PPCustomFrame_DOM extends PPFrame_DOM {
                return $s;
        }
 
+       /**
+        * @return bool
+        */
        function isEmpty() {
                return !count( $this->args );
        }
@@ -1427,7 +1555,12 @@ class PPCustomFrame_DOM extends PPFrame_DOM {
  * @ingroup Parser
  */
 class PPNode_DOM implements PPNode {
-       var $node, $xpath;
+
+       /**
+        * @var DOMElement
+        */
+       var $node;
+       var $xpath;
 
        function __construct( $node, $xpath = false ) {
                $this->node = $node;
@@ -1568,6 +1701,7 @@ class PPNode_DOM implements PPNode {
 
        /**
         * Split a <h> node
+        * @return array
         */
        function splitHeading() {
                if ( $this->getName() !== 'h' ) {