nel-neo-thinsdk
Version:
229 lines (212 loc) • 8.17 kB
text/typescript
/// <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;
}
}
}