292 lines
		
	
	
		
			8.1 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			292 lines
		
	
	
		
			8.1 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
| <?php
 | |
| 
 | |
| /*
 | |
|  * This file is part of SwiftMailer.
 | |
|  * (c) 2004-2009 Chris Corbyn
 | |
|  *
 | |
|  * For the full copyright and license information, please view the LICENSE
 | |
|  * file that was distributed with this source code.
 | |
|  */
 | |
| 
 | |
| /**
 | |
|  * A CharacterStream implementation which stores characters in an internal array.
 | |
|  *
 | |
|  * @author Chris Corbyn
 | |
|  */
 | |
| class Swift_CharacterStream_ArrayCharacterStream implements Swift_CharacterStream
 | |
| {
 | |
|     /** A map of byte values and their respective characters */
 | |
|     private static $charMap;
 | |
| 
 | |
|     /** A map of characters and their derivative byte values */
 | |
|     private static $byteMap;
 | |
| 
 | |
|     /** The char reader (lazy-loaded) for the current charset */
 | |
|     private $charReader;
 | |
| 
 | |
|     /** A factory for creating CharacterReader instances */
 | |
|     private $charReaderFactory;
 | |
| 
 | |
|     /** The character set this stream is using */
 | |
|     private $charset;
 | |
| 
 | |
|     /** Array of characters */
 | |
|     private $array = [];
 | |
| 
 | |
|     /** Size of the array of character */
 | |
|     private $array_size = [];
 | |
| 
 | |
|     /** The current character offset in the stream */
 | |
|     private $offset = 0;
 | |
| 
 | |
|     /**
 | |
|      * Create a new CharacterStream with the given $chars, if set.
 | |
|      *
 | |
|      * @param Swift_CharacterReaderFactory $factory for loading validators
 | |
|      * @param string                       $charset used in the stream
 | |
|      */
 | |
|     public function __construct(Swift_CharacterReaderFactory $factory, $charset)
 | |
|     {
 | |
|         self::initializeMaps();
 | |
|         $this->setCharacterReaderFactory($factory);
 | |
|         $this->setCharacterSet($charset);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Set the character set used in this CharacterStream.
 | |
|      *
 | |
|      * @param string $charset
 | |
|      */
 | |
|     public function setCharacterSet($charset)
 | |
|     {
 | |
|         $this->charset = $charset;
 | |
|         $this->charReader = null;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Set the CharacterReaderFactory for multi charset support.
 | |
|      */
 | |
|     public function setCharacterReaderFactory(Swift_CharacterReaderFactory $factory)
 | |
|     {
 | |
|         $this->charReaderFactory = $factory;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Overwrite this character stream using the byte sequence in the byte stream.
 | |
|      *
 | |
|      * @param Swift_OutputByteStream $os output stream to read from
 | |
|      */
 | |
|     public function importByteStream(Swift_OutputByteStream $os)
 | |
|     {
 | |
|         if (!isset($this->charReader)) {
 | |
|             $this->charReader = $this->charReaderFactory
 | |
|                 ->getReaderFor($this->charset);
 | |
|         }
 | |
| 
 | |
|         $startLength = $this->charReader->getInitialByteSize();
 | |
|         while (false !== $bytes = $os->read($startLength)) {
 | |
|             $c = [];
 | |
|             for ($i = 0, $len = \strlen($bytes); $i < $len; ++$i) {
 | |
|                 $c[] = self::$byteMap[$bytes[$i]];
 | |
|             }
 | |
|             $size = \count($c);
 | |
|             $need = $this->charReader
 | |
|                 ->validateByteSequence($c, $size);
 | |
|             if ($need > 0 &&
 | |
|                 false !== $bytes = $os->read($need)) {
 | |
|                 for ($i = 0, $len = \strlen($bytes); $i < $len; ++$i) {
 | |
|                     $c[] = self::$byteMap[$bytes[$i]];
 | |
|                 }
 | |
|             }
 | |
|             $this->array[] = $c;
 | |
|             ++$this->array_size;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Import a string a bytes into this CharacterStream, overwriting any existing
 | |
|      * data in the stream.
 | |
|      *
 | |
|      * @param string $string
 | |
|      */
 | |
|     public function importString($string)
 | |
|     {
 | |
|         $this->flushContents();
 | |
|         $this->write($string);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Read $length characters from the stream and move the internal pointer
 | |
|      * $length further into the stream.
 | |
|      *
 | |
|      * @param int $length
 | |
|      *
 | |
|      * @return string
 | |
|      */
 | |
|     public function read($length)
 | |
|     {
 | |
|         if ($this->offset == $this->array_size) {
 | |
|             return false;
 | |
|         }
 | |
| 
 | |
|         // Don't use array slice
 | |
|         $arrays = [];
 | |
|         $end = $length + $this->offset;
 | |
|         for ($i = $this->offset; $i < $end; ++$i) {
 | |
|             if (!isset($this->array[$i])) {
 | |
|                 break;
 | |
|             }
 | |
|             $arrays[] = $this->array[$i];
 | |
|         }
 | |
|         $this->offset += $i - $this->offset; // Limit function calls
 | |
|         $chars = false;
 | |
|         foreach ($arrays as $array) {
 | |
|             $chars .= implode('', array_map('chr', $array));
 | |
|         }
 | |
| 
 | |
|         return $chars;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Read $length characters from the stream and return a 1-dimensional array
 | |
|      * containing there octet values.
 | |
|      *
 | |
|      * @param int $length
 | |
|      *
 | |
|      * @return int[]
 | |
|      */
 | |
|     public function readBytes($length)
 | |
|     {
 | |
|         if ($this->offset == $this->array_size) {
 | |
|             return false;
 | |
|         }
 | |
|         $arrays = [];
 | |
|         $end = $length + $this->offset;
 | |
|         for ($i = $this->offset; $i < $end; ++$i) {
 | |
|             if (!isset($this->array[$i])) {
 | |
|                 break;
 | |
|             }
 | |
|             $arrays[] = $this->array[$i];
 | |
|         }
 | |
|         $this->offset += ($i - $this->offset); // Limit function calls
 | |
| 
 | |
|         return array_merge(...$arrays);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Write $chars to the end of the stream.
 | |
|      *
 | |
|      * @param string $chars
 | |
|      */
 | |
|     public function write($chars)
 | |
|     {
 | |
|         if (!isset($this->charReader)) {
 | |
|             $this->charReader = $this->charReaderFactory->getReaderFor(
 | |
|                 $this->charset);
 | |
|         }
 | |
| 
 | |
|         $startLength = $this->charReader->getInitialByteSize();
 | |
| 
 | |
|         $fp = fopen('php://memory', 'w+b');
 | |
|         fwrite($fp, $chars);
 | |
|         unset($chars);
 | |
|         fseek($fp, 0, SEEK_SET);
 | |
| 
 | |
|         $buffer = [0];
 | |
|         $buf_pos = 1;
 | |
|         $buf_len = 1;
 | |
|         $has_datas = true;
 | |
|         do {
 | |
|             $bytes = [];
 | |
|             // Buffer Filing
 | |
|             if ($buf_len - $buf_pos < $startLength) {
 | |
|                 $buf = array_splice($buffer, $buf_pos);
 | |
|                 $new = $this->reloadBuffer($fp, 100);
 | |
|                 if ($new) {
 | |
|                     $buffer = array_merge($buf, $new);
 | |
|                     $buf_len = \count($buffer);
 | |
|                     $buf_pos = 0;
 | |
|                 } else {
 | |
|                     $has_datas = false;
 | |
|                 }
 | |
|             }
 | |
|             if ($buf_len - $buf_pos > 0) {
 | |
|                 $size = 0;
 | |
|                 for ($i = 0; $i < $startLength && isset($buffer[$buf_pos]); ++$i) {
 | |
|                     ++$size;
 | |
|                     $bytes[] = $buffer[$buf_pos++];
 | |
|                 }
 | |
|                 $need = $this->charReader->validateByteSequence(
 | |
|                     $bytes, $size);
 | |
|                 if ($need > 0) {
 | |
|                     if ($buf_len - $buf_pos < $need) {
 | |
|                         $new = $this->reloadBuffer($fp, $need);
 | |
| 
 | |
|                         if ($new) {
 | |
|                             $buffer = array_merge($buffer, $new);
 | |
|                             $buf_len = \count($buffer);
 | |
|                         }
 | |
|                     }
 | |
|                     for ($i = 0; $i < $need && isset($buffer[$buf_pos]); ++$i) {
 | |
|                         $bytes[] = $buffer[$buf_pos++];
 | |
|                     }
 | |
|                 }
 | |
|                 $this->array[] = $bytes;
 | |
|                 ++$this->array_size;
 | |
|             }
 | |
|         } while ($has_datas);
 | |
| 
 | |
|         fclose($fp);
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Move the internal pointer to $charOffset in the stream.
 | |
|      *
 | |
|      * @param int $charOffset
 | |
|      */
 | |
|     public function setPointer($charOffset)
 | |
|     {
 | |
|         if ($charOffset > $this->array_size) {
 | |
|             $charOffset = $this->array_size;
 | |
|         } elseif ($charOffset < 0) {
 | |
|             $charOffset = 0;
 | |
|         }
 | |
|         $this->offset = $charOffset;
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Empty the stream and reset the internal pointer.
 | |
|      */
 | |
|     public function flushContents()
 | |
|     {
 | |
|         $this->offset = 0;
 | |
|         $this->array = [];
 | |
|         $this->array_size = 0;
 | |
|     }
 | |
| 
 | |
|     private function reloadBuffer($fp, $len)
 | |
|     {
 | |
|         if (!feof($fp) && false !== ($bytes = fread($fp, $len))) {
 | |
|             $buf = [];
 | |
|             for ($i = 0, $len = \strlen($bytes); $i < $len; ++$i) {
 | |
|                 $buf[] = self::$byteMap[$bytes[$i]];
 | |
|             }
 | |
| 
 | |
|             return $buf;
 | |
|         }
 | |
| 
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     private static function initializeMaps()
 | |
|     {
 | |
|         if (!isset(self::$charMap)) {
 | |
|             self::$charMap = [];
 | |
|             for ($byte = 0; $byte < 256; ++$byte) {
 | |
|                 self::$charMap[$byte] = \chr($byte);
 | |
|             }
 | |
|             self::$byteMap = array_flip(self::$charMap);
 | |
|         }
 | |
|     }
 | |
| }
 |