Added feature #15998: Create a new API to send mails based on SwiftMailer to replace...
[Packages/TYPO3.CMS.git] / typo3 / contrib / swiftmailer / classes / Swift / CharacterStream / ArrayCharacterStream.php
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 //@require 'Swift/CharacterStream.php';
12 //@require 'Swift/OutputByteStream.php';
13
14
15 /**
16 * A CharacterStream implementation which stores characters in an internal array.
17 * @package Swift
18 * @subpackage CharacterStream
19 * @author Chris Corbyn
20 */
21 class Swift_CharacterStream_ArrayCharacterStream
22 implements Swift_CharacterStream
23 {
24
25 /** A map of byte values and their respective characters */
26 private static $_charMap;
27
28 /** A map of characters and their derivative byte values */
29 private static $_byteMap;
30
31 /** The char reader (lazy-loaded) for the current charset */
32 private $_charReader;
33
34 /** A factory for creatiing CharacterReader instances */
35 private $_charReaderFactory;
36
37 /** The character set this stream is using */
38 private $_charset;
39
40 /** Array of characters */
41 private $_array = array();
42
43 /** Size of the array of character */
44 private $_array_size = array();
45
46 /** The current character offset in the stream */
47 private $_offset = 0;
48
49 /**
50 * Create a new CharacterStream with the given $chars, if set.
51 * @param Swift_CharacterReaderFactory $factory for loading validators
52 * @param string $charset used in the stream
53 */
54 public function __construct(Swift_CharacterReaderFactory $factory,
55 $charset)
56 {
57 self::_initializeMaps();
58 $this->setCharacterReaderFactory($factory);
59 $this->setCharacterSet($charset);
60 }
61
62 /**
63 * Set the character set used in this CharacterStream.
64 * @param string $charset
65 */
66 public function setCharacterSet($charset)
67 {
68 $this->_charset = $charset;
69 $this->_charReader = null;
70 }
71
72 /**
73 * Set the CharacterReaderFactory for multi charset support.
74 * @param Swift_CharacterReaderFactory $factory
75 */
76 public function setCharacterReaderFactory(
77 Swift_CharacterReaderFactory $factory)
78 {
79 $this->_charReaderFactory = $factory;
80 }
81
82 /**
83 * Overwrite this character stream using the byte sequence in the byte stream.
84 * @param Swift_OutputByteStream $os output stream to read from
85 */
86 public function importByteStream(Swift_OutputByteStream $os)
87 {
88 if (!isset($this->_charReader))
89 {
90 $this->_charReader = $this->_charReaderFactory
91 ->getReaderFor($this->_charset);
92 }
93
94 $startLength = $this->_charReader->getInitialByteSize();
95 while (false !== $bytes = $os->read($startLength))
96 {
97 $c = array();
98 for ($i = 0, $len = strlen($bytes); $i < $len; ++$i)
99 {
100 $c[] = self::$_byteMap[$bytes[$i]];
101 }
102 $size = count($c);
103 $need = $this->_charReader
104 ->validateByteSequence($c, $size);
105 if ($need > 0 &&
106 false !== $bytes = $os->read($need))
107 {
108 for ($i = 0, $len = strlen($bytes); $i < $len; ++$i)
109 {
110 $c[] = self::$_byteMap[$bytes[$i]];
111 }
112 }
113 $this->_array[] = $c;
114 ++$this->_array_size;
115 }
116 }
117
118 /**
119 * Import a string a bytes into this CharacterStream, overwriting any existing
120 * data in the stream.
121 * @param string $string
122 */
123 public function importString($string)
124 {
125 $this->flushContents();
126 $this->write($string);
127 }
128
129 /**
130 * Read $length characters from the stream and move the internal pointer
131 * $length further into the stream.
132 * @param int $length
133 * @return string
134 */
135 public function read($length)
136 {
137 if ($this->_offset == $this->_array_size)
138 {
139 return false;
140 }
141
142 // Don't use array slice
143 $arrays = array();
144 $end = $length + $this->_offset;
145 for ($i = $this->_offset; $i < $end; ++$i)
146 {
147 if (!isset($this->_array[$i]))
148 {
149 break;
150 }
151 $arrays[] = $this->_array[$i];
152 }
153 $this->_offset += $i - $this->_offset; // Limit function calls
154 $chars = false;
155 foreach ($arrays as $array)
156 {
157 $chars .= implode('', array_map('chr', $array));
158 }
159 return $chars;
160 }
161
162 /**
163 * Read $length characters from the stream and return a 1-dimensional array
164 * containing there octet values.
165 * @param int $length
166 * @return int[]
167 */
168 public function readBytes($length)
169 {
170 if ($this->_offset == $this->_array_size)
171 {
172 return false;
173 }
174 $arrays = array();
175 $end = $length + $this->_offset;
176 for ($i = $this->_offset; $i < $end; ++$i)
177 {
178 if (!isset($this->_array[$i]))
179 {
180 break;
181 }
182 $arrays[] = $this->_array[$i];
183 }
184 $this->_offset += ($i - $this->_offset); // Limit function calls
185 return call_user_func_array('array_merge', $arrays);
186 }
187
188 /**
189 * Write $chars to the end of the stream.
190 * @param string $chars
191 */
192 public function write($chars)
193 {
194 if (!isset($this->_charReader))
195 {
196 $this->_charReader = $this->_charReaderFactory->getReaderFor(
197 $this->_charset);
198 }
199
200 $startLength = $this->_charReader->getInitialByteSize();
201
202 $fp = fopen('php://memory', 'w+b');
203 fwrite($fp, $chars);
204 unset($chars);
205 fseek($fp, 0, SEEK_SET);
206
207 $buffer = array(0);
208 $buf_pos = 1;
209 $buf_len = 1;
210 $has_datas = true;
211 do
212 {
213 $bytes = array();
214 // Buffer Filing
215 if ($buf_len - $buf_pos < $startLength)
216 {
217 $buf = array_splice($buffer, $buf_pos);
218 $new = $this->_reloadBuffer($fp, 100);
219 if ($new)
220 {
221 $buffer = array_merge($buf, $new);
222 $buf_len = count($buffer);
223 $buf_pos = 0;
224 }
225 else
226 {
227 $has_datas = false;
228 }
229 }
230 if ($buf_len - $buf_pos > 0)
231 {
232 $size = 0;
233 for ($i = 0; $i < $startLength && isset($buffer[$buf_pos]); ++$i)
234 {
235 ++$size;
236 $bytes[] = $buffer[$buf_pos++];
237 }
238 $need = $this->_charReader->validateByteSequence(
239 $bytes, $size);
240 if ($need > 0)
241 {
242 if ($buf_len - $buf_pos < $need)
243 {
244 $new = $this->_reloadBuffer($fp, $need);
245
246 if ($new)
247 {
248 $buffer = array_merge($buffer, $new);
249 $buf_len = count($buffer);
250 }
251 }
252 for ($i = 0; $i < $need && isset($buffer[$buf_pos]); ++$i)
253 {
254 $bytes[] = $buffer[$buf_pos++];
255 }
256 }
257 $this->_array[] = $bytes;
258 ++$this->_array_size;
259 }
260 }
261 while ($has_datas);
262
263 fclose($fp);
264 }
265
266 /**
267 * Move the internal pointer to $charOffset in the stream.
268 * @param int $charOffset
269 */
270 public function setPointer($charOffset)
271 {
272 if ($charOffset > $this->_array_size)
273 {
274 $charOffset = $this->_array_size;
275 }
276 elseif ($charOffset < 0)
277 {
278 $charOffset = 0;
279 }
280 $this->_offset = $charOffset;
281 }
282
283 /**
284 * Empty the stream and reset the internal pointer.
285 */
286 public function flushContents()
287 {
288 $this->_offset = 0;
289 $this->_array = array();
290 $this->_array_size = 0;
291 }
292
293 private function _reloadBuffer($fp, $len)
294 {
295 if (!feof($fp) && ($bytes = fread($fp, $len)) !== false)
296 {
297 $buf = array();
298 for ($i = 0, $len = strlen($bytes); $i < $len; ++$i)
299 {
300 $buf[] = self::$_byteMap[$bytes[$i]];
301 }
302 return $buf;
303 }
304 return false;
305 }
306
307 private static function _initializeMaps()
308 {
309 if (!isset(self::$_charMap))
310 {
311 self::$_charMap = array();
312 for ($byte = 0; $byte < 256; ++$byte)
313 {
314 self::$_charMap[$byte] = chr($byte);
315 }
316 self::$_byteMap = array_flip(self::$_charMap);
317 }
318 }
319 }