414 lines
12 KiB
TypeScript
414 lines
12 KiB
TypeScript
import b from "buffer/index.js";
|
|
import { logger } from "db://assets/Scripts/Main/Common/Logger";
|
|
|
|
const { Buffer } = b;
|
|
|
|
export enum EDeserializeError {
|
|
OK,
|
|
NOT_ENOUGH,
|
|
EXCEED_SIZE,
|
|
}
|
|
|
|
|
|
const MIN_CAPACITY: number = 16
|
|
|
|
const f_2power32 = Math.pow(2, 32)
|
|
const f_2power56 = Math.pow(2, 56)
|
|
|
|
export default class ByteBuf {
|
|
private static emptyBuff: Buffer = Buffer.allocUnsafe(0)
|
|
|
|
constructor(bytes?: Uint8Array) {
|
|
this._bytes = bytes != null ? Buffer.from(bytes) : ByteBuf.emptyBuff
|
|
this._readerIndex = 0
|
|
this._writerIndex = bytes != null ? bytes.length : 0
|
|
}
|
|
|
|
|
|
Replace(bytes: Uint8Array) {
|
|
this._bytes = Buffer.from(bytes)
|
|
this._readerIndex = 0
|
|
this._writerIndex = bytes.length
|
|
}
|
|
|
|
Replace2(bytes: Uint8Array, beginPos: number, endPos: number) {
|
|
this._bytes = Buffer.from(bytes, beginPos, endPos - beginPos)
|
|
this._readerIndex = beginPos
|
|
this._writerIndex = endPos
|
|
}
|
|
|
|
private _bytes: Buffer
|
|
|
|
// get Bytes(): Buffer { return this._bytes }
|
|
|
|
private _readerIndex: number
|
|
// get this._readerIndex(): number { return this._readerIndex }
|
|
// set this._readerIndex(value: number) { this._readerIndex = value }
|
|
|
|
private _writerIndex: number
|
|
// get this._writerIndex(): number { return this._writerIndex }
|
|
// set this._writerIndex(value: number) { this._writerIndex = value }
|
|
|
|
get capacity(): number { return this._bytes.length }
|
|
get size(): number { return this._writerIndex - this._readerIndex }
|
|
get empty(): boolean { return this._writerIndex <= this._readerIndex }
|
|
get notEmpty(): boolean { return this._writerIndex > this._readerIndex }
|
|
|
|
getBytesNotSafe(): Buffer { return this._bytes }
|
|
|
|
addReadIndex(add: number) {
|
|
this._readerIndex += add
|
|
}
|
|
|
|
private static emptyBytes: Uint8Array = new Uint8Array()
|
|
|
|
copyData(): Uint8Array {
|
|
const n = this.remaining
|
|
if (n > 0) {
|
|
return new Uint8Array(this._bytes.buffer.slice(this._readerIndex, this._writerIndex))
|
|
} else {
|
|
return ByteBuf.emptyBytes
|
|
}
|
|
}
|
|
|
|
get remaining(): number { return this._writerIndex - this._readerIndex }
|
|
|
|
discardReadBytes() {
|
|
this._bytes.copyWithin(0, this._readerIndex, this._writerIndex)
|
|
this._writerIndex -= this._readerIndex
|
|
this._readerIndex = 0
|
|
}
|
|
|
|
|
|
clear() {
|
|
this._readerIndex = this._writerIndex = 0
|
|
}
|
|
|
|
|
|
private static propSize(initSize: number, needSize: number): number {
|
|
for (let i = Math.max(initSize, MIN_CAPACITY); i <<= 1;) {
|
|
if (i >= needSize) {
|
|
return i
|
|
}
|
|
}
|
|
}
|
|
|
|
private ensureRead(size: number) {
|
|
if (this._readerIndex + size > this._writerIndex) {
|
|
throw new Error()
|
|
}
|
|
}
|
|
|
|
|
|
private canRead(size: number): boolean {
|
|
return (this._readerIndex + size <= this._writerIndex)
|
|
}
|
|
|
|
readBool(): boolean {
|
|
this.ensureRead(1)
|
|
return this._bytes[this._readerIndex++] != 0
|
|
}
|
|
|
|
readByte(): number {
|
|
this.ensureRead(1)
|
|
return this._bytes[this._readerIndex++]
|
|
}
|
|
|
|
readShort(): number {
|
|
this.ensureRead(1)
|
|
const buf = this._bytes
|
|
const h = buf.readUInt8(this._readerIndex)
|
|
if (h < 0x80) {
|
|
this._readerIndex++
|
|
return h
|
|
}
|
|
else if (h < 0xc0) {
|
|
this.ensureRead(2)
|
|
const x = buf.readUInt16BE(this._readerIndex) & 0x3fff
|
|
this._readerIndex += 2
|
|
return x
|
|
}
|
|
else if ((h == 0xff)) {
|
|
this.ensureRead(3)
|
|
const x = buf.readInt16BE(this._readerIndex + 1)
|
|
this._readerIndex += 3
|
|
return x
|
|
}
|
|
else {
|
|
throw new Error()
|
|
}
|
|
}
|
|
|
|
readInt(): number {
|
|
const buf = this._bytes
|
|
|
|
this.ensureRead(1)
|
|
const h = buf.readUInt8(this._readerIndex)
|
|
if (h < 0x80) {
|
|
this._readerIndex++
|
|
return h
|
|
}
|
|
else if (h < 0xc0) {
|
|
this.ensureRead(2)
|
|
const x = buf.readUInt16BE(this._readerIndex) & 0x3fff
|
|
this._readerIndex += 2
|
|
return x
|
|
}
|
|
else if (h < 0xe0) {
|
|
// logger.log(`== read ${buf.readInt32BE(this._readerIndex)}`)
|
|
this.ensureRead(3)
|
|
const x = ((h & 0x1f) << 16) | (buf.readUInt16BE(this._readerIndex + 1))
|
|
this._readerIndex += 3
|
|
return x
|
|
}
|
|
else if (h < 0xf0) {
|
|
this.ensureRead(4)
|
|
// logger.log(`== read ${buf.readInt32BE(this._readerIndex)}`)
|
|
const x = buf.readInt32BE(this._readerIndex) & 0x0fffffff
|
|
this._readerIndex += 4
|
|
return x
|
|
}
|
|
else {
|
|
this.ensureRead(5)
|
|
const x = buf.readInt32BE(this._readerIndex + 1)
|
|
this._readerIndex += 5
|
|
return x
|
|
}
|
|
}
|
|
|
|
readFint(): number {
|
|
this.ensureRead(4)
|
|
const x = this._bytes.readInt32LE()
|
|
this._readerIndex += 4
|
|
return x
|
|
}
|
|
|
|
readLongAsNumber(): number {
|
|
const buf = this._bytes
|
|
///
|
|
/// 警告! 如有修改,记得调整 TryDeserializeInplaceOctets
|
|
this.ensureRead(1)
|
|
const h = buf.readUInt8(this._readerIndex)
|
|
if (h < 0x80) {
|
|
this._readerIndex++
|
|
return h
|
|
}
|
|
else if (h < 0xc0) {
|
|
this.ensureRead(2)
|
|
const x = buf.readUInt16BE(this._readerIndex) & 0x3fff
|
|
// logger.log(`== read long :${x} index:${this._readerIndex}`)
|
|
this._readerIndex += 2
|
|
return x
|
|
}
|
|
else if (h < 0xe0) {
|
|
// logger.log(`== read ${buf.readInt32BE(this._readerIndex)}`)
|
|
this.ensureRead(3)
|
|
const x = ((h & 0x1f) << 16) | (buf.readUInt16BE(this._readerIndex + 1))
|
|
this._readerIndex += 3
|
|
return x
|
|
}
|
|
else if (h < 0xf0) {
|
|
this.ensureRead(4)
|
|
// logger.log(`== read ${buf.readInt32BE(this._readerIndex)}`)
|
|
const x = buf.readInt32BE(this._readerIndex) & 0x0fffffff
|
|
this._readerIndex += 4
|
|
return x
|
|
}
|
|
else if (h < 0xf8) {
|
|
this.ensureRead(5)
|
|
const xl = buf.readUInt32BE(this._readerIndex + 1)
|
|
const xh = h & 0x07
|
|
this._readerIndex += 5
|
|
return xh * 0x100000000 + xl
|
|
}
|
|
else if (h < 0xfc) { // 1111 10xx - - - - -
|
|
this.ensureRead(6)
|
|
const xl = buf.readUInt32BE(this._readerIndex + 2)
|
|
const xh = buf.readUInt16BE(this._readerIndex) & 0x3ff
|
|
this._readerIndex += 6
|
|
return xh * 0x100000000 + xl
|
|
}
|
|
else if (h < 0xfe) {
|
|
this.ensureRead(7)
|
|
const xl = buf.readUInt32BE(this._readerIndex + 3)
|
|
const xh = (buf.readUInt32BE(this._readerIndex) >> 8) & 0x1ffff
|
|
this._readerIndex += 7
|
|
return xh * 0x100000000 + xl
|
|
}
|
|
else if (h < 0xff) { // 1111 1110, - - - - - - -
|
|
this.ensureRead(8)
|
|
// TODO 是否要对 < Number.MAX_SAFE_INTEGER 优化处理?
|
|
const xl = buf.readUInt32BE(this._readerIndex + 4)
|
|
const xh = buf.readUInt32BE(this._readerIndex) & 0xffffff
|
|
this._readerIndex += 8
|
|
return xh * f_2power32 + xl
|
|
}
|
|
else {
|
|
this.ensureRead(9)
|
|
const x = buf.readBigInt64BE(this._readerIndex + 1)
|
|
// const xl = buf.readUInt32BE(this._readerIndex + 5)
|
|
// const xh = buf.readInt32BE(this._readerIndex + 1)
|
|
this._readerIndex += 9
|
|
return Number(x)
|
|
}
|
|
}
|
|
|
|
readLong(): bigint {
|
|
const buf = this._bytes
|
|
///
|
|
this.ensureRead(1)
|
|
const h = buf.readUInt8(this._readerIndex)
|
|
if (h < 0x80) {
|
|
this._readerIndex++
|
|
return BigInt(h)
|
|
}
|
|
else if (h < 0xc0) {
|
|
this.ensureRead(2)
|
|
const x = buf.readUInt16BE(this._readerIndex) & 0x3fff
|
|
this._readerIndex += 2
|
|
return BigInt(x)
|
|
}
|
|
else if (h < 0xe0) {
|
|
this.ensureRead(3)
|
|
const x = ((h & 0x1f) << 16) | (buf.readUInt16BE(this._readerIndex + 1))
|
|
this._readerIndex += 3
|
|
return BigInt(x)
|
|
}
|
|
else if (h < 0xf0) {
|
|
this.ensureRead(4)
|
|
const x = buf.readInt32BE(this._readerIndex) & 0x0fffffff
|
|
this._readerIndex += 4
|
|
return BigInt(x)
|
|
}
|
|
else if (h < 0xf8) {
|
|
this.ensureRead(5)
|
|
const xl = buf.readUInt32BE(this._readerIndex + 1)
|
|
const xh = h & 0x07
|
|
this._readerIndex += 5
|
|
return BigInt(xh * 0x100000000 + xl)
|
|
}
|
|
else if (h < 0xfc) { // 1111 10xx - - - - -
|
|
this.ensureRead(6)
|
|
const xl = buf.readUInt32BE(this._readerIndex + 2)
|
|
const xh = buf.readUInt16BE(this._readerIndex) & 0x3ff
|
|
this._readerIndex += 6
|
|
return BigInt(xh * 0x100000000 + xl)
|
|
}
|
|
else if (h < 0xfe) {
|
|
this.ensureRead(7)
|
|
const xl = buf.readUInt32BE(this._readerIndex + 3)
|
|
const xh = (buf.readUInt32BE(this._readerIndex) >> 8) & 0x1ffff
|
|
this._readerIndex += 7
|
|
return BigInt(xh * 0x100000000 + xl)
|
|
}
|
|
else if (h < 0xff) { // 1111 1110, - - - - - - -
|
|
this.ensureRead(8)
|
|
// TODO 是否要对 < Number.MAX_SAFE_INTEGER 优化处理?
|
|
const xl = buf.readUInt32BE(this._readerIndex + 4)
|
|
const xh = buf.readUInt32BE(this._readerIndex) & 0xffffff
|
|
// logger.log(`== read8 ${xl} ${xh}`)
|
|
this._readerIndex += 8
|
|
return (BigInt(xh) << BigInt(32)) | BigInt(xl)
|
|
}
|
|
else {
|
|
this.ensureRead(9)
|
|
const x = buf.readBigInt64BE(this._readerIndex + 1)
|
|
// const xl = buf.readUInt32BE(this._readerIndex + 5)
|
|
// const xh = buf.readInt32BE(this._readerIndex + 1)
|
|
this._readerIndex += 9
|
|
return x
|
|
}
|
|
}
|
|
|
|
readFloat(): number {
|
|
this.ensureRead(4)
|
|
const x = this._bytes.readFloatLE(this._readerIndex)
|
|
this._readerIndex += 4
|
|
return x
|
|
}
|
|
|
|
readDouble(): number {
|
|
this.ensureRead(8)
|
|
const x = this._bytes.readDoubleLE(this._readerIndex)
|
|
this._readerIndex += 8
|
|
return x
|
|
}
|
|
|
|
readSize(): number {
|
|
return this.readInt()
|
|
}
|
|
|
|
// marshal int
|
|
// n -> (n << 1) ^ (n >> 31)
|
|
// read
|
|
// (x >>> 1) ^ ((x << 31) >> 31)
|
|
// (x >>> 1) ^ -(n&1)
|
|
// WriteSint(x: number)
|
|
// {
|
|
// WriteUint(((uint)x << 1) ^ ((uint)x >> 31))
|
|
// }
|
|
|
|
// readSint: number()
|
|
// {
|
|
// x: number = readUint()
|
|
// return (int)((x >> 1) ^ ((x & 1) << 31))
|
|
// }
|
|
|
|
|
|
// marshal long
|
|
// n -> (n << 1) ^ (n >> 63)
|
|
// read
|
|
// (x >>> 1) ^((x << 63) >> 63)
|
|
// (x >>> 1) ^ -(n&1L)
|
|
// WriteSlong(long x)
|
|
// {
|
|
// WriteUlong(((ulong)x << 1) ^ ((ulong)x >> 63))
|
|
// }
|
|
|
|
// long readSlong()
|
|
// {
|
|
// long x = readLong()
|
|
// return ((long)((ulong)x >> 1) ^ ((x & 1) << 63))
|
|
// }
|
|
|
|
// // Uint8Array, [start, end)
|
|
// static Func < Uint8Array, int, int, string > StringCacheFinder { get set }
|
|
|
|
readString(): string {
|
|
const n = this.readSize()
|
|
if (n > 0) {
|
|
this.ensureRead(n)
|
|
const s = this._bytes.toString("utf-8", this._readerIndex, this._readerIndex + n)
|
|
this._readerIndex += n
|
|
return s
|
|
}
|
|
else {
|
|
return ""
|
|
}
|
|
}
|
|
|
|
readBytes(): Uint8Array {
|
|
const n = this.readSize()
|
|
if (n > 0) {
|
|
this.ensureRead(n)
|
|
const x = Buffer.from(this._bytes.slice(this._readerIndex, this._readerIndex + n))
|
|
this._readerIndex += n
|
|
return x
|
|
}
|
|
else {
|
|
return ByteBuf.emptyBuff
|
|
}
|
|
}
|
|
|
|
readArrayBuffer(): ArrayBuffer {
|
|
return this.readBytes().buffer
|
|
}
|
|
|
|
SkipBytes() {
|
|
const n = this.readSize()
|
|
this.ensureRead(n)
|
|
this._readerIndex += n
|
|
}
|
|
|
|
}
|