Fixed bit math logic error in 0e765f8405c3ec1b428994d3149599a7132ae07b.
[lhc/web/wiklou.git] / includes / StringUtils.php
index 6c8412f..3b500ae 100644 (file)
@@ -1,4 +1,25 @@
 <?php
+/**
+ * Methods to play with strings.
+ *
+ * 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
+ */
+
 /**
  * A collection of static methods to play with strings.
  */
@@ -13,6 +34,13 @@ class StringUtils {
         * Compared to delimiterReplace(), this implementation is fast but memory-
         * hungry and inflexible. The memory requirements are such that I don't
         * recommend using it on anything but guaranteed small chunks of text.
+        *
+        * @param $startDelim
+        * @param $endDelim
+        * @param $replace
+        * @param $subject
+        *
+        * @return string
         */
        static function hungryDelimiterReplace( $startDelim, $endDelim, $replace, $subject ) {
                $segments = explode( $startDelim, $subject );
@@ -36,17 +64,20 @@ class StringUtils {
         * This implementation is slower than hungryDelimiterReplace but uses far less
         * memory. The delimiters are literal strings, not regular expressions.
         *
+        * If the start delimiter ends with an initial substring of the end delimiter,
+        * e.g. in the case of C-style comments, the behaviour differs from the model
+        * regex. In this implementation, the end must share no characters with the
+        * start, so e.g. /*\/ is not considered to be both the start and end of a
+        * comment. /*\/xy/*\/ is considered to be a single comment with contents /xy/.
+        *
         * @param $startDelim String: start delimiter
         * @param $endDelim String: end delimiter
         * @param $callback Callback: function to call on each match
         * @param $subject String
         * @param $flags String: regular expression flags
+        * @throws MWException
+        * @return string
         */
-       # If the start delimiter ends with an initial substring of the end delimiter,
-       # e.g. in the case of C-style comments, the behaviour differs from the model
-       # regex. In this implementation, the end must share no characters with the
-       # start, so e.g. /*/ is not considered to be both the start and end of a
-       # comment. /*/xy/*/ is considered to be a single comment with contents /xy/.
        static function delimiterReplaceCallback( $startDelim, $endDelim, $callback, $subject, $flags = '' ) {
                $inputPos = 0;
                $outputPos = 0;
@@ -81,16 +112,20 @@ class StringUtils {
                        }
 
                        if ( $tokenType == 'start' ) {
-                               $inputPos = $tokenOffset + $tokenLength;
                                # Only move the start position if we haven't already found a start
                                # This means that START START END matches outer pair
                                if ( !$foundStart ) {
                                        # Found start
+                                       $inputPos = $tokenOffset + $tokenLength;
                                        # Write out the non-matching section
                                        $output .= substr( $subject, $outputPos, $tokenOffset - $outputPos );
                                        $outputPos = $tokenOffset;
                                        $contentPos = $inputPos;
                                        $foundStart = true;
+                               } else {
+                                       # Move the input position past the *first character* of START,
+                                       # to protect against missing END when it overlaps with START
+                                       $inputPos = $tokenOffset + 1;
                                }
                        } elseif ( $tokenType == 'end' ) {
                                if ( $foundStart ) {
@@ -115,7 +150,7 @@ class StringUtils {
                return $output;
        }
 
-       /*
+       /**
         * Perform an operation equivalent to
         *
         *   preg_replace( "!$startDelim(.*)$endDelim!$flags", $replace, $subject )
@@ -125,6 +160,7 @@ class StringUtils {
         * @param $replace String: replacement string. May contain $1, which will be
         *                 replaced by the text between the delimiters
         * @param $subject String to search
+        * @param $flags String: regular expression flags
         * @return String: The string with the matches replaced
         */
        static function delimiterReplace( $startDelim, $endDelim, $replace, $subject, $flags = '' ) {
@@ -175,6 +211,9 @@ class StringUtils {
        /**
         * Workalike for explode() with limited memory usage.
         * Returns an Iterator
+        * @param $separator
+        * @param $subject
+        * @return ArrayIterator|\ExplodeIterator
         */
        static function explode( $separator, $subject ) {
                if ( substr_count( $subject, $separator ) > 1000 ) {
@@ -190,6 +229,10 @@ class StringUtils {
  * StringUtils::delimiterReplaceCallback()
  */
 class Replacer {
+
+       /**
+        * @return array
+        */
        function cb() {
                return array( &$this, 'replace' );
        }
@@ -200,10 +243,18 @@ class Replacer {
  */
 class RegexlikeReplacer extends Replacer {
        var $r;
+
+       /**
+        * @param $r string
+        */
        function __construct( $r ) {
                $this->r = $r;
        }
 
+       /**
+        * @param $matches array
+        * @return string
+        */
        function replace( $matches ) {
                $pairs = array();
                foreach ( $matches as $i => $match ) {
@@ -218,12 +269,22 @@ class RegexlikeReplacer extends Replacer {
  * Class to perform secondary replacement within each replacement string
  */
 class DoubleReplacer extends Replacer {
+
+       /**
+        * @param $from
+        * @param $to
+        * @param $index int
+        */
        function __construct( $from, $to, $index = 0 ) {
                $this->from = $from;
                $this->to = $to;
                $this->index = $index;
        }
 
+       /**
+        * @param $matches array
+        * @return mixed
+        */
        function replace( $matches ) {
                return str_replace( $this->from, $this->to, $matches[$this->index] );
        }
@@ -235,11 +296,19 @@ class DoubleReplacer extends Replacer {
 class HashtableReplacer extends Replacer {
        var $table, $index;
 
+       /**
+        * @param $table
+        * @param $index int
+        */
        function __construct( $table, $index = 0 ) {
                $this->table = $table;
                $this->index = $index;
        }
 
+       /**
+        * @param $matches array
+        * @return mixed
+        */
        function replace( $matches ) {
                return $this->table[$matches[$this->index]];
        }
@@ -256,11 +325,15 @@ class ReplacementArray {
        /**
         * Create an object with the specified replacement array
         * The array should have the same form as the replacement array for strtr()
+        * @param array $data
         */
        function __construct( $data = array() ) {
                $this->data = $data;
        }
 
+       /**
+        * @return array
+        */
        function __sleep() {
                return array( 'data' );
        }
@@ -277,39 +350,61 @@ class ReplacementArray {
                $this->fss = false;
        }
 
+       /**
+        * @return array|bool
+        */
        function getArray() {
                return $this->data;
        }
 
        /**
         * Set an element of the replacement array
+        * @param $from string
+        * @param $to stromg
         */
        function setPair( $from, $to ) {
                $this->data[$from] = $to;
                $this->fss = false;
        }
 
+       /**
+        * @param $data array
+        */
        function mergeArray( $data ) {
                $this->data = array_merge( $this->data, $data );
                $this->fss = false;
        }
 
+       /**
+        * @param $other
+        */
        function merge( $other ) {
                $this->data = array_merge( $this->data, $other->data );
                $this->fss = false;
        }
 
+       /**
+        * @param $from string
+        */
        function removePair( $from ) {
                unset($this->data[$from]);
                $this->fss = false;
        }
 
+       /**
+        * @param $data array
+        */
        function removeArray( $data ) {
-               foreach( $data as $from => $to )
+               foreach( $data as $from => $to ) {
                        $this->removePair( $from );
+               }
                $this->fss = false;
        }
 
+       /**
+        * @param $subject string
+        * @return string
+        */
        function replace( $subject ) {
                if ( function_exists( 'fss_prep_replace' ) ) {
                        wfProfileIn( __METHOD__.'-fss' );
@@ -352,8 +447,10 @@ class ExplodeIterator implements Iterator {
        // The current token
        var $current;
 
-       /** 
+       /**
         * Construct a DelimIterator
+        * @param $delim string
+        * @param $s string
         */
        function __construct( $delim, $s ) {
                $this->subject = $s;
@@ -372,7 +469,6 @@ class ExplodeIterator implements Iterator {
                $this->refreshCurrent();
        }
 
-
        function refreshCurrent() {
                if ( $this->curPos === false ) {
                        $this->current = false;
@@ -393,6 +489,9 @@ class ExplodeIterator implements Iterator {
                return $this->curPos;
        }
 
+       /**
+        * @return string
+        */
        function next() {
                if ( $this->endPos === false ) {
                        $this->curPos = false;
@@ -408,8 +507,10 @@ class ExplodeIterator implements Iterator {
                return $this->current;
        }
 
+       /**
+        * @return bool
+        */
        function valid() {
                return $this->curPos !== false;
        }
 }
-