123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291 |
- <?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);
- }
- }
- }
|