PageRenderTime 45ms CodeModel.GetById 35ms app.highlight 7ms RepoModel.GetById 1ms app.codeStats 0ms

/framework/vendor/swift/lib/classes/Swift/CharacterStream/ArrayCharacterStream.php

http://zoop.googlecode.com/
PHP | 319 lines | 218 code | 31 blank | 70 comment | 31 complexity | 749721908c6db791129ec7c1c9681bae MD5 | raw file
  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 */
 21class 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}