* @since 1.1.0.0 * @link http://tools.ietf.org/html/rfc2425 * @package Mammut\Documents */ class RFC2425Parser extends StrictObject { /** * Identifier regular expression * * @var string */ const RE_ID = '[0-9a-zA-Z-]+'; protected $decodeQuoted = false; /** * @var iLineReader */ protected $reader; /** * @var object */ protected $tokenHander; public function __construct() { } /** * Creates an object tree from a text source. * The text source could be a file, uri, or iLineReader object. * * @param mixed $source * file, uri, or iLineReader object to use as document * @throws \InvalidArgumentException if the source is not supported * @return void|\stdClass the document tree based on \stdClass */ public function parse($source) { $result = null; if(is_string($source)) { if(strstr($source, '://') === false) { $this->reader = new \Mammut\IO\Textfile($source); $this->reader->open(); $result = $this->parseContent(); $this->reader->close(); $this->reader = null; } else return $this->parse(new Http($source)); } elseif ($source instanceof Http) { $client = new \Zend\Http\Client($source); $response = $client->send(); if ($response->isSuccess()) { $this->reader = new \Mammut\IO\StringBuffer($response->getBody()); $result = $this->parseContent(); $this->reader->close(); $this->reader = null; } else throw new IOException('Fetch error with remote document', IOException::IO_GENERAL, $source); } else throw new \InvalidArgumentException("unknown source type"); return $result; } protected function parseContent() { $result = array(); $currentLine = ''; while($st = $this->reader->readLine()) { if (strlen($st) == 0) { echo "WARNING: skipping empty line\n"; continue; } if ($st[0] == ' ' || $st == "\t") { $currentLine .= substr($st, 1); continue; } if (strlen($currentLine) > 0) { $result[] = $this->parseLine($currentLine); } $currentLine = $st; } if (strlen($currentLine) > 0) $result[] = $this->parseLine($currentLine); return $result; } protected function parseLine($line) { $len = strlen($line); $state = 'NAME'; $start = 0; $nextEscaped = false; $group = false; $name = false; $params = array(); $values = array(); $paramName = ''; for ($i = 0; $i < $len; $i++) { if($state == 'NAME') { if($line[$i] == '.') { $group = substr($line, $start, $i); $start = $i + 1; } elseif($line[$i] == ';') { $name = substr($line, $start, $i - $start); $start = $i + 1; $state = 'PARAM_NAME'; } elseif($line[$i] == ':') { $name = substr($line, $start, $i - $start); $start = $i + 1; $state = 'VALUE'; } elseif($line[$i] == ' ') echo "WARNING: Key contains whitespace\n"; } elseif($state == 'PARAM_NAME') { if($line[$i] == '=') { $paramName = substr($line, $start, $i - $start); $start = $i + 1; $state = 'PARAM_VALUE_START'; } } elseif($state == 'PARAM_VALUE_START') { if($line[$i] == '"') { $state = 'PARAM_VALUE_QUOTED'; $start = $i + 1; } else $state = 'PARAM_VALUE_UNQUOTED'; } elseif($state == 'PARAM_VALUE_UNQUOTED') { if($line[$i] == ';') { $paramValue = substr($line, $start, $i - $start); $params[$paramName] = $paramValue; $start = $i + 1; $state = 'PARAM_NAME'; } elseif($line[$i] == ':') { $paramValue = substr($line, $start, $i - $start); $params[$paramName][] = $paramValue; $start = $i + 1; $state = 'VALUE'; } elseif($line[$i] == ',') { $paramValue = substr($line, $start, $i - $start); $params[$paramName][] = $paramValue; $start = $i + 1; $state = 'PARAM_VALUE_START'; } else { } } elseif($state == 'PARAM_VALUE_QUOTED') { if($line[$i] == '"') { $paramValue = substr($line, $start, $i - $start); $params[$paramName][] = $paramValue; $start = $i + 1; $state = 'PARAM_VALUE_END'; } } elseif($state == 'PARAM_VALUE_END') { if($line[$i] == ';') { $start = $i + 1; $state = 'PARAM_NAME'; } elseif($line[$i] == ',') { $start = $i + 1; $state = 'PARAM_VALUE_START'; } elseif($line[$i] == ':') { $start = $i + 1; $state = 'VALUE'; } } elseif($state == 'VALUE') { if($nextEscaped) $nextEscaped = false; else { if($line[$i] == '\\') $nextEscaped = true; elseif($line[$i] == '='){ $paramName = substr($line, $start, $i - $start); $start = $i + 1; $state = 'PARAM_VALUE_START'; } elseif($line[$i] == ';' && $this->isMulti($name)) { $paramValue = substr($line, $start, $i - $start); $params[$paramName][] = $paramValue; $start = $i + 1; $state = 'PARAM_NAME'; } elseif($line[$i] == ',' && $this->isMulti($name)) { $values[] = substr($line, $start, $i - $start); $start = $i + 1; } } } } if($state == 'VALUE') { $values[] = substr($line, $start, $i - $start); } else { $paramValue = substr($line, $start, $i - $start); $params[$paramName][] = $paramValue; $start = $i + 1; $values[] = ''; } if (count($params) == 0) $params = false; else { foreach ($params as &$p) { if (is_array($p) && count($p) == 1) $p = $p[0]; } } if (count($values) == 1) $values = $values[0]; $info = new \stdClass(); $info->group = $group; $info->name = $name; $info->params = $params; $info->values = $values; return $info; } protected function isMulti($name) { return false; } }