1<?php 2 3/* 4 * This file is part of SwiftMailer. 5 * (c) 2004-2009 Chris Corbyn 6 * 7 * For the full copyright and license information, please view the LICENSE 8 * file that was distributed with this source code. 9 */ 10 11/** 12 * A CharacterStream implementation which stores characters in an internal array. 13 * 14 * @author Xavier De Cock <xdecock@gmail.com> 15 */ 16class Swift_CharacterStream_NgCharacterStream implements Swift_CharacterStream 17{ 18 /** 19 * The char reader (lazy-loaded) for the current charset. 20 * 21 * @var Swift_CharacterReader 22 */ 23 private $_charReader; 24 25 /** 26 * A factory for creating CharacterReader instances. 27 * 28 * @var Swift_CharacterReaderFactory 29 */ 30 private $_charReaderFactory; 31 32 /** 33 * The character set this stream is using. 34 * 35 * @var string 36 */ 37 private $_charset; 38 39 /** 40 * The data's stored as-is. 41 * 42 * @var string 43 */ 44 private $_datas = ''; 45 46 /** 47 * Number of bytes in the stream. 48 * 49 * @var int 50 */ 51 private $_datasSize = 0; 52 53 /** 54 * Map. 55 * 56 * @var mixed 57 */ 58 private $_map; 59 60 /** 61 * Map Type. 62 * 63 * @var int 64 */ 65 private $_mapType = 0; 66 67 /** 68 * Number of characters in the stream. 69 * 70 * @var int 71 */ 72 private $_charCount = 0; 73 74 /** 75 * Position in the stream. 76 * 77 * @var int 78 */ 79 private $_currentPos = 0; 80 81 /** 82 * Constructor. 83 * 84 * @param Swift_CharacterReaderFactory $factory 85 * @param string $charset 86 */ 87 public function __construct(Swift_CharacterReaderFactory $factory, $charset) 88 { 89 $this->setCharacterReaderFactory($factory); 90 $this->setCharacterSet($charset); 91 } 92 93 /* -- Changing parameters of the stream -- */ 94 95 /** 96 * Set the character set used in this CharacterStream. 97 * 98 * @param string $charset 99 */ 100 public function setCharacterSet($charset) 101 { 102 $this->_charset = $charset; 103 $this->_charReader = null; 104 $this->_mapType = 0; 105 } 106 107 /** 108 * Set the CharacterReaderFactory for multi charset support. 109 * 110 * @param Swift_CharacterReaderFactory $factory 111 */ 112 public function setCharacterReaderFactory(Swift_CharacterReaderFactory $factory) 113 { 114 $this->_charReaderFactory = $factory; 115 } 116 117 /** 118 * @see Swift_CharacterStream::flushContents() 119 */ 120 public function flushContents() 121 { 122 $this->_datas = null; 123 $this->_map = null; 124 $this->_charCount = 0; 125 $this->_currentPos = 0; 126 $this->_datasSize = 0; 127 } 128 129 /** 130 * @see Swift_CharacterStream::importByteStream() 131 * 132 * @param Swift_OutputByteStream $os 133 */ 134 public function importByteStream(Swift_OutputByteStream $os) 135 { 136 $this->flushContents(); 137 $blocks = 512; 138 $os->setReadPointer(0); 139 while (false !== ($read = $os->read($blocks))) { 140 $this->write($read); 141 } 142 } 143 144 /** 145 * @see Swift_CharacterStream::importString() 146 * 147 * @param string $string 148 */ 149 public function importString($string) 150 { 151 $this->flushContents(); 152 $this->write($string); 153 } 154 155 /** 156 * @see Swift_CharacterStream::read() 157 * 158 * @param int $length 159 * 160 * @return string 161 */ 162 public function read($length) 163 { 164 if ($this->_currentPos >= $this->_charCount) { 165 return false; 166 } 167 $ret = false; 168 $length = $this->_currentPos + $length > $this->_charCount ? $this->_charCount - $this->_currentPos : $length; 169 switch ($this->_mapType) { 170 case Swift_CharacterReader::MAP_TYPE_FIXED_LEN: 171 $len = $length * $this->_map; 172 $ret = substr($this->_datas, 173 $this->_currentPos * $this->_map, 174 $len); 175 $this->_currentPos += $length; 176 break; 177 178 case Swift_CharacterReader::MAP_TYPE_INVALID: 179 $ret = ''; 180 for (; $this->_currentPos < $length; ++$this->_currentPos) { 181 if (isset($this->_map[$this->_currentPos])) { 182 $ret .= '?'; 183 } else { 184 $ret .= $this->_datas[$this->_currentPos]; 185 } 186 } 187 break; 188 189 case Swift_CharacterReader::MAP_TYPE_POSITIONS: 190 $end = $this->_currentPos + $length; 191 $end = $end > $this->_charCount ? $this->_charCount : $end; 192 $ret = ''; 193 $start = 0; 194 if ($this->_currentPos > 0) { 195 $start = $this->_map['p'][$this->_currentPos - 1]; 196 } 197 $to = $start; 198 for (; $this->_currentPos < $end; ++$this->_currentPos) { 199 if (isset($this->_map['i'][$this->_currentPos])) { 200 $ret .= substr($this->_datas, $start, $to - $start).'?'; 201 $start = $this->_map['p'][$this->_currentPos]; 202 } else { 203 $to = $this->_map['p'][$this->_currentPos]; 204 } 205 } 206 $ret .= substr($this->_datas, $start, $to - $start); 207 break; 208 } 209 210 return $ret; 211 } 212 213 /** 214 * @see Swift_CharacterStream::readBytes() 215 * 216 * @param int $length 217 * 218 * @return int[] 219 */ 220 public function readBytes($length) 221 { 222 $read = $this->read($length); 223 if ($read !== false) { 224 $ret = array_map('ord', str_split($read, 1)); 225 226 return $ret; 227 } 228 229 return false; 230 } 231 232 /** 233 * @see Swift_CharacterStream::setPointer() 234 * 235 * @param int $charOffset 236 */ 237 public function setPointer($charOffset) 238 { 239 if ($this->_charCount < $charOffset) { 240 $charOffset = $this->_charCount; 241 } 242 $this->_currentPos = $charOffset; 243 } 244 245 /** 246 * @see Swift_CharacterStream::write() 247 * 248 * @param string $chars 249 */ 250 public function write($chars) 251 { 252 if (!isset($this->_charReader)) { 253 $this->_charReader = $this->_charReaderFactory->getReaderFor( 254 $this->_charset); 255 $this->_map = array(); 256 $this->_mapType = $this->_charReader->getMapType(); 257 } 258 $ignored = ''; 259 $this->_datas .= $chars; 260 $this->_charCount += $this->_charReader->getCharPositions(substr($this->_datas, $this->_datasSize), $this->_datasSize, $this->_map, $ignored); 261 if ($ignored !== false) { 262 $this->_datasSize = strlen($this->_datas) - strlen($ignored); 263 } else { 264 $this->_datasSize = strlen($this->_datas); 265 } 266 } 267} 268