|
|
@ -9,17 +9,29 @@ |
|
|
|
* https://github.com/zhukov/webogram/blob/master/LICENSE
|
|
|
|
* https://github.com/zhukov/webogram/blob/master/LICENSE
|
|
|
|
*/ |
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
import { bytesToHex } from '../../helpers/bytes'; |
|
|
|
import { bytesFromHex, bytesToHex } from '../../helpers/bytes'; |
|
|
|
import { isObject, longFromInts } from './bin_utils'; |
|
|
|
import { addPadding, isObject, longFromInts } from './bin_utils'; |
|
|
|
import { MOUNT_CLASS_TO } from '../../config/debug'; |
|
|
|
import { MOUNT_CLASS_TO } from '../../config/debug'; |
|
|
|
import { str2bigInt, dup, divide_, bigInt2str } from '../../vendor/leemon'; |
|
|
|
import { str2bigInt, bigInt2str, int2bigInt, sub_ } from '../../vendor/leemon'; |
|
|
|
import Schema, { MTProtoConstructor } from './schema'; |
|
|
|
import Schema, { MTProtoConstructor } from './schema'; |
|
|
|
|
|
|
|
import { JSONValue } from '../../layer'; |
|
|
|
|
|
|
|
|
|
|
|
/// #if MTPROTO_WORKER
|
|
|
|
/// #if MTPROTO_WORKER
|
|
|
|
// @ts-ignore
|
|
|
|
// @ts-ignore
|
|
|
|
import { gzipUncompress } from '../crypto/crypto_utils'; |
|
|
|
import { gzipUncompress } from '../crypto/crypto_utils'; |
|
|
|
/// #endif
|
|
|
|
/// #endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// @ts-ignore
|
|
|
|
|
|
|
|
/* import {BigInteger} from 'jsbn'; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export function bigint(num: number) { |
|
|
|
|
|
|
|
return new BigInteger(num.toString(16), 16); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function bigStringInt(strNum: string) { |
|
|
|
|
|
|
|
return new BigInteger(strNum, 10) |
|
|
|
|
|
|
|
} */ |
|
|
|
|
|
|
|
|
|
|
|
const boolFalse = +Schema.API.constructors.find(c => c.predicate === 'boolFalse').id; |
|
|
|
const boolFalse = +Schema.API.constructors.find(c => c.predicate === 'boolFalse').id; |
|
|
|
const boolTrue = +Schema.API.constructors.find(c => c.predicate === 'boolTrue').id; |
|
|
|
const boolTrue = +Schema.API.constructors.find(c => c.predicate === 'boolTrue').id; |
|
|
|
const vector = +Schema.API.constructors.find(c => c.predicate === 'vector').id; |
|
|
|
const vector = +Schema.API.constructors.find(c => c.predicate === 'vector').id; |
|
|
@ -155,28 +167,33 @@ class TLSerialization { |
|
|
|
sLong = sLong ? sLong.toString() : '0'; |
|
|
|
sLong = sLong ? sLong.toString() : '0'; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const R = 0x100000000; |
|
|
|
/* let perf = performance.now(); |
|
|
|
//const divRem = bigStringInt(sLong).divideAndRemainder(bigint(R));
|
|
|
|
const jsbnBytes: Uint8Array = new Uint8Array(8); |
|
|
|
|
|
|
|
const jsbnBigInt = bigStringInt(sLong); |
|
|
|
|
|
|
|
for(let i = 0; i < 8; i++) { |
|
|
|
|
|
|
|
jsbnBytes[i] = +jsbnBigInt.shiftRight(8 * i).and(bigint(255)).toString(10); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
console.log('perf1', performance.now() - perf); */ |
|
|
|
|
|
|
|
|
|
|
|
const a = str2bigInt(sLong, 10, 64); |
|
|
|
// perf = performance.now();
|
|
|
|
const q = dup(a); |
|
|
|
let bigInt: number[]; |
|
|
|
const r = dup(a); |
|
|
|
if(sLong[0] === '-') { // leemon library can't parse signed numbers
|
|
|
|
divide_(a, str2bigInt((R).toString(16), 16, 64), q, r); |
|
|
|
bigInt = int2bigInt(0, 64, 8); |
|
|
|
//divInt_(a, R);
|
|
|
|
sub_(bigInt, str2bigInt(sLong.slice(1), 10, 64)); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
bigInt = str2bigInt(sLong, 10, 64); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const high = +bigInt2str(q, 10); |
|
|
|
const hex = bigInt2str(bigInt, 16).slice(-16); |
|
|
|
let low = +bigInt2str(r, 10); |
|
|
|
const bytes = addPadding(bytesFromHex(hex).reverse(), 8, true, true, false); |
|
|
|
|
|
|
|
|
|
|
|
if(high < low) { |
|
|
|
// console.log('perf2', performance.now() - perf);
|
|
|
|
low -= R; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//console.log('storeLong', sLong, divRem[0].intValue(), divRem[1].intValue(), high, low);
|
|
|
|
this.storeRawBytes(bytes); |
|
|
|
|
|
|
|
|
|
|
|
//this.writeInt(divRem[1].intValue(), (field || '') + ':long[low]');
|
|
|
|
// if(jsbnBytes.hex !== bytes.hex) {
|
|
|
|
//this.writeInt(divRem[0].intValue(), (field || '') + ':long[high]');
|
|
|
|
// console.error(bigInt, sLong, bigInt2str(bigInt, 10), negative(bigInt), jsbnBytes.hex, bigInt2str(bigInt, 16), bytes.hex);
|
|
|
|
this.writeInt(low, (field || '') + ':long[low]'); |
|
|
|
// }
|
|
|
|
this.writeInt(high, (field || '') + ':long[high]'); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public storeDouble(f: any, field?: string) { |
|
|
|
public storeDouble(f: any, field?: string) { |
|
|
@ -806,9 +823,32 @@ class TLDeserialization<FetchLongAs extends Long> { |
|
|
|
if(fallback) { |
|
|
|
if(fallback) { |
|
|
|
this.mtproto = true; |
|
|
|
this.mtproto = true; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if(type === 'JSONValue') { |
|
|
|
|
|
|
|
return this.formatJSONValue(result); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return result; |
|
|
|
return result; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private formatJSONValue(jsonValue: JSONValue): any { |
|
|
|
|
|
|
|
if(!jsonValue._) return jsonValue; |
|
|
|
|
|
|
|
switch(jsonValue._) { |
|
|
|
|
|
|
|
case 'jsonNull': |
|
|
|
|
|
|
|
return null; |
|
|
|
|
|
|
|
case 'jsonObject': { |
|
|
|
|
|
|
|
const out: any = {}; |
|
|
|
|
|
|
|
const objectValues = jsonValue.value; |
|
|
|
|
|
|
|
for(let i = 0, length = objectValues.length; i < length; ++i) { |
|
|
|
|
|
|
|
const objectValue = objectValues[i]; |
|
|
|
|
|
|
|
out[objectValue.key] = this.formatJSONValue(objectValue.value); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return out; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
default: |
|
|
|
|
|
|
|
return jsonValue.value; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public getOffset() { |
|
|
|
public getOffset() { |
|
|
|
return this.offset; |
|
|
|
return this.offset; |
|
|
|