2016-06-23 23:51:08 +02:00
|
|
|
<?php
|
2016-07-14 15:15:50 +02:00
|
|
|
|
|
|
|
set_include_path(get_include_path().PATH_SEPARATOR.dirname(__FILE__).DIRECTORY_SEPARATOR.'libpy2php');
|
|
|
|
require_once 'libpy2php.php';
|
2016-06-23 23:51:08 +02:00
|
|
|
$__author__ = 'agrigoryev';
|
2016-07-14 15:15:50 +02:00
|
|
|
require_once 'os.php';
|
|
|
|
class TlConstructor
|
|
|
|
{
|
|
|
|
public function __construct($json_dict)
|
|
|
|
{
|
|
|
|
$this->id = (int) $json_dict['id'];
|
2016-06-23 23:51:08 +02:00
|
|
|
$this->type = $json_dict['type'];
|
|
|
|
$this->predicate = $json_dict['predicate'];
|
|
|
|
$this->params = [];
|
|
|
|
foreach ($json_dict['params'] as $param) {
|
|
|
|
if (($param['type'] == 'Vector<long>')) {
|
|
|
|
$param['type'] = 'Vector t';
|
|
|
|
$param['subtype'] = 'long';
|
2016-07-14 15:15:50 +02:00
|
|
|
} elseif (($param['type'] == 'vector<%Message>')) {
|
2016-06-23 23:51:08 +02:00
|
|
|
$param['type'] = 'vector';
|
|
|
|
$param['subtype'] = 'message';
|
2016-07-14 15:15:50 +02:00
|
|
|
} elseif (($param['type'] == 'vector<future_salt>')) {
|
2016-06-23 23:51:08 +02:00
|
|
|
$param['type'] = 'vector';
|
|
|
|
$param['subtype'] = 'future_salt';
|
|
|
|
} else {
|
|
|
|
$param['subtype'] = null;
|
|
|
|
}
|
|
|
|
$this->params[] = $param;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-07-14 15:15:50 +02:00
|
|
|
class TlMethod
|
|
|
|
{
|
|
|
|
public function __construct($json_dict)
|
|
|
|
{
|
|
|
|
$this->id = (int) $json_dict['id'];
|
2016-06-23 23:51:08 +02:00
|
|
|
$this->type = $json_dict['type'];
|
|
|
|
$this->method = $json_dict['method'];
|
|
|
|
$this->params = $json_dict['params'];
|
|
|
|
}
|
|
|
|
}
|
2016-07-14 15:15:50 +02:00
|
|
|
class TLObject extends ArrayObject
|
|
|
|
{
|
|
|
|
public function __construct($tl_elem)
|
|
|
|
{
|
2016-06-28 17:49:51 +02:00
|
|
|
parent::__construct();
|
2016-06-23 23:51:08 +02:00
|
|
|
$this->name = $tl_elem->predicate;
|
|
|
|
}
|
|
|
|
}
|
2016-07-14 15:15:50 +02:00
|
|
|
class TL
|
|
|
|
{
|
|
|
|
public function __construct($filename)
|
|
|
|
{
|
2016-06-26 14:53:16 +02:00
|
|
|
$TL_dict = json_decode(file_get_contents($filename), true);
|
2016-06-23 23:51:08 +02:00
|
|
|
$this->constructors = $TL_dict['constructors'];
|
|
|
|
$this->constructor_id = [];
|
|
|
|
$this->constructor_type = [];
|
|
|
|
foreach ($this->constructors as $elem) {
|
|
|
|
$z = new TlConstructor($elem);
|
|
|
|
$this->constructor_id[$z->id] = $z;
|
|
|
|
$this->constructor_type[$z->predicate] = $z;
|
|
|
|
}
|
|
|
|
$this->methods = $TL_dict['methods'];
|
|
|
|
$this->method_id = [];
|
|
|
|
$this->method_name = [];
|
|
|
|
foreach ($this->methods as $elem) {
|
|
|
|
$z = new TlMethod($elem);
|
|
|
|
$this->method_id[$z->id] = $z;
|
|
|
|
$this->method_name[$z->method] = $z;
|
|
|
|
}
|
2016-07-30 16:14:25 +02:00
|
|
|
$this->struct = new \danog\PHP\StructClass();
|
2016-06-23 23:51:08 +02:00
|
|
|
}
|
2016-07-14 15:15:50 +02:00
|
|
|
|
|
|
|
public function serialize_obj($type_, $kwargs)
|
|
|
|
{
|
2016-08-06 20:48:33 +02:00
|
|
|
$bytes_io = '';
|
2016-07-14 15:15:50 +02:00
|
|
|
if (isset($this->constructor_type[$type_])) {
|
2016-07-14 14:22:46 +02:00
|
|
|
$tl_constructor = $this->constructor_type[$type_];
|
2016-07-14 15:15:50 +02:00
|
|
|
} else {
|
2016-07-14 14:22:46 +02:00
|
|
|
throw new Exception(sprintf('Could not extract type: %s', $type_));
|
2016-06-23 23:51:08 +02:00
|
|
|
}
|
2016-08-06 20:48:33 +02:00
|
|
|
$bytes_io .= $this->struct->pack('<i', $tl_constructor->id);
|
2016-07-14 14:22:46 +02:00
|
|
|
foreach ($tl_constructor->params as $arg) {
|
2016-08-06 20:48:33 +02:00
|
|
|
$bytes_io .= $this->serialize_param($arg['type'], $kwargs[$arg['name']]);
|
2016-07-14 14:22:46 +02:00
|
|
|
}
|
2016-07-14 15:15:50 +02:00
|
|
|
|
2016-08-06 20:48:33 +02:00
|
|
|
return $bytes_io;
|
2016-06-23 23:51:08 +02:00
|
|
|
}
|
2016-07-14 15:15:50 +02:00
|
|
|
|
|
|
|
public function serialize_method($type_, $kwargs)
|
|
|
|
{
|
2016-08-06 20:48:33 +02:00
|
|
|
$bytes_io = '';
|
2016-07-14 15:15:50 +02:00
|
|
|
if (isset($this->method_name[$type_])) {
|
2016-07-14 14:22:46 +02:00
|
|
|
$tl_method = $this->method_name[$type_];
|
2016-07-14 15:15:50 +02:00
|
|
|
} else {
|
2016-07-14 14:22:46 +02:00
|
|
|
throw new Exception(sprintf('Could not extract type: %s', $type_));
|
2016-06-26 12:59:15 +02:00
|
|
|
}
|
2016-08-06 20:48:33 +02:00
|
|
|
$bytes_io .= $this->struct->pack('<i', $tl_method->id);
|
2016-07-14 14:22:46 +02:00
|
|
|
foreach ($tl_method->params as $arg) {
|
2016-08-06 20:48:33 +02:00
|
|
|
$bytes_io .= $this->serialize_param($arg['type'], $kwargs[$arg['name']]);
|
2016-06-23 23:51:08 +02:00
|
|
|
}
|
2016-08-06 20:48:33 +02:00
|
|
|
return $bytes_io;
|
2016-07-14 14:22:46 +02:00
|
|
|
}
|
2016-07-14 15:15:50 +02:00
|
|
|
|
2016-08-06 20:48:33 +02:00
|
|
|
public function serialize_param($type_, $value)
|
2016-07-14 15:15:50 +02:00
|
|
|
{
|
2016-07-18 17:11:37 +02:00
|
|
|
switch ($type_) {
|
|
|
|
case 'int':
|
2016-08-06 12:14:40 +02:00
|
|
|
if (!is_numeric($value)) {
|
|
|
|
throw new Exception("serialize_param: given value isn't numeric");
|
|
|
|
}
|
|
|
|
if (!(strlen(decbin($value)) <= 32)) {
|
|
|
|
throw new Exception('Given value is too long.');
|
|
|
|
}
|
2016-08-06 20:48:33 +02:00
|
|
|
return $this->struct->pack('<i', $value);
|
2016-07-18 17:11:37 +02:00
|
|
|
break;
|
|
|
|
case 'long':
|
2016-08-06 12:14:40 +02:00
|
|
|
if (!is_numeric($value)) {
|
|
|
|
throw new Exception("serialize_param: given value isn't numeric");
|
|
|
|
}
|
2016-08-06 20:48:33 +02:00
|
|
|
return $this->struct->pack('<q', $value);
|
2016-07-18 17:11:37 +02:00
|
|
|
break;
|
|
|
|
case 'int128':
|
|
|
|
case 'int256':
|
2016-08-06 12:14:40 +02:00
|
|
|
if (!is_string($value)) {
|
|
|
|
throw new Exception("serialize_param: given value isn't a string");
|
|
|
|
}
|
2016-08-06 20:48:33 +02:00
|
|
|
return $value;
|
2016-07-18 17:11:37 +02:00
|
|
|
break;
|
|
|
|
case 'string':
|
|
|
|
case 'bytes':
|
2016-08-06 01:29:18 +02:00
|
|
|
$l = strlen($value);
|
2016-08-06 20:48:33 +02:00
|
|
|
$concat = '';
|
2016-08-06 01:29:18 +02:00
|
|
|
if ($l < 254) {
|
2016-08-06 20:48:33 +02:00
|
|
|
$concat .= $this->struct->pack('<b', $l);
|
|
|
|
$concat .= $value;
|
|
|
|
$concat .= pack('@'.posmod((-$l - 1), 4));
|
2016-07-18 17:11:37 +02:00
|
|
|
} else {
|
2016-08-06 20:48:33 +02:00
|
|
|
$concat .= string2bin('\xfe');
|
|
|
|
$concat .= substr($this->struct->pack('<i', $l), 0, 3);
|
|
|
|
$concat .= $value;
|
|
|
|
$concat .= pack('@'.posmod(-$l, 4));
|
2016-07-18 17:11:37 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
2016-06-23 23:51:08 +02:00
|
|
|
}
|
2016-07-14 14:22:46 +02:00
|
|
|
}
|
2016-07-14 15:15:50 +02:00
|
|
|
|
2016-07-14 14:22:46 +02:00
|
|
|
/**
|
2016-07-14 15:15:50 +02:00
|
|
|
* :type bytes_io: io.BytesIO object.
|
|
|
|
*/
|
2016-07-15 15:01:32 +02:00
|
|
|
public function deserialize($bytes_io, $type_ = null, $subtype = null)
|
2016-07-14 15:15:50 +02:00
|
|
|
{
|
2016-08-06 12:14:40 +02:00
|
|
|
if (!(get_resource_type($bytes_io) == 'file' || get_resource_type($bytes_io) == 'stream')) {
|
|
|
|
throw new Exception('An invalid bytes_io handle provided.');
|
|
|
|
}
|
2016-07-18 17:11:37 +02:00
|
|
|
switch ($type_) {
|
|
|
|
case 'int':
|
|
|
|
$x = $this->struct->unpack('<i', fread($bytes_io, 4)) [0];
|
|
|
|
break;
|
|
|
|
case '#':
|
|
|
|
$x = $this->struct->unpack('<I', fread($bytes_io, 4)) [0];
|
|
|
|
break;
|
|
|
|
case 'long':
|
|
|
|
$x = $this->struct->unpack('<q', fread($bytes_io, 8)) [0];
|
|
|
|
break;
|
|
|
|
case 'double':
|
|
|
|
$x = $this->struct->unpack('<d', fread($bytes_io, 8)) [0];
|
|
|
|
break;
|
|
|
|
case 'int128':
|
|
|
|
$x = fread($bytes_io, 16);
|
|
|
|
break;
|
|
|
|
case 'int256':
|
|
|
|
$x = fread($bytes_io, 32);
|
|
|
|
break;
|
|
|
|
case 'string':
|
|
|
|
case 'bytes':
|
|
|
|
$l = $this->struct->unpack('<B', fread($bytes_io, 1)) [0];
|
2016-08-06 12:14:40 +02:00
|
|
|
if ($l > 254) {
|
|
|
|
throw new Exception('Length is too big');
|
|
|
|
}
|
2016-08-06 01:29:18 +02:00
|
|
|
if ($l == 254) {
|
2016-07-18 17:11:37 +02:00
|
|
|
$long_len = $this->struct->unpack('<I', fread($bytes_io, 3).string2bin('\x00')) [0];
|
|
|
|
$x = fread($bytes_io, $long_len);
|
|
|
|
fread($bytes_io, posmod(-$long_len, 4));
|
2016-07-14 14:22:46 +02:00
|
|
|
} else {
|
2016-07-18 17:11:37 +02:00
|
|
|
$x = fread($bytes_io, $l);
|
|
|
|
fread($bytes_io, posmod(-($l + 1), 4));
|
|
|
|
}
|
2016-08-06 12:14:40 +02:00
|
|
|
if (!is_string($x)) {
|
|
|
|
throw new Exception("deserialize: generated value isn't a string");
|
|
|
|
}
|
2016-07-18 17:11:37 +02:00
|
|
|
break;
|
|
|
|
case 'vector':
|
2016-08-06 12:14:40 +02:00
|
|
|
if ($subtype == null) {
|
|
|
|
throw new Exception("deserialize: subtype isn't null");
|
|
|
|
}
|
2016-07-18 17:11:37 +02:00
|
|
|
$count = $this->struct->unpack('<l', fread($bytes_io, 4)) [0];
|
|
|
|
$x = [];
|
|
|
|
foreach (pyjslib_range($count) as $i) {
|
|
|
|
$x[] = $this->deserialize($bytes_io, $subtype);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
if (isset($this->constructor_type[$type_])) {
|
|
|
|
$tl_elem = $this->constructor_type[$type_];
|
|
|
|
} else {
|
|
|
|
$Idata = fread($bytes_io, 4);
|
|
|
|
$i = $this->struct->unpack('<i', $Idata) [0];
|
|
|
|
if (isset($this->constructor_id[$i])) {
|
|
|
|
$tl_elem = $this->constructor_id[$i];
|
|
|
|
} else {
|
|
|
|
throw new Exception(sprintf('Could not extract type: %s', $type_));
|
|
|
|
}
|
2016-07-14 14:22:46 +02:00
|
|
|
}
|
|
|
|
|
2016-07-18 17:11:37 +02:00
|
|
|
$base_boxed_types = ['Vector t', 'Int', 'Long', 'Double', 'String', 'Int128', 'Int256'];
|
|
|
|
if (in_array($tl_elem->type, $base_boxed_types)) {
|
|
|
|
$x = $this->deserialize($bytes_io, $tl_elem->predicate, $subtype);
|
|
|
|
} else {
|
|
|
|
$x = new TLObject($tl_elem);
|
|
|
|
foreach ($tl_elem->params as $arg) {
|
|
|
|
$x[$arg['name']] = $this->deserialize($bytes_io, $arg['type'], $arg['subtype']);
|
|
|
|
}
|
2016-07-14 14:22:46 +02:00
|
|
|
}
|
2016-07-18 17:11:37 +02:00
|
|
|
break;
|
2016-06-23 23:51:08 +02:00
|
|
|
}
|
2016-08-06 02:50:19 +02:00
|
|
|
|
2016-07-14 14:22:46 +02:00
|
|
|
return $x;
|
2016-06-23 23:51:08 +02:00
|
|
|
}
|
|
|
|
}
|