TYPO3 API  SVNRelease
ByteArrayReplacementFilter.php
Go to the documentation of this file.
00001 <?php
00002 
00003 /*
00004  * This file is part of SwiftMailer.
00005  * (c) 2004-2009 Chris Corbyn
00006  *
00007  * For the full copyright and license information, please view the LICENSE
00008  * file that was distributed with this source code.
00009  */
00010 
00011 //@require 'Swift/StreamFilter.php';
00012 
00013 /**
00014  * Processes bytes as they pass through a buffer and replaces sequences in it.
00015  * This stream filter deals with Byte arrays rather than simple strings.
00016  * @package Swift
00017  * @author Chris Corbyn
00018  */
00019 class Swift_StreamFilters_ByteArrayReplacementFilter
00020   implements Swift_StreamFilter
00021 {
00022 
00023   /** The needle(s) to search for */
00024   private $_search;
00025 
00026   /** The replacement(s) to make */
00027   private $_replace;
00028 
00029   /** The Index for searching */
00030   private $_index;
00031 
00032   /** The Search Tree */
00033   private $_tree = array();
00034 
00035   /**  Gives the size of the largest search */
00036   private $_treeMaxLen = 0;
00037 
00038   private $_repSize;
00039 
00040   /**
00041    * Create a new ByteArrayReplacementFilter with $search and $replace.
00042    * @param array $search
00043    * @param array $replace
00044    */
00045   public function __construct($search, $replace)
00046   {
00047     $this->_search = $search;
00048     $this->_index = array();
00049     $this->_tree = array();
00050     $this->_replace = array();
00051     $this->_repSize = array();
00052 
00053     $tree = null;
00054     $i = null;
00055     $last_size = $size = 0;
00056     foreach ($search as $i => $search_element)
00057     {
00058       if ($tree !== null)
00059       {
00060         $tree[-1] = min (count($replace) - 1, $i - 1);
00061         $tree[-2] = $last_size;
00062       }
00063       $tree = &$this->_tree;
00064       if (is_array ($search_element))
00065       {
00066         foreach ($search_element as $k => $char)
00067         {
00068           $this->_index[$char] = true;
00069           if (!isset($tree[$char]))
00070           {
00071             $tree[$char] = array();
00072           }
00073           $tree = &$tree[$char];
00074         }
00075         $last_size = $k+1;
00076         $size = max($size, $last_size);
00077       }
00078       else
00079       {
00080         $last_size = 1;
00081         if (!isset($tree[$search_element]))
00082         {
00083           $tree[$search_element] = array();
00084         }
00085         $tree = &$tree[$search_element];
00086         $size = max($last_size, $size);
00087         $this->_index[$search_element] = true;
00088       }
00089     }
00090     if ($i !== null)
00091     {
00092       $tree[-1] = min (count ($replace) - 1, $i);
00093       $tree[-2] = $last_size;
00094       $this->_treeMaxLen = $size;
00095     }
00096     foreach ($replace as $rep)
00097     {
00098       if (!is_array($rep))
00099       {
00100         $rep = array ($rep);
00101       }
00102       $this->_replace[] = $rep;
00103     }
00104     for ($i = count($this->_replace) - 1; $i >= 0; --$i)
00105     {
00106       $this->_replace[$i] = $rep = $this->filter($this->_replace[$i], $i);
00107       $this->_repSize[$i] = count($rep);
00108     }
00109   }
00110 
00111   /**
00112    * Returns true if based on the buffer passed more bytes should be buffered.
00113    * @param array $buffer
00114    * @return boolean
00115    */
00116   public function shouldBuffer($buffer)
00117   {
00118     $endOfBuffer = end($buffer);
00119     return isset ($this->_index[$endOfBuffer]);
00120   }
00121 
00122   /**
00123    * Perform the actual replacements on $buffer and return the result.
00124    * @param array $buffer
00125    * @return array
00126    */
00127   public function filter($buffer, $_minReplaces = -1)
00128   {
00129     if ($this->_treeMaxLen == 0)
00130     {
00131       return $buffer;
00132     }
00133 
00134     $newBuffer = array();
00135     $buf_size = count($buffer);
00136     for ($i = 0; $i < $buf_size; ++$i)
00137     {
00138       $search_pos = $this->_tree;
00139       $last_found = PHP_INT_MAX;
00140       // We try to find if the next byte is part of a search pattern
00141       for ($j = 0; $j <= $this->_treeMaxLen; ++$j)
00142       {
00143         // We have a new byte for a search pattern
00144         if (isset ($buffer [$p = $i + $j]) && isset($search_pos[$buffer[$p]]))
00145         {
00146           $search_pos = $search_pos[$buffer[$p]];
00147           // We have a complete pattern, save, in case we don't find a better match later
00148           if (isset($search_pos[- 1]) && $search_pos[-1] < $last_found
00149             && $search_pos[-1] > $_minReplaces)
00150           {
00151             $last_found = $search_pos[-1];
00152             $last_size = $search_pos[-2];
00153           }
00154         }
00155         // We got a complete pattern
00156         elseif ($last_found !== PHP_INT_MAX)
00157         {
00158           // Adding replacement datas to output buffer
00159           $rep_size = $this->_repSize[$last_found];
00160           for ($j = 0; $j < $rep_size; ++$j)
00161           {
00162             $newBuffer[] = $this->_replace[$last_found][$j];
00163           }
00164           // We Move cursor forward
00165           $i += $last_size - 1;
00166           // Edge Case, last position in buffer
00167           if ($i >= $buf_size)
00168           {
00169             $newBuffer[] = $buffer[$i];
00170           }
00171 
00172           // We start the next loop
00173           continue 2;
00174         }
00175         else
00176         {
00177           // this byte is not in a pattern and we haven't found another pattern
00178           break;
00179         }
00180       }
00181       // Normal byte, move it to output buffer
00182       $newBuffer[] = $buffer[$i];
00183     }
00184 
00185     return $newBuffer;
00186   }
00187 
00188 }