[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/lib/horde/framework/Horde/Imap/Client/ -> Tokenize.php (source)

   1  <?php
   2  /**
   3   * Copyright 2012-2014 Horde LLC (http://www.horde.org/)
   4   *
   5   * See the enclosed file COPYING for license information (LGPL). If you
   6   * did not receive this file, see http://www.horde.org/licenses/lgpl21.
   7   *
   8   * @category  Horde
   9   * @copyright 2012-2014 Horde LLC
  10   * @license   http://www.horde.org/licenses/lgpl21 LGPL 2.1
  11   * @package   Imap_Client
  12   */
  13  
  14  /**
  15   * Tokenization of an IMAP data stream.
  16   *
  17   * NOTE: This class is NOT intended to be accessed outside of this package.
  18   * There is NO guarantees that the API of this class will not change across
  19   * versions.
  20   *
  21   * @author    Michael Slusarz <slusarz@horde.org>
  22   * @category  Horde
  23   * @copyright 2012-2014 Horde LLC
  24   * @internal
  25   * @license   http://www.horde.org/licenses/lgpl21 LGPL 2.1
  26   * @package   Imap_Client
  27   *
  28   * @property-read boolean $eos  Has the end of the stream been reached?
  29   */
  30  class Horde_Imap_Client_Tokenize implements Iterator
  31  {
  32      /**
  33       * Current data.
  34       *
  35       * @var mixed
  36       */
  37      protected $_current = false;
  38  
  39      /**
  40       * Current key.
  41       *
  42       * @var integer
  43       */
  44      protected $_key = false;
  45  
  46      /**
  47       * Sublevel.
  48       *
  49       * @var integer
  50       */
  51      protected $_level = false;
  52  
  53      /**
  54       * next() modifiers.
  55       *
  56       * @var array
  57       */
  58      protected $_nextModify = array();
  59  
  60      /**
  61       * Data stream.
  62       *
  63       * @var Horde_Stream
  64       */
  65      protected $_stream;
  66  
  67      /**
  68       * Constructor.
  69       *
  70       * @param mixed $data  Data to add (string, resource, or Horde_Stream
  71       *                     object).
  72       */
  73      public function __construct($data = null)
  74      {
  75          $this->_stream = new Horde_Stream_Temp();
  76  
  77          if (!is_null($data)) {
  78              $this->add($data);
  79          }
  80      }
  81  
  82      /**
  83       */
  84      public function __get($name)
  85      {
  86          switch ($name) {
  87          case 'eos':
  88              return $this->_stream->eof();
  89          }
  90      }
  91  
  92      /**
  93       */
  94      public function __sleep()
  95      {
  96          throw new LogicException('Object can not be serialized.');
  97      }
  98  
  99      /**
 100       */
 101      public function __toString()
 102      {
 103          $pos = $this->_stream->pos();
 104          $out = $this->_current . ' ' . $this->_stream->getString();
 105          $this->_stream->seek($pos, false);
 106          return $out;
 107      }
 108  
 109      /**
 110       * Add data to buffer.
 111       *
 112       * @param mixed $data  Data to add (string, resource, or Horde_Stream
 113       *                     object).
 114       */
 115      public function add($data)
 116      {
 117          $this->_stream->add($data);
 118      }
 119  
 120      /**
 121       * Flush the remaining entries left in the iterator.
 122       *
 123       * @param boolean $return    If true, return entries. Only returns entries
 124       *                           on the current level.
 125       * @param boolean $sublevel  Only flush items in current sublevel?
 126       *
 127       * @return array  The entries if $return is true.
 128       */
 129      public function flushIterator($return = true, $sublevel = true)
 130      {
 131          $out = array();
 132  
 133          if ($return) {
 134              $this->_nextModify = array(
 135                  'level' => $sublevel ? $this->_level : 0,
 136                  'out' => array()
 137              );
 138              $this->next();
 139              $out = $this->_nextModify['out'];
 140              $this->_nextModify = array();
 141          } elseif ($sublevel && $this->_level) {
 142              $this->_nextModify = array(
 143                  'level' => $this->_level
 144              );
 145              $this->next();
 146              $this->_nextModify = array();
 147          } else {
 148              $this->_stream->end();
 149              $this->_stream->getChar();
 150              $this->_current = $this->_key = $this->_level = false;
 151          }
 152  
 153          return $out;
 154      }
 155  
 156      /**
 157       * Return literal length data located at the end of the stream.
 158       *
 159       * @return mixed  Null if no literal data found, or an array with these
 160       *                keys:
 161       *   - binary: (boolean) True if this is a literal8.
 162       *   - length: (integer) Length of the literal.
 163       */
 164      public function getLiteralLength()
 165      {
 166          $this->_stream->end(-1);
 167          if ($this->_stream->peek() === '}') {
 168              $literal_data = $this->_stream->getString($this->_stream->search('{', true) - 1);
 169              $literal_len = substr($literal_data, 2, -1);
 170  
 171              if (is_numeric($literal_len)) {
 172                  return array(
 173                      'binary' => ($literal_data[0] === '~'),
 174                      'length' => intval($literal_len)
 175                  );
 176              }
 177          }
 178  
 179          return null;
 180      }
 181  
 182      /* Iterator methods. */
 183  
 184      /**
 185       */
 186      public function current()
 187      {
 188          return $this->_current;
 189      }
 190  
 191      /**
 192       */
 193      public function key()
 194      {
 195          return $this->_key;
 196      }
 197  
 198      /**
 199       * @return mixed  Either a string, boolean (true for open paren, false for
 200       *                close paren/EOS), or null.
 201       */
 202      public function next()
 203      {
 204          $level = isset($this->_nextModify['level'])
 205              ? $this->_nextModify['level']
 206              : null;
 207          /* Directly access stream here to drastically reduce the number of
 208           * getChar() calls we would have to make. */
 209          $stream = $this->_stream->stream;
 210  
 211          do {
 212              $check_len = true;
 213              $in_quote = $text = false;
 214  
 215              while (($c = fgetc($stream)) !== false) {
 216                  switch ($c) {
 217                  case '\\':
 218                      $text .= $in_quote
 219                          ? fgetc($stream)
 220                          : $c;
 221                      break;
 222  
 223                  case '"':
 224                      if ($in_quote) {
 225                          $check_len = false;
 226                          break 2;
 227                      }
 228                      $in_quote = true;
 229                      /* Set $text to non-false (could be empty string). */
 230                      $text = '';
 231                      break;
 232  
 233                  default:
 234                      if ($in_quote) {
 235                          $text .= $c;
 236                          break;
 237                      }
 238  
 239                      switch ($c) {
 240                      case '(':
 241                          ++$this->_level;
 242                          $check_len = false;
 243                          $text = true;
 244                          break 3;
 245  
 246                      case ')':
 247                          if ($text === false) {
 248                              --$this->_level;
 249                              $check_len = $text = false;
 250                          } else {
 251                              $this->_stream->seek(-1);
 252                          }
 253                          break 3;
 254  
 255                      case '~':
 256                          // Ignore binary string identifier. PHP strings are
 257                          // binary-safe.
 258                          break;
 259  
 260                      case '{':
 261                          $text = $this->_stream->substring(
 262                              0,
 263                              intval($this->_stream->getToChar('}'))
 264                          );
 265                          $check_len = false;
 266                          break 3;
 267  
 268                      case ' ':
 269                          if ($text !== false) {
 270                              break 3;
 271                          }
 272                          break;
 273  
 274                      default:
 275                          $text .= $c;
 276                          break;
 277                      }
 278                      break;
 279                  }
 280              }
 281  
 282              if ($check_len) {
 283                  switch (strlen($text)) {
 284                  case 0:
 285                      $text = false;
 286                      break;
 287  
 288                  case 3:
 289                      if (($text === 'NIL') || (strcasecmp($text, 'NIL') === 0)) {
 290                          $text = null;
 291                      }
 292                      break;
 293                  }
 294              }
 295  
 296              if (($text === false) && feof($stream)) {
 297                  $this->_key = $this->_level = false;
 298                  break;
 299              }
 300  
 301              ++$this->_key;
 302  
 303              if (is_null($level) || ($level > $this->_level)) {
 304                  break;
 305              }
 306  
 307              if (($level === $this->_level) && !is_bool($text)) {
 308                  $this->_nextModify['out'][] = $text;
 309              }
 310          } while (true);
 311  
 312          $this->_current = $text;
 313  
 314          return $text;
 315      }
 316  
 317      /**
 318       */
 319      public function rewind()
 320      {
 321          $this->_stream->rewind();
 322          $this->_current = false;
 323          $this->_key = -1;
 324          $this->_level = 0;
 325      }
 326  
 327      /**
 328       */
 329      public function valid()
 330      {
 331          return ($this->_level !== false);
 332      }
 333  
 334  }


Generated: Thu Aug 11 10:00:09 2016 Cross-referenced by PHPXref 0.7.1