@awayjs/core
Version:
AwayJS core classes
357 lines (278 loc) • 10.3 kB
text/typescript
import { ByteArrayBase } from './ByteArrayBase';
export class ByteArray extends ByteArrayBase {
public maxlength: number;
public arraybytes; //ArrayBuffer
public unalignedarraybytestemp; //ArrayBuffer
constructor(maxlength: number = 4) {
super();
this._mode = 'Typed array';
this.maxlength = Math.max((maxlength + 255) & (~255), 4);
this.arraybytes = new ArrayBuffer(this.maxlength);
this.unalignedarraybytestemp = new ArrayBuffer(16);
}
public ensureWriteableSpace(n: number): void {
this.ensureSpace(n + this.position);
}
public setArrayBuffer(aBuffer: ArrayBuffer): void {
this.ensureSpace(aBuffer.byteLength);
this.length = aBuffer.byteLength;
const inInt8AView: Int8Array = new Int8Array(aBuffer);
const localInt8View: Int8Array = new Int8Array(this.arraybytes, 0, this.length);
localInt8View.set(inInt8AView);
this.position = 0;
}
public writeArrayBuffer(aBuffer: ArrayBuffer): void {
this.ensureWriteableSpace(aBuffer.byteLength);
const inInt8AView: Int8Array = new Int8Array(aBuffer);
const localInt8View: Int8Array = new Int8Array(this.arraybytes, this.length, aBuffer.byteLength);
localInt8View.set(inInt8AView);
this.length += aBuffer.byteLength;
this.position = this.length;
}
public writeByteArray(ba: ByteArray): void {
this.ensureWriteableSpace(ba.length);
const inInt8AView: Int8Array = new Int8Array(ba.arraybytes, 0, ba.length);
const localInt8View: Int8Array = new Int8Array(this.arraybytes, this.length, ba.length);
localInt8View.set(inInt8AView);
this.length += ba.length;
this.position = this.length;
}
public getBytesAvailable(): number {
return (this.length) - (this.position);
}
public ensureSpace(n: number): void {
if (n > this.maxlength) {
const newmaxlength: number = (n + 255) & (~255);
const newarraybuffer = new ArrayBuffer(newmaxlength);
const view = new Uint8Array(this.arraybytes, 0, this.length);
const newview = new Uint8Array(newarraybuffer, 0, this.length);
newview.set(view); // memcpy
this.arraybytes = newarraybuffer;
this.maxlength = newmaxlength;
}
}
public writeObject(object: any): void {
console.log('writeObject not implemented yet in core/ByteArray');
}
public readObject(): any {
console.log('readObject not implemented yet in core/ByteArray');
return {};
}
public writeByte(b: number): void {
this.ensureWriteableSpace(1);
const view = new Int8Array(this.arraybytes);
view[ this.position++ ] = (~~b); // ~~ is cast to int in js...
if (this.position > this.length) {
this.length = this.position;
}
}
public readByte(): number {
if (this.position >= this.length)
throw 'ByteArray out of bounds read. Positon=' + this.position + ', Length=' + this.length;
const view = new Int8Array(this.arraybytes);
return view[ this.position++ ];
}
public readBytes(bytes: ByteArray, offset: number = 0, length: number = 0): void {
if (length == null)
length = bytes.length;
bytes.ensureWriteableSpace(offset + length);
const byteView: Int8Array = new Int8Array(bytes.arraybytes);
const localByteView: Int8Array = new Int8Array(this.arraybytes);
byteView.set(localByteView.subarray(this.position, this.position + length), offset);
this.position += length;
if (length + offset > bytes.length)
bytes.length += (length + offset) - bytes.length;
}
public writeUnsignedByte(b: number): void {
this.ensureWriteableSpace(1);
const view = new Uint8Array(this.arraybytes);
view[this.position++] = (~~b) & 0xff; // ~~ is cast to int in js...
if (this.position > this.length)
this.length = this.position;
}
public readUnsignedByte(): number {
if (this.position >= this.length)
throw 'ByteArray out of bounds read. Positon=' + this.position + ', Length=' + this.length;
const view = new Uint8Array(this.arraybytes);
return view[this.position++];
}
public writeUnsignedShort(b: number): void {
this.ensureWriteableSpace(2);
if ((this.position & 1) == 0) {
const view = new Uint16Array(this.arraybytes);
view[ this.position >> 1 ] = (~~b) & 0xffff; // ~~ is cast to int in js...
} else {
const view = new Uint16Array(this.unalignedarraybytestemp, 0, 1);
view[0] = (~~b) & 0xffff;
const view2 = new Uint8Array(this.arraybytes, this.position, 2);
const view3 = new Uint8Array(this.unalignedarraybytestemp, 0, 2);
view2.set(view3);
}
this.position += 2;
if (this.position > this.length)
this.length = this.position;
}
public readUTFBytes(len: number): string {
let value: string = '';
const max: number = this.position + len;
const data: DataView = new DataView(this.arraybytes);
// utf8-encode
while (this.position < max) {
const c: number = data.getUint8(this.position++);
if (c < 0x80) {
if (c == 0) break;
value += String.fromCharCode(c);
} else if (c < 0xE0) {
value += String.fromCharCode(((c & 0x3F) << 6) | (data.getUint8(this.position++) & 0x7F));
} else if (c < 0xF0) {
const c2 = data.getUint8(this.position++);
value += String.fromCharCode(((c & 0x1F) << 12)
| ((c2 & 0x7F) << 6)
| (data.getUint8(this.position++) & 0x7F));
} else {
const c2 = data.getUint8(this.position++);
const c3 = data.getUint8(this.position++);
value += String.fromCharCode(((c & 0x0F) << 18)
| ((c2 & 0x7F) << 12)
| ((c3 << 6) & 0x7F)
| (data.getUint8(this.position++) & 0x7F));
}
}
return value;
}
public writeUTFBytes(s: string) {
const escstr = encodeURIComponent(s);
const binstr = escstr.replace(/%([0-9A-F]{2})/g, function(match, p1) {
return String.fromCharCode(parseInt('0x' + p1));
});
this.ensureWriteableSpace(4 + binstr.length);
this.writeInt(binstr.length);
for (let i = 0; i < binstr.length; i++) {
this.writeUnsignedByte(binstr.charCodeAt(i)); //todo: there are probably faster ways to do this
}
if (binstr.length % 4) {
const paddingbytes: number = binstr.length % 4;
for (let i = 0; i < paddingbytes; i++) {
this.writeUnsignedByte(0);
}
}
return binstr.length;
}
public readInt(): number {
const data: DataView = new DataView(this.arraybytes);
const int: number = data.getInt32(this.position, true);
this.position += 4;
return int;
}
public readShort(): number {
const data: DataView = new DataView(this.arraybytes);
const short: number = data.getInt16(this.position, true);
this.position += 2;
return short;
}
public readDouble(): number {
const data: DataView = new DataView(this.arraybytes);
const double: number = data.getFloat64(this.position, true);
this.position += 8;
return double;
}
public readUnsignedShort(): number {
if (this.position > this.length + 2)
throw 'ByteArray out of bounds read. Position=' + this.position + ', Length=' + this.length;
if ((this.position & 1) == 0) {
const view = new Uint16Array(this.arraybytes);
const pa: number = this.position >> 1;
this.position += 2;
return view[ pa ];
} else {
const view = new Uint16Array(this.unalignedarraybytestemp, 0, 1);
const view2 = new Uint8Array(this.arraybytes, this.position, 2);
const view3 = new Uint8Array(this.unalignedarraybytestemp, 0, 2);
view3.set(view2);
this.position += 2;
return view[0];
}
}
public writeUnsignedInt(b: number): void {
this.ensureWriteableSpace(4);
if ((this.position & 3) == 0) {
const view = new Uint32Array(this.arraybytes);
view[ this.position >> 2 ] = (~~b) & 0xffffffff; // ~~ is cast to int in js...
} else {
const view = new Uint32Array(this.unalignedarraybytestemp, 0, 1);
view[0] = (~~b) & 0xffffffff;
const view2 = new Uint8Array(this.arraybytes, this.position, 4);
const view3 = new Uint8Array(this.unalignedarraybytestemp, 0, 4);
view2.set(view3);
}
this.position += 4;
if (this.position > this.length)
this.length = this.position;
}
public writeInt(b: number): void {
this.ensureWriteableSpace(4);
if ((this.position & 3) == 0) {
const view = new Int32Array(this.arraybytes);
view[ this.position >> 2 ] = (~~b); // ~~ is cast to int in js...
} else {
const view = new Int32Array(this.unalignedarraybytestemp, 0, 1);
view[0] = (~~b);
const view2 = new Uint8Array(this.arraybytes, this.position, 4);
const view3 = new Uint8Array(this.unalignedarraybytestemp, 0, 4);
view2.set(view3);
}
this.position += 4;
if (this.position > this.length)
this.length = this.position;
}
public readUnsignedInt(): number {
if (this.position > this.length + 4)
throw 'ByteArray out of bounds read. Position=' + this.position + ', Length=' + this.length;
if ((this.position & 3) == 0) {
const view = new Uint32Array(this.arraybytes);
const pa: number = this.position >> 2;
this.position += 4;
return view[ pa ];
} else {
const view = new Uint32Array(this.unalignedarraybytestemp, 0, 1);
const view2 = new Uint8Array(this.arraybytes, this.position, 4);
const view3 = new Uint8Array(this.unalignedarraybytestemp, 0, 4);
view3.set(view2);
this.position += 4;
return view[0];
}
}
public writeFloat(b: number): void {
this.ensureWriteableSpace(4);
if ((this.position & 3) == 0) {
const view = new Float32Array(this.arraybytes);
view[ this.position >> 2 ] = b;
} else {
const view = new Float32Array(this.unalignedarraybytestemp, 0, 1);
view[0] = b;
const view2 = new Uint8Array(this.arraybytes, this.position, 4);
const view3 = new Uint8Array(this.unalignedarraybytestemp, 0, 4);
view2.set(view3);
}
this.position += 4;
if (this.position > this.length)
this.length = this.position;
}
public readFloat(): number {
if (this.position > this.length + 4)
throw 'ByteArray out of bounds read. Positon=' + this.position + ', Length=' + this.length;
if ((this.position & 3) == 0) {
const view = new Float32Array(this.arraybytes);
const pa = this.position >> 2;
this.position += 4;
return view[pa];
} else {
const view = new Float32Array(this.unalignedarraybytestemp, 0, 1);
const view2 = new Uint8Array(this.arraybytes, this.position, 4);
const view3 = new Uint8Array(this.unalignedarraybytestemp, 0, 4);
view3.set(view2);
this.position += 4;
return view[ 0 ];
}
}
}