[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
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 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Aug 11 10:00:09 2016 | Cross-referenced by PHPXref 0.7.1 |