151 lines
4.4 KiB
TypeScript
151 lines
4.4 KiB
TypeScript
export default class Stream {
|
||
|
||
private _stream: number[];
|
||
private _readPoiner: number = 0;
|
||
private _writePointer: number = 0;
|
||
|
||
constructor(stream : number[] = []) {
|
||
this._stream = stream;
|
||
}
|
||
|
||
public getStream(): number[] {
|
||
return this._stream;
|
||
}
|
||
|
||
public setStream(stream: number[]) {
|
||
this._stream = stream;
|
||
}
|
||
|
||
public writeInt8(value: number) {
|
||
const negationBit = value < 0 ? 1 : 0;
|
||
const int8Value = Math.abs(value) & 0xFF;
|
||
this._stream[this._writePointer >> 3] |= negationBit << (7 - (this._writePointer & 7));
|
||
this._writePointer++;
|
||
for (let i = 0; i < 8; i++) {
|
||
const bit = (int8Value >> (7 - i)) & 1;
|
||
this._stream[this._writePointer >> 3] |= bit << (7 - (this._writePointer & 7));
|
||
this._writePointer++;
|
||
}
|
||
}
|
||
|
||
public readInt8(): number {
|
||
let value = 0;
|
||
const negationBit = (this._stream[this._readPoiner >> 3] >> (7 - (this._readPoiner & 7))) & 1;
|
||
this._readPoiner++;
|
||
for (let i = 0; i < 8; i++) {
|
||
const bit = (this._stream[this._readPoiner >> 3] >> (7 - (this._readPoiner & 7))) & 1;
|
||
value |= bit << (7 - i);
|
||
this._readPoiner++;
|
||
}
|
||
return negationBit ? -value : value;
|
||
}
|
||
|
||
public writeBit(value: number) {
|
||
const bit = value & 1;
|
||
this._stream[this._writePointer >> 3] |= bit << (7 - (this._writePointer & 7));
|
||
this._writePointer++;
|
||
}
|
||
|
||
public readBit(): number {
|
||
const bit = (this._stream[this._readPoiner >> 3] >> (7 - (this._readPoiner & 7))) & 1;
|
||
this._readPoiner++;
|
||
return bit;
|
||
}
|
||
|
||
public writeBoolean(value: boolean) {
|
||
this.writeBit(value ? 1 : 0);
|
||
}
|
||
|
||
public readBoolean(): boolean {
|
||
return this.readBit() === 1;
|
||
}
|
||
|
||
public writeInt16(value: number) {
|
||
this.writeInt8(value >> 8);
|
||
this.writeInt8(value & 0xFF);
|
||
}
|
||
|
||
public readInt16(): number {
|
||
const value = this.readInt8() << 8;
|
||
return value | this.readInt8();
|
||
}
|
||
|
||
public writeInt32(value: number) {
|
||
this.writeInt16(value >> 16);
|
||
this.writeInt16(value & 0xFFFF);
|
||
}
|
||
|
||
public readInt32(): number {
|
||
const value = this.readInt16() << 16;
|
||
return value | this.readInt16();
|
||
}
|
||
|
||
public writeInt64(value: number) {
|
||
const high = Math.floor(value / 0x100000000);
|
||
const low = value >>> 0;
|
||
this.writeInt32(high);
|
||
this.writeInt32(low);
|
||
}
|
||
|
||
public readInt64(): number {
|
||
const high = this.readInt32();
|
||
const low = this.readInt32() >>> 0;
|
||
return high * 0x100000000 + low;
|
||
}
|
||
|
||
public writeFloat32(value: number) {
|
||
const buffer = new ArrayBuffer(4);
|
||
new DataView(buffer).setFloat32(0, value, true);
|
||
const float32Value = new Uint32Array(buffer)[0];
|
||
this.writeInt32(float32Value);
|
||
}
|
||
|
||
public readFloat32(): number {
|
||
const float32Value = this.readInt32();
|
||
const buffer = new ArrayBuffer(4);
|
||
new Uint32Array(buffer)[0] = float32Value;
|
||
return new DataView(buffer).getFloat32(0, true);
|
||
}
|
||
|
||
public writeString(value: string) {
|
||
let length = value.length;
|
||
this.writeInt32(length);
|
||
for (let i = 0; i < value.length; i++) {
|
||
this.writeInt16(value.charCodeAt(i));
|
||
}
|
||
}
|
||
|
||
public readString(): string {
|
||
let length = this.readInt32();
|
||
/**
|
||
* Фикс уязвимости с длинной строки, превышающей
|
||
* возможность для чтения _stream
|
||
*/
|
||
if (length < 0 || length > (this._stream.length - (this._readPoiner >> 3))) {
|
||
console.info("Stream readString length invalid", length, this._stream.length, this._readPoiner);
|
||
return "";
|
||
}
|
||
let value = "";
|
||
for (let i = 0; i < length; i++) {
|
||
value += String.fromCharCode(this.readInt16());
|
||
}
|
||
return value;
|
||
}
|
||
|
||
public writeBytes(value: number[]) {
|
||
this.writeInt32(value.length);
|
||
for (let i = 0; i < value.length; i++) {
|
||
this.writeInt8(value[i]);
|
||
}
|
||
}
|
||
|
||
public readBytes(): number[] {
|
||
let length = this.readInt32();
|
||
let value : any = [];
|
||
for (let i = 0; i < length; i++) {
|
||
value.push(this.readInt8());
|
||
}
|
||
return value;
|
||
}
|
||
|
||
} |