1<?php
2
3/*
4 CharacterStream implementation using an array in Swift Mailer.
5
6 This program is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program.  If not, see <http://www.gnu.org/licenses/>.
18
19 */
20
21//@require 'Swift/CharacterStream.php';
22//@require 'Swift/OutputByteStream.php';
23
24
25/**
26 * A CharacterStream implementation which stores characters in an internal array.
27 * @package Swift
28 * @subpackage CharacterStream
29 * @author Xavier De Cock <xdecock@gmail.com>
30 */
31
32Class Swift_CharacterStream_NgCharacterStream
33  implements Swift_CharacterStream
34{
35
36  /**
37   * The char reader (lazy-loaded) for the current charset.
38   * @var Swift_CharacterReader
39   * @access private
40   */
41  private $_charReader;
42
43  /**
44   * A factory for creatiing CharacterReader instances.
45   * @var Swift_CharacterReaderFactory
46   * @access private
47   */
48  private $_charReaderFactory;
49
50  /**
51   * The character set this stream is using.
52   * @var string
53   * @access private
54   */
55  private $_charset;
56
57  /**
58   * The datas stored as is
59   *
60   * @var string
61   */
62  private $_datas = "";
63
64  /**
65   * Number of bytes in the stream
66   *
67   * @var int
68   */
69  private $_datasSize = 0;
70
71  /**
72   * Map
73   *
74   * @var mixed
75   */
76  private $_map;
77
78  /**
79   * Map Type
80   *
81   * @var int
82   */
83  private $_mapType = 0;
84
85  /**
86   * Number of characters in the stream
87   *
88   * @var int
89   */
90  private $_charCount = 0;
91
92  /**
93   * Position in the stream
94   *
95   * @var unknown_type
96   */
97  private $_currentPos = 0;
98
99  /**
100   * The constructor
101   *
102   * @param Swift_CharacterReaderFactory $factory
103   * @param unknown_type $charset
104   */
105  public function __construct(Swift_CharacterReaderFactory $factory,
106    $charset)
107  {
108    $this->setCharacterReaderFactory($factory);
109    $this->setCharacterSet($charset);
110  }
111
112  /* -- Changing parameters of the stream -- */
113
114  /**
115   * Set the character set used in this CharacterStream.
116   * @param string $charset
117   */
118  public function setCharacterSet($charset)
119  {
120    $this->_charset = $charset;
121    $this->_charReader = null;
122  	$this->_mapType = 0;
123  }
124
125  /**
126   * Set the CharacterReaderFactory for multi charset support.
127   * @param Swift_CharacterReaderFactory $factory
128   */
129  public function setCharacterReaderFactory(
130    Swift_CharacterReaderFactory $factory)
131  {
132    $this->_charReaderFactory = $factory;
133  }
134
135  /**
136   * @see Swift_CharacterStream::flushContents()
137   *
138   */
139  public function flushContents()
140  {
141  	$this->_datas = null;
142  	$this->_map = null;
143  	$this->_charCount = 0;
144  	$this->_currentPos = 0;
145  	$this->_datasSize = 0;
146  }
147
148  /**
149   * @see Swift_CharacterStream::importByteStream()
150   *
151   * @param Swift_OutputByteStream $os
152   */
153  public function importByteStream(Swift_OutputByteStream $os)
154  {
155    $this->flushContents();
156    $blocks=512;
157    $os->setReadPointer(0);
158    while(false!==($read = $os->read($blocks)))
159      $this->write($read);
160  }
161
162  /**
163   * @see Swift_CharacterStream::importString()
164   *
165   * @param string $string
166   */
167  public function importString($string)
168  {
169    $this->flushContents();
170    $this->write($string);
171  }
172
173  /**
174   * @see Swift_CharacterStream::read()
175   *
176   * @param int $length
177   * @return string
178   */
179  public function read($length)
180  {
181  	if ($this->_currentPos>=$this->_charCount)
182  	{
183  	  return false;
184  	}
185  	$ret=false;
186  	$length = ($this->_currentPos+$length > $this->_charCount)
187  	  ? $this->_charCount - $this->_currentPos
188  	  : $length;
189  	  switch ($this->_mapType)
190  	{
191      case Swift_CharacterReader::MAP_TYPE_FIXED_LEN:
192        $len = $length*$this->_map;
193        $ret = substr($this->_datas,
194            $this->_currentPos * $this->_map,
195            $len);
196        $this->_currentPos += $length;
197        break;
198
199      case Swift_CharacterReader::MAP_TYPE_INVALID:
200        $end = $this->_currentPos + $length;
201        $end = $end > $this->_charCount
202          ?$this->_charCount
203          :$end;
204        $ret = '';
205        for (; $this->_currentPos < $length; ++$this->_currentPos)
206        {
207          if (isset ($this->_map[$this->_currentPos]))
208          {
209            $ret .= '?';
210          }
211          else
212          {
213            $ret .= $this->_datas[$this->_currentPos];
214          }
215        }
216        break;
217
218      case Swift_CharacterReader::MAP_TYPE_POSITIONS:
219        $end = $this->_currentPos + $length;
220        $end = $end > $this->_charCount
221          ?$this->_charCount
222          :$end;
223        $ret = '';
224        $start = 0;
225        if ($this->_currentPos>0)
226        {
227          $start = $this->_map['p'][$this->_currentPos-1];
228        }
229        $to = $start;
230        for (; $this->_currentPos < $end; ++$this->_currentPos)
231        {
232          if (isset($this->_map['i'][$this->_currentPos])) {
233          	$ret .= substr($this->_datas, $start, $to - $start).'?';
234          	$start = $this->_map['p'][$this->_currentPos];
235          } else {
236          	$to = $this->_map['p'][$this->_currentPos];
237          }
238        }
239        $ret .= substr($this->_datas, $start, $to - $start);
240        break;
241  	}
242  	return $ret;
243  }
244
245  /**
246   * @see Swift_CharacterStream::readBytes()
247   *
248   * @param int $length
249   * @return int[]
250   */
251  public function readBytes($length)
252  {
253    $read=$this->read($length);
254  	if ($read!==false)
255  	{
256      $ret = array_map('ord', str_split($read, 1));
257      return $ret;
258  	}
259  	return false;
260  }
261
262  /**
263   * @see Swift_CharacterStream::setPointer()
264   *
265   * @param int $charOffset
266   */
267  public function setPointer($charOffset)
268  {
269  	if ($this->_charCount<$charOffset){
270  		$charOffset=$this->_charCount;
271  	}
272  	$this->_currentPos = $charOffset;
273  }
274
275  /**
276   * @see Swift_CharacterStream::write()
277   *
278   * @param string $chars
279   */
280  public function write($chars)
281  {
282  	if (!isset($this->_charReader))
283    {
284      $this->_charReader = $this->_charReaderFactory->getReaderFor(
285        $this->_charset);
286      $this->_map = array();
287      $this->_mapType = $this->_charReader->getMapType();
288    }
289  	$ignored='';
290  	$this->_datas .= $chars;
291    $this->_charCount += $this->_charReader->getCharPositions(substr($this->_datas, $this->_datasSize), $this->_datasSize, $this->_map, $ignored);
292    if ($ignored!==false) {
293      $this->_datasSize=strlen($this->_datas)-strlen($ignored);
294    }
295    else
296    {
297      $this->_datasSize=strlen($this->_datas);
298    }
299  }
300}