| <?php | |
| class BinTreeNodeWriter | |
| { | |
| private $output; | |
| /** @var $key KeyStream */ | |
| private $key; | |
| public function resetKey() | |
| { | |
| $this->key = null; | |
| } | |
| public function setKey($key) | |
| { | |
| $this->key = $key; | |
| } | |
| public function StartStream($domain, $resource) | |
| { | |
| $attributes = array(); | |
| $attributes["to"] = $domain; | |
| $attributes["resource"] = $resource; | |
| $this->writeListStart(count($attributes) * 2 + 1); | |
| $this->output .= "\x01"; | |
| $this->writeAttributes($attributes); | |
| return "WA" . $this->writeInt8(1) . $this->writeInt8(5) . $this->flushBuffer(); | |
| } | |
| /** | |
| * @param ProtocolNode $node | |
| * @param bool $encrypt | |
| * | |
| * @return string | |
| */ | |
| public function write($node, $encrypt = true) | |
| { | |
| if ($node == null) { | |
| $this->output .= "\x00"; | |
| } else { | |
| $this->writeInternal($node); | |
| } | |
| return $this->flushBuffer($encrypt); | |
| } | |
| /** | |
| * @param ProtocolNode $node | |
| */ | |
| protected function writeInternal($node) | |
| { | |
| $len = 1; | |
| if ($node->getAttributes() != null) { | |
| $len += count($node->getAttributes()) * 2; | |
| } | |
| if (count($node->getChildren()) > 0) { | |
| $len += 1; | |
| } | |
| if (strlen($node->getData()) > 0) { | |
| $len += 1; | |
| } | |
| $this->writeListStart($len); | |
| $this->writeString($node->getTag()); | |
| $this->writeAttributes($node->getAttributes()); | |
| if (strlen($node->getData()) > 0) { | |
| $this->writeBytes($node->getData()); | |
| } | |
| if ($node->getChildren()) { | |
| $this->writeListStart(count($node->getChildren())); | |
| foreach ($node->getChildren() as $child) { | |
| $this->writeInternal($child); | |
| } | |
| } | |
| } | |
| protected function parseInt24($data) | |
| { | |
| $ret = ord(substr($data, 0, 1)) << 16; | |
| $ret |= ord(substr($data, 1, 1)) << 8; | |
| $ret |= ord(substr($data, 2, 1)) << 0; | |
| return $ret; | |
| } | |
| protected function flushBuffer($encrypt = true) | |
| { | |
| $size = strlen($this->output); | |
| $data = $this->output; | |
| if ($this->key != null && $encrypt) { | |
| $bsize = $this->getInt24($size); | |
| //encrypt | |
| $data = $this->key->EncodeMessage($data, $size, 0, $size); | |
| $len = strlen($data); | |
| $bsize[0] = chr((8 << 4) | (($len & 16711680) >> 16)); | |
| $bsize[1] = chr(($len & 65280) >> 8); | |
| $bsize[2] = chr($len & 255); | |
| $size = $this->parseInt24($bsize); | |
| } | |
| $ret = $this->writeInt24($size) . $data; | |
| $this->output = ''; | |
| return $ret; | |
| } | |
| protected function getInt24($length) | |
| { | |
| $ret = ''; | |
| $ret .= chr((($length & 0xf0000) >> 16)); | |
| $ret .= chr((($length & 0xff00) >> 8)); | |
| $ret .= chr(($length & 0xff)); | |
| return $ret; | |
| } | |
| protected function writeToken($token) | |
| { | |
| if ($token < 0xf5) { | |
| $this->output .= chr($token); | |
| } elseif ($token <= 0x1f4) { | |
| $this->output .= "\xfe" . chr($token - 0xf5); | |
| } | |
| } | |
| protected function writeJid($user, $server) | |
| { | |
| $this->output .= "\xfa"; | |
| if (strlen($user) > 0) { | |
| $this->writeString($user); | |
| } else { | |
| $this->writeToken(0); | |
| } | |
| $this->writeString($server); | |
| } | |
| protected function writeInt8($v) | |
| { | |
| $ret = chr($v & 0xff); | |
| return $ret; | |
| } | |
| protected function writeInt16($v) | |
| { | |
| $ret = chr(($v & 0xff00) >> 8); | |
| $ret .= chr(($v & 0x00ff) >> 0); | |
| return $ret; | |
| } | |
| protected function writeInt24($v) | |
| { | |
| $ret = chr(($v & 0xff0000) >> 16); | |
| $ret .= chr(($v & 0x00ff00) >> 8); | |
| $ret .= chr(($v & 0x0000ff) >> 0); | |
| return $ret; | |
| } | |
| protected function writeBytes($bytes) | |
| { | |
| $len = strlen($bytes); | |
| if ($len >= 0x100) { | |
| $this->output .= "\xfd"; | |
| $this->output .= $this->writeInt24($len); | |
| } else { | |
| $this->output .= "\xfc"; | |
| $this->output .= $this->writeInt8($len); | |
| } | |
| $this->output .= $bytes; | |
| } | |
| protected function writeString($tag) | |
| { | |
| $intVal = -1; | |
| $subdict = false; | |
| if (TokenMap::TryGetToken($tag, $subdict, $intVal)) { | |
| if ($subdict) { | |
| $this->writeToken(236); | |
| } | |
| $this->writeToken($intVal); | |
| return; | |
| } | |
| $index = strpos($tag, '@'); | |
| if ($index) { | |
| $server = substr($tag, $index + 1); | |
| $user = substr($tag, 0, $index); | |
| $this->writeJid($user, $server); | |
| } else { | |
| $this->writeBytes($tag); | |
| } | |
| } | |
| protected function writeAttributes($attributes) | |
| { | |
| if ($attributes) { | |
| foreach ($attributes as $key => $value) { | |
| $this->writeString($key); | |
| $this->writeString($value); | |
| } | |
| } | |
| } | |
| protected function writeListStart($len) | |
| { | |
| if ($len == 0) { | |
| $this->output .= "\x00"; | |
| } elseif ($len < 256) { | |
| $this->output .= "\xf8" . chr($len); | |
| } else { | |
| $this->output .= "\xf9" . $this->writeInt16($len); | |
| } | |
| } | |
| } |