199 lines
5.2 KiB
PHP
199 lines
5.2 KiB
PHP
<?php
|
|
|
|
/*
|
|
ByteArrayReplacementFilter from Swift Mailer.
|
|
|
|
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 3 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, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
//@require 'Swift/StreamFilter.php';
|
|
|
|
/**
|
|
* Processes bytes as they pass through a buffer and replaces sequences in it.
|
|
* This stream filter deals with Byte arrays rather than simple strings.
|
|
* @package Swift
|
|
* @author Chris Corbyn
|
|
*/
|
|
class Swift_StreamFilters_ByteArrayReplacementFilter
|
|
implements Swift_StreamFilter
|
|
{
|
|
|
|
/** The needle(s) to search for */
|
|
private $_search;
|
|
|
|
/** The replacement(s) to make */
|
|
private $_replace;
|
|
|
|
/** The Index for searching */
|
|
private $_index;
|
|
|
|
/** The Search Tree */
|
|
private $_tree = array();
|
|
|
|
/** Gives the size of the largest search */
|
|
private $_treeMaxLen = 0;
|
|
|
|
private $_repSize;
|
|
|
|
/**
|
|
* Create a new ByteArrayReplacementFilter with $search and $replace.
|
|
* @param array $search
|
|
* @param array $replace
|
|
*/
|
|
public function __construct($search, $replace)
|
|
{
|
|
$this->_search = $search;
|
|
$this->_index = array();
|
|
$this->_tree = array();
|
|
$this->_replace = array();
|
|
$this->_repSize = array();
|
|
|
|
$tree = null;
|
|
$i = null;
|
|
$last_size = $size = 0;
|
|
foreach ($search as $i => $search_element)
|
|
{
|
|
if ($tree !== null)
|
|
{
|
|
$tree[-1] = min (count($replace) - 1, $i - 1);
|
|
$tree[-2] = $last_size;
|
|
}
|
|
$tree = &$this->_tree;
|
|
if (is_array ($search_element))
|
|
{
|
|
foreach ($search_element as $k => $char)
|
|
{
|
|
$this->_index[$char] = true;
|
|
if (!isset($tree[$char]))
|
|
{
|
|
$tree[$char] = array();
|
|
}
|
|
$tree = &$tree[$char];
|
|
}
|
|
$last_size = $k+1;
|
|
$size = max($size, $last_size);
|
|
}
|
|
else
|
|
{
|
|
$last_size = 1;
|
|
if (!isset($tree[$search_element]))
|
|
{
|
|
$tree[$search_element] = array();
|
|
}
|
|
$tree = &$tree[$search_element];
|
|
$size = max($last_size, $size);
|
|
$this->_index[$search_element] = true;
|
|
}
|
|
}
|
|
if ($i !== null)
|
|
{
|
|
$tree[-1] = min (count ($replace) - 1, $i);
|
|
$tree[-2] = $last_size;
|
|
$this->_treeMaxLen = $size;
|
|
}
|
|
foreach ($replace as $rep)
|
|
{
|
|
if (!is_array($rep))
|
|
{
|
|
$rep = array ($rep);
|
|
}
|
|
$this->_replace[] = $rep;
|
|
}
|
|
for ($i = count($this->_replace) - 1; $i >= 0; --$i)
|
|
{
|
|
$this->_replace[$i] = $rep = $this->filter($this->_replace[$i], $i);
|
|
$this->_repSize[$i] = count($rep);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns true if based on the buffer passed more bytes should be buffered.
|
|
* @param array $buffer
|
|
* @return boolean
|
|
*/
|
|
public function shouldBuffer($buffer)
|
|
{
|
|
$endOfBuffer = end($buffer);
|
|
return isset ($this->_index[$endOfBuffer]);
|
|
}
|
|
|
|
/**
|
|
* Perform the actual replacements on $buffer and return the result.
|
|
* @param array $buffer
|
|
* @return array
|
|
*/
|
|
public function filter($buffer, $_minReplaces = -1)
|
|
{
|
|
if ($this->_treeMaxLen == 0)
|
|
{
|
|
return $buffer;
|
|
}
|
|
|
|
$newBuffer = array();
|
|
$buf_size = count($buffer);
|
|
for ($i = 0; $i < $buf_size; ++$i)
|
|
{
|
|
$search_pos = $this->_tree;
|
|
$last_found = PHP_INT_MAX;
|
|
// We try to find if the next byte is part of a search pattern
|
|
for ($j = 0; $j <= $this->_treeMaxLen; ++$j)
|
|
{
|
|
// We have a new byte for a search pattern
|
|
if (isset ($buffer [$p = $i + $j]) && isset($search_pos[$buffer[$p]]))
|
|
{
|
|
$search_pos = $search_pos[$buffer[$p]];
|
|
// We have a complete pattern, save, in case we don't find a better match later
|
|
if (isset($search_pos[- 1]) && $search_pos[-1] < $last_found
|
|
&& $search_pos[-1] > $_minReplaces)
|
|
{
|
|
$last_found = $search_pos[-1];
|
|
$last_size = $search_pos[-2];
|
|
}
|
|
}
|
|
// We got a complete pattern
|
|
elseif ($last_found !== PHP_INT_MAX)
|
|
{
|
|
// Adding replacement datas to output buffer
|
|
$rep_size = $this->_repSize[$last_found];
|
|
for ($j = 0; $j < $rep_size; ++$j)
|
|
{
|
|
$newBuffer[] = $this->_replace[$last_found][$j];
|
|
}
|
|
// We Move cursor forward
|
|
$i += $last_size - 1;
|
|
// Edge Case, last position in buffer
|
|
if ($i >= $buf_size)
|
|
{
|
|
$newBuffer[] = $buffer[$i];
|
|
}
|
|
|
|
// We start the next loop
|
|
continue 2;
|
|
}
|
|
else
|
|
{
|
|
// this byte is not in a pattern and we haven't found another pattern
|
|
break;
|
|
}
|
|
}
|
|
// Normal byte, move it to output buffer
|
|
$newBuffer[] = $buffer[$i];
|
|
}
|
|
|
|
return $newBuffer;
|
|
}
|
|
|
|
}
|