UNPKG

nel-neo-thinsdk

Version:
229 lines (212 loc) 8.17 kB
/// <reference path="Stream.ts"/> namespace Neo.IO { const BufferSize = 1024; export class MemoryStream extends Stream { private _buffers = new Array<ArrayBuffer>(); private _origin = 0; private _position = 0; private _length: number; private _capacity: number; private _expandable: boolean; private _writable: boolean; public constructor(capacity?: number); public constructor(buffer: ArrayBuffer, writable?: boolean); public constructor(buffer: ArrayBuffer, index: number, count: number, writable?: boolean); public constructor() { super(); if (arguments.length == 0) { this._length = 0; this._capacity = 0; this._expandable = true; this._writable = true; } else if (arguments.length == 1 && typeof arguments[0] === "number") { this._length = 0; this._capacity = arguments[0]; this._expandable = true; this._writable = true; this._buffers.push(new ArrayBuffer(this._capacity)); } else { let buffer = arguments[0] as ArrayBuffer; this._buffers.push(buffer); this._expandable = false; if (arguments.length == 1) { this._writable = false; this._length = buffer.byteLength; } else if (typeof arguments[1] === "boolean") { this._writable = arguments[1]; this._length = buffer.byteLength; } else { this._origin = arguments[1] as number; this._length = arguments[2] as number; this._writable = arguments.length == 4 ? arguments[3] as boolean : false; if (this._origin < 0 || this._origin + this._length > buffer.byteLength) throw new RangeError(); } this._capacity = this._length; } } public canRead(): boolean { return true; } public canSeek(): boolean { return true; } public canWrite(): boolean { return this._writable; } public capacity(): number { return this._capacity; } private findBuffer(position: number): { iBuff: number, pBuff: number } { let iBuff: number, pBuff: number; let firstSize = this._buffers[0] == null ? BufferSize : this._buffers[0].byteLength; if (position < firstSize) { iBuff = 0; pBuff = position; } else { iBuff = Math.floor((position - firstSize) / BufferSize) + 1; pBuff = (position - firstSize) % BufferSize; } return { iBuff, pBuff }; } public length(): number { return this._length; } public position(): number { return this._position; } public read(buffer: ArrayBuffer, offset: number, count: number): number { if (this._position + count > this._length) count = this._length - this._position; this.readInternal(new Uint8Array(buffer, offset, count), this._position); this._position += count; return count; } private readInternal(dst: Uint8Array, srcPos: number): void { if (this._expandable) { let i = 0, count = dst.length; let d = this.findBuffer(srcPos); while (count > 0) { let actual_count: number; if (this._buffers[d.iBuff] == null) { actual_count = Math.min(count, BufferSize - d.pBuff); dst.fill(0, i, i + actual_count); } else { actual_count = Math.min(count, this._buffers[d.iBuff].byteLength - d.pBuff); let src = new Uint8Array(this._buffers[d.iBuff]); Array.copy(src, d.pBuff, dst, i, actual_count); } i += actual_count; count -= actual_count; d.iBuff++; d.pBuff = 0; } } else { let src = new Uint8Array(this._buffers[0], this._origin, this._length); Array.copy(src, srcPos, dst, 0, dst.length); } } public seek(offset: number, origin: SeekOrigin): number { switch (origin) { case SeekOrigin.Begin: break; case SeekOrigin.Current: offset += this._position; break; case SeekOrigin.End: offset += this._length; break; default: throw new RangeError(); } if (offset < 0 || offset > this._length) throw new RangeError(); this._position = offset; return offset; } public setLength(value: number): void { if (value < 0 || (value != this._length && !this._writable) || (value > this._capacity && !this._expandable)) throw new RangeError(); this._length = value; if (this._position > this._length) this._position = this._length; if (this._capacity < this._length) this._capacity = this._length; } public toArray(): ArrayBuffer { if (this._buffers.length == 1 && this._origin == 0 && this._length == this._buffers[0].byteLength) return this._buffers[0]; let bw = new Uint8Array(this._length); this.readInternal(bw, 0); return bw.buffer; } public write(buffer: ArrayBuffer, offset: number, count: number): void { if (!this._writable || (!this._expandable && this._capacity - this._position < count)) throw new Error(); if (this._expandable) { let src = new Uint8Array(buffer); let d = this.findBuffer(this._position); while (count > 0) { if (this._buffers[d.iBuff] == null) this._buffers[d.iBuff] = new ArrayBuffer(BufferSize); let actual_count = Math.min(count, this._buffers[d.iBuff].byteLength - d.pBuff); let dst = new Uint8Array(this._buffers[d.iBuff]); Array.copy(src, offset, dst, d.pBuff, actual_count); this._position += actual_count; offset += actual_count; count -= actual_count; d.iBuff++; d.pBuff = 0; } } else { let src = new Uint8Array(buffer, offset, count); let dst = new Uint8Array(this._buffers[0], this._origin, this._capacity); Array.copy(src, 0, dst, this._position, count); this._position += count; } if (this._length < this._position) this._length = this._position; if (this._capacity < this._length) this._capacity = this._length; } } }