Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
branch: master
278 lines (234 sloc) 7.516 kb
<?php
class BinTreeNodeReader
{
private $input;
/** @var $key KeyStream */
private $key;
public function resetKey()
{
$this->key = null;
}
public function setKey($key)
{
$this->key = $key;
}
public function nextTree($input = null)
{
if ($input != null) {
$this->input = $input;
}
$firstByte = $this->peekInt8();
$stanzaFlag = ($firstByte & 0xF0) >> 4;
$stanzaSize = $this->peekInt16(1) | (($firstByte & 0x0F) << 16);
if ($stanzaSize > strlen($this->input)) {
throw new Exception("Incomplete message $stanzaSize != " . strlen($this->input));
}
$this->readInt24();
if ($stanzaFlag & 8) {
if (isset($this->key)) {
$realSize = $stanzaSize - 4;
$this->input = $this->key->DecodeMessage($this->input, $realSize, 0, $realSize);// . $remainingData;
} else {
throw new Exception("Encountered encrypted message, missing key");
}
}
if ($stanzaSize > 0) {
return $this->nextTreeInternal();
}
return null;
}
protected function readNibble() {
$byte = $this->readInt8();
$ignoreLastNibble = (bool) ($byte & 0x80);
$size = ($byte & 0x7f);
$nrOfNibbles = $size * 2 - (int) $ignoreLastNibble;
$data = $this->fillArray($size);
$string = '';
for ($i = 0; $i < $nrOfNibbles; $i++) {
$byte = $data[(int) floor($i / 2)];
$ord = ord($byte);
$shift = 4 * (1 - $i % 2);
$decimal = ($ord & (15 << $shift)) >> $shift;
switch ($decimal) {
case 0:
case 1:
case 2:
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
case 9:
$string .= $decimal;
break;
case 10:
case 11:
$string .= chr($decimal - 10 + 45);
break;
default:
throw new Exception("Bad nibble: $decimal");
}
}
return $string;
}
protected function getToken($token)
{
$ret = "";
$subdict = false;
TokenMap::GetToken($token, $subdict, $ret);
if (!$ret) {
$token = $this->readInt8();
TokenMap::GetToken($token, $subdict, $ret);
if (!$ret) {
throw new Exception("BinTreeNodeReader->getToken: Invalid token $token");
}
}
return $ret;
}
protected function readString($token)
{
$ret = "";
if ($token == -1) {
throw new Exception("BinTreeNodeReader->readString: Invalid token $token");
}
if (($token > 2) && ($token < 0xf5)) {
$ret = $this->getToken($token);
} elseif ($token == 0) {
$ret = "";
} elseif ($token == 0xfc) {
$size = $this->readInt8();
$ret = $this->fillArray($size);
} elseif ($token == 0xfd) {
$size = $this->readInt24();
$ret = $this->fillArray($size);
} elseif ($token == 0xfa) {
$user = $this->readString($this->readInt8());
$server = $this->readString($this->readInt8());
if ((strlen($user) > 0) && (strlen($server) > 0)) {
$ret = $user . "@" . $server;
} elseif (strlen($server) > 0) {
$ret = $server;
}
} elseif ($token == 0xff) {
$ret = $this->readNibble();
}
return $ret;
}
protected function readAttributes($size)
{
$attributes = array();
$attribCount = ($size - 2 + $size % 2) / 2;
for ($i = 0; $i < $attribCount; $i++) {
$key = $this->readString($this->readInt8());
$value = $this->readString($this->readInt8());
$attributes[$key] = $value;
}
return $attributes;
}
protected function nextTreeInternal()
{
$token = $this->readInt8();
$size = $this->readListSize($token);
$token = $this->readInt8();
if ($token == 1) {
$attributes = $this->readAttributes($size);
return new ProtocolNode("start", $attributes, null, "");
} elseif ($token == 2) {
return null;
}
$tag = $this->readString($token);
$attributes = $this->readAttributes($size);
if (($size % 2) == 1) {
return new ProtocolNode($tag, $attributes, null, "");
}
$token = $this->readInt8();
if ($this->isListTag($token)) {
return new ProtocolNode($tag, $attributes, $this->readList($token), "");
}
return new ProtocolNode($tag, $attributes, null, $this->readString($token));
}
protected function isListTag($token)
{
return ($token == 248 || $token == 0 || $token == 249);
}
protected function readList($token)
{
$size = $this->readListSize($token);
$ret = array();
for ($i = 0; $i < $size; $i++) {
array_push($ret, $this->nextTreeInternal());
}
return $ret;
}
protected function readListSize($token)
{
if ($token == 0xf8) {
return $this->readInt8();
} elseif ($token == 0xf9) {
return $this->readInt16();
}
throw new Exception("BinTreeNodeReader->readListSize: Invalid token $token");
}
protected function peekInt24($offset = 0)
{
$ret = 0;
if (strlen($this->input) >= (3 + $offset)) {
$ret = ord(substr($this->input, $offset, 1)) << 16;
$ret |= ord(substr($this->input, $offset + 1, 1)) << 8;
$ret |= ord(substr($this->input, $offset + 2, 1)) << 0;
}
return $ret;
}
protected function readInt24()
{
$ret = $this->peekInt24();
if (strlen($this->input) >= 3) {
$this->input = substr($this->input, 3);
}
return $ret;
}
protected function peekInt16($offset = 0)
{
$ret = 0;
if (strlen($this->input) >= (2 + $offset)) {
$ret = ord(substr($this->input, $offset, 1)) << 8;
$ret |= ord(substr($this->input, $offset + 1, 1)) << 0;
}
return $ret;
}
protected function readInt16()
{
$ret = $this->peekInt16();
if ($ret > 0) {
$this->input = substr($this->input, 2);
}
return $ret;
}
protected function peekInt8($offset = 0)
{
$ret = 0;
if (strlen($this->input) >= (1 + $offset)) {
$sbstr = substr($this->input, $offset, 1);
$ret = ord($sbstr);
}
return $ret;
}
protected function readInt8()
{
$ret = $this->peekInt8();
if (strlen($this->input) >= 1) {
$this->input = substr($this->input, 1);
}
return $ret;
}
protected function fillArray($len)
{
$ret = "";
if (strlen($this->input) >= $len) {
$ret = substr($this->input, 0, $len);
$this->input = substr($this->input, $len);
}
return $ret;
}
}
Jump to Line
Something went wrong with that request. Please try again.