oicq
Version:
QQ protocol!
161 lines (154 loc) • 3.81 kB
JavaScript
/**
* protobuf组包解包
*/
;
// const pb = require("protobufjs");
const pb = require("./protobuf.min");
class Proto {
/**
* @param {Buffer} bytes
* @param {import("../ref").Proto} decoded
*/
constructor(bytes, decoded) {
if (decoded)
Reflect.setPrototypeOf(this, decoded);
this._raw = bytes;
}
toString() {
return String(this._raw);
}
toHex() {
return this._raw.toString("hex");
}
toBase64() {
return this._raw.toString("base64");
}
toBuffer() {
return this._raw;
}
[Symbol.toPrimitive]() {
return this.toString();
}
}
/**
* @param {pb.Writer} writer
* @param {number} tag
* @param {any} value
*/
function _encode(writer, tag, value) {
if (value === null || value === undefined)
return;
let type = 2;
if (typeof value === "number") {
type = Number.isInteger(value) ? 0 : 1;
} else if (typeof value === "string") {
value = Buffer.from(value);
} else if (value instanceof Uint8Array) {
//
} else if (value instanceof Proto) {
value = value.toBuffer();
} else if (typeof value === "object") {
value = encode(value);
} else if (typeof value === "bigint") {
const tmp = new pb.util.Long();
tmp.unsigned = false;
tmp.low = parseInt(value & 0xffffffffn);
tmp.high = parseInt((value & 0xffffffff00000000n) >> 32n);
value = tmp;
type = 0;
} else {
return;
}
const head = tag << 3 | type;
writer.uint32(head);
switch (type) {
case 0:
if (value < 0)
writer.sint64(value);
else
writer.int64(value);
break;
case 2:
writer.bytes(value);
break;
case 1:
writer.double(value);
break;
}
}
/**
* @param {import("../ref").Proto} o
* @returns {Uint8Array}
*/
function encode(o) {
const writer = new pb.Writer();
for (let tag in o) {
const value = o[tag];
tag = parseInt(tag);
if (!Number.isInteger(tag))
continue;
if (Array.isArray(value)) {
for (let v of value)
_encode(writer, tag, v);
} else {
_encode(writer, tag, value);
}
}
return writer.finish();
}
/**
* @param {pb.Long} long
*/
function long2int(long) {
if (long.high === 0) {
return long.low >>> 0;
}
const bigint = (BigInt(long.high) << 32n) | (BigInt(long.low) & 0xffffffffn);
const int = long.toNumber();
return Number.isSafeInteger(int) ? int : bigint;
}
/**
* @param {Buffer} buf
* @returns {import("../ref").Proto}
*/
function decode(buf) {
const data = new Proto(buf);
const reader = new pb.Reader(buf);
while (reader.pos < reader.len) {
const k = reader.uint32();
const tag = k >> 3, type = k & 0b111;
let value, decoded;
switch (type) {
case 0:
value = long2int(reader.int64());
break;
case 1:
value = long2int(reader.fixed64());
break;
case 2:
value = reader.bytes();
try {
decoded = decode(value);
} catch { }
value = new Proto(value, decoded);
break;
case 5:
value = reader.fixed32();
break;
default:
return;
}
if (Array.isArray(data[tag])) {
data[tag].push(value);
} else if (Reflect.has(data, tag)) {
data[tag] = [data[tag]];
data[tag].push(value);
} else {
data[tag] = value;
}
}
return data;
}
module.exports = {
encode, decode,
};