UNPKG

@awayjs/graphics

Version:
839 lines (838 loc) 30.4 kB
/** * Copyright 2014 Mozilla Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ //import notImplemented = Shumway.Debug.notImplemented; import { assert, isNullOrUndefined, ArrayBufferPool, clamp, Errors, IntegerUtilities, utf8decode, utf8encode } from './utilities'; import { Deflate, Inflate } from './deflate'; import { LzmaDecoder } from './lzma'; function axCoerceString(x) { if (typeof x === 'string') { return x; } else if (x == undefined) { return null; } return x + ''; } var PlainObjectDataBuffer = /** @class */ (function () { function PlainObjectDataBuffer(buffer, length, littleEndian) { this.buffer = buffer; this.length = length; this.littleEndian = littleEndian; } return PlainObjectDataBuffer; }()); export { PlainObjectDataBuffer }; var bitMasks = new Uint32Array(33); for (var i = 1, mask = 0; i <= 32; i++) { bitMasks[i] = mask = (mask << 1) | 1; } var TypedArrayViewFlags; (function (TypedArrayViewFlags) { TypedArrayViewFlags[TypedArrayViewFlags["U8"] = 1] = "U8"; TypedArrayViewFlags[TypedArrayViewFlags["I32"] = 2] = "I32"; TypedArrayViewFlags[TypedArrayViewFlags["F32"] = 4] = "F32"; })(TypedArrayViewFlags || (TypedArrayViewFlags = {})); var DataBuffer = /** @class */ (function () { function DataBuffer(initialSize) { if (initialSize === void 0) { initialSize = DataBuffer.INITIAL_SIZE; } // If we're constructing a child class of DataBuffer (or ByteArray), buffer initialization // has already happened at this point. if (this._buffer) { return; } this._buffer = new ArrayBuffer(initialSize); this._length = 0; this._position = 0; this._resetViews(); this._littleEndian = DataBuffer._nativeLittleEndian; this._bitBuffer = 0; this._bitLength = 0; } DataBuffer.FromArrayBuffer = function (buffer, length) { if (length === void 0) { length = -1; } var dataBuffer = Object.create(DataBuffer.prototype); dataBuffer._buffer = buffer; dataBuffer._length = length === -1 ? buffer.byteLength : length; dataBuffer._position = 0; dataBuffer._resetViews(); dataBuffer._littleEndian = DataBuffer._nativeLittleEndian; dataBuffer._bitBuffer = 0; dataBuffer._bitLength = 0; return dataBuffer; }; DataBuffer.FromPlainObject = function (source) { var dataBuffer = DataBuffer.FromArrayBuffer(source.buffer, source.length); dataBuffer._littleEndian = source.littleEndian; return dataBuffer; }; DataBuffer.prototype.toPlainObject = function () { return new PlainObjectDataBuffer(this._buffer, this._length, this._littleEndian); }; /** * Clone the DataBuffer in a way that guarantees the underlying ArrayBuffer to be copied * into an instance of the current global's ArrayBuffer. * * Important if the underlying buffer comes from a different global, in which case accessing * its elements is excruiciatingly slow. */ DataBuffer.prototype.clone = function () { var clone = DataBuffer.FromArrayBuffer(new Uint8Array(this._u8).buffer, this._length); clone._position = this._position; clone._littleEndian = this._littleEndian; clone._bitBuffer = this._bitBuffer; clone._bitLength = this._bitLength; return clone; }; /** * By default, we only have a byte view. All other views are |null|. */ DataBuffer.prototype._resetViews = function () { this._u8 = new Uint8Array(this._buffer); this._i32 = null; this._f32 = null; }; /** * We don't want to eagerly allocate views if we won't ever need them. You must call this method * before using a view of a certain type to make sure it's available. Once a view is allocated, * it is not re-allocated unless the view becomes |null| as a result of a call to |resetViews|. */ DataBuffer.prototype._requestViews = function (flags) { if ((this._buffer.byteLength & 0x3) === 0) { if (this._i32 === null && flags & TypedArrayViewFlags.I32) { this._i32 = new Int32Array(this._buffer); } if (this._f32 === null && flags & TypedArrayViewFlags.F32) { this._f32 = new Float32Array(this._buffer); } } }; DataBuffer.prototype.getBytes = function () { return new Uint8Array(this._buffer, 0, this._length); }; DataBuffer.prototype._ensureCapacity = function (length) { var currentBuffer = this._buffer; if (currentBuffer.byteLength >= length) { return; } var newLength = Math.max(currentBuffer.byteLength, 1); while (newLength < length) { newLength *= 2; } if (newLength > 0xFFFFFFFF) { assert(this.sec); this.sec.throwError('RangeError', Errors.ParamRangeError); } var newBuffer = DataBuffer._arrayBufferPool.acquire(newLength); var curentView = this._u8; this._buffer = newBuffer; this._resetViews(); this._u8.set(curentView); var u8 = this._u8; // Zero out the rest of the buffer, since the arrayBufferPool doesn't // always give us a empty buffer. for (var i = curentView.length; i < u8.length; i++) { u8[i] = 0; } DataBuffer._arrayBufferPool.release(currentBuffer); }; DataBuffer.prototype.clear = function () { this._length = 0; this._position = 0; }; DataBuffer.prototype.readBoolean = function () { return this.readUnsignedByte() !== 0; }; DataBuffer.prototype.readByte = function () { return this.readUnsignedByte() << 24 >> 24; }; DataBuffer.prototype.readUnsignedByte = function () { if (this._position + 1 > this._length) { assert(this.sec); this.sec.throwError('flash.errors.EOFError', Errors.EOFError); } return this._u8[this._position++]; }; DataBuffer.prototype.readBytes = function (bytes, offset /*uint*/, length /*uint*/) { var position = this._position; offset = offset >>> 0; length = length >>> 0; if (length === 0) { length = this._length - position; } if (position + length > this._length) { assert(this.sec); this.sec.throwError('flash.errors.EOFError', Errors.EOFError); } if (bytes.length < offset + length) { bytes._ensureCapacity(offset + length); bytes.length = offset + length; } bytes._u8.set(new Uint8Array(this._buffer, position, length), offset); this._position += length; }; DataBuffer.prototype.readShort = function () { return this.readUnsignedShort() << 16 >> 16; }; DataBuffer.prototype.readUnsignedShort = function () { var u8 = this._u8; var position = this._position; if (position + 2 > this._length) { assert(this.sec); this.sec.throwError('flash.errors.EOFError', Errors.EOFError); } var a = u8[position + 0]; var b = u8[position + 1]; this._position = position + 2; return this._littleEndian ? (b << 8) | a : (a << 8) | b; }; DataBuffer.prototype.readInt = function () { var u8 = this._u8; var position = this._position; if (position + 4 > this._length) { assert(this.sec); this.sec.throwError('flash.errors.EOFError', Errors.EOFError); } var a = u8[position + 0]; var b = u8[position + 1]; var c = u8[position + 2]; var d = u8[position + 3]; this._position = position + 4; return this._littleEndian ? (d << 24) | (c << 16) | (b << 8) | a : (a << 24) | (b << 16) | (c << 8) | d; }; DataBuffer.prototype.readUnsignedInt = function () { return this.readInt() >>> 0; }; DataBuffer.prototype.readFloat = function () { var position = this._position; if (position + 4 > this._length) { assert(this.sec); this.sec.throwError('flash.errors.EOFError', Errors.EOFError); } this._position = position + 4; this._requestViews(TypedArrayViewFlags.F32); if (this._littleEndian && (position & 0x3) === 0 && this._f32) { return this._f32[position >> 2]; } else { var u8 = this._u8; var t8 = IntegerUtilities.u8; if (this._littleEndian) { t8[0] = u8[position + 0]; t8[1] = u8[position + 1]; t8[2] = u8[position + 2]; t8[3] = u8[position + 3]; } else { t8[3] = u8[position + 0]; t8[2] = u8[position + 1]; t8[1] = u8[position + 2]; t8[0] = u8[position + 3]; } return IntegerUtilities.f32[0]; } }; DataBuffer.prototype.readDouble = function () { var u8 = this._u8; var position = this._position; if (position + 8 > this._length) { assert(this.sec); this.sec.throwError('flash.errors.EOFError', Errors.EOFError); } var t8 = IntegerUtilities.u8; if (this._littleEndian) { t8[0] = u8[position + 0]; t8[1] = u8[position + 1]; t8[2] = u8[position + 2]; t8[3] = u8[position + 3]; t8[4] = u8[position + 4]; t8[5] = u8[position + 5]; t8[6] = u8[position + 6]; t8[7] = u8[position + 7]; } else { t8[0] = u8[position + 7]; t8[1] = u8[position + 6]; t8[2] = u8[position + 5]; t8[3] = u8[position + 4]; t8[4] = u8[position + 3]; t8[5] = u8[position + 2]; t8[6] = u8[position + 1]; t8[7] = u8[position + 0]; } this._position = position + 8; return IntegerUtilities.f64[0]; }; DataBuffer.prototype.writeBoolean = function (value) { this.writeByte(value ? 1 : 0); }; DataBuffer.prototype.writeByte = function (value /*int*/) { var length = this._position + 1; this._ensureCapacity(length); this._u8[this._position++] = value; if (length > this._length) { this._length = length; } }; DataBuffer.prototype.writeUnsignedByte = function (value /*uint*/) { var length = this._position + 1; this._ensureCapacity(length); this._u8[this._position++] = value; if (length > this._length) { this._length = length; } }; DataBuffer.prototype.writeRawBytes = function (bytes) { var length = this._position + bytes.length; this._ensureCapacity(length); this._u8.set(bytes, this._position); this._position = length; if (length > this._length) { this._length = length; } }; DataBuffer.prototype.writeBytes = function (bytes, offset /*uint*/, length /*uint*/) { if (isNullOrUndefined(bytes)) { assert(this.sec); this.sec.throwError('TypeError', Errors.NullPointerError, 'bytes'); } offset = offset >>> 0; length = length >>> 0; if (arguments.length < 2) { offset = 0; } if (arguments.length < 3) { length = 0; } if (offset !== clamp(offset, 0, bytes.length) || offset + length !== clamp(offset + length, 0, bytes.length)) { assert(this.sec); this.sec.throwError('RangeError', Errors.ParamRangeError); } if (length === 0) { length = bytes.length - offset; } this.writeRawBytes(new Uint8Array(bytes._buffer, offset, length)); }; DataBuffer.prototype.writeShort = function (value /*int*/) { this.writeUnsignedShort(value); }; DataBuffer.prototype.writeUnsignedShort = function (value /*uint*/) { var position = this._position; this._ensureCapacity(position + 2); var u8 = this._u8; if (this._littleEndian) { u8[position + 0] = value; u8[position + 1] = value >> 8; } else { u8[position + 0] = value >> 8; u8[position + 1] = value; } position += 2; this._position = position; if (position > this._length) { this._length = position; } }; DataBuffer.prototype.writeInt = function (value /*int*/) { this.writeUnsignedInt(value); }; DataBuffer.prototype.write2Ints = function (a, b) { this.write2UnsignedInts(a, b); }; DataBuffer.prototype.write4Ints = function (a, b, c, d) { this.write4UnsignedInts(a, b, c, d); }; DataBuffer.prototype.writeUnsignedInt = function (value /*uint*/) { var position = this._position; this._ensureCapacity(position + 4); this._requestViews(TypedArrayViewFlags.I32); if (this._littleEndian === DataBuffer._nativeLittleEndian && (position & 0x3) === 0 && this._i32) { this._i32[position >> 2] = value; } else { var u8 = this._u8; if (this._littleEndian) { u8[position + 0] = value; u8[position + 1] = value >> 8; u8[position + 2] = value >> 16; u8[position + 3] = value >> 24; } else { u8[position + 0] = value >> 24; u8[position + 1] = value >> 16; u8[position + 2] = value >> 8; u8[position + 3] = value; } } position += 4; this._position = position; if (position > this._length) { this._length = position; } }; DataBuffer.prototype.write2UnsignedInts = function (a, b) { var position = this._position; this._ensureCapacity(position + 8); this._requestViews(TypedArrayViewFlags.I32); if (this._littleEndian === DataBuffer._nativeLittleEndian && (position & 0x3) === 0 && this._i32) { this._i32[(position >> 2) + 0] = a; this._i32[(position >> 2) + 1] = b; position += 8; this._position = position; if (position > this._length) { this._length = position; } } else { this.writeUnsignedInt(a); this.writeUnsignedInt(b); } }; DataBuffer.prototype.write4UnsignedInts = function (a, b, c, d) { var position = this._position; this._ensureCapacity(position + 16); this._requestViews(TypedArrayViewFlags.I32); if (this._littleEndian === DataBuffer._nativeLittleEndian && (position & 0x3) === 0 && this._i32) { this._i32[(position >> 2) + 0] = a; this._i32[(position >> 2) + 1] = b; this._i32[(position >> 2) + 2] = c; this._i32[(position >> 2) + 3] = d; position += 16; this._position = position; if (position > this._length) { this._length = position; } } else { this.writeUnsignedInt(a); this.writeUnsignedInt(b); this.writeUnsignedInt(c); this.writeUnsignedInt(d); } }; DataBuffer.prototype.writeFloat = function (value) { var position = this._position; this._ensureCapacity(position + 4); this._requestViews(TypedArrayViewFlags.F32); if (this._littleEndian === DataBuffer._nativeLittleEndian && (position & 0x3) === 0 && this._f32) { this._f32[position >> 2] = value; } else { var u8 = this._u8; IntegerUtilities.f32[0] = value; var t8 = IntegerUtilities.u8; if (this._littleEndian) { u8[position + 0] = t8[0]; u8[position + 1] = t8[1]; u8[position + 2] = t8[2]; u8[position + 3] = t8[3]; } else { u8[position + 0] = t8[3]; u8[position + 1] = t8[2]; u8[position + 2] = t8[1]; u8[position + 3] = t8[0]; } } position += 4; this._position = position; if (position > this._length) { this._length = position; } }; DataBuffer.prototype.write2Floats = function (a, b) { var position = this._position; this._ensureCapacity(position + 8); this._requestViews(TypedArrayViewFlags.F32); if (this._littleEndian === DataBuffer._nativeLittleEndian && (position & 0x3) === 0 && this._f32) { this._f32[(position >> 2) + 0] = a; this._f32[(position >> 2) + 1] = b; position += 8; this._position = position; if (position > this._length) { this._length = position; } } else { this.writeFloat(a); this.writeFloat(b); } }; DataBuffer.prototype.write6Floats = function (a, b, c, d, e, f) { var position = this._position; this._ensureCapacity(position + 24); this._requestViews(TypedArrayViewFlags.F32); if (this._littleEndian === DataBuffer._nativeLittleEndian && (position & 0x3) === 0 && this._f32) { this._f32[(position >> 2) + 0] = a; this._f32[(position >> 2) + 1] = b; this._f32[(position >> 2) + 2] = c; this._f32[(position >> 2) + 3] = d; this._f32[(position >> 2) + 4] = e; this._f32[(position >> 2) + 5] = f; position += 24; this._position = position; if (position > this._length) { this._length = position; } } else { this.writeFloat(a); this.writeFloat(b); this.writeFloat(c); this.writeFloat(d); this.writeFloat(e); this.writeFloat(f); } }; DataBuffer.prototype.writeDouble = function (value) { var position = this._position; this._ensureCapacity(position + 8); var u8 = this._u8; IntegerUtilities.f64[0] = value; var t8 = IntegerUtilities.u8; if (this._littleEndian) { u8[position + 0] = t8[0]; u8[position + 1] = t8[1]; u8[position + 2] = t8[2]; u8[position + 3] = t8[3]; u8[position + 4] = t8[4]; u8[position + 5] = t8[5]; u8[position + 6] = t8[6]; u8[position + 7] = t8[7]; } else { u8[position + 0] = t8[7]; u8[position + 1] = t8[6]; u8[position + 2] = t8[5]; u8[position + 3] = t8[4]; u8[position + 4] = t8[3]; u8[position + 5] = t8[2]; u8[position + 6] = t8[1]; u8[position + 7] = t8[0]; } position += 8; this._position = position; if (position > this._length) { this._length = position; } }; DataBuffer.prototype.readRawBytes = function () { return new Int8Array(this._buffer, 0, this._length); }; DataBuffer.prototype.writeUTF = function (value) { value = axCoerceString(value); var bytes = utf8decode(value); this.writeShort(bytes.length); this.writeRawBytes(bytes); }; DataBuffer.prototype.writeUTFBytes = function (value) { value = axCoerceString(value); var bytes = utf8decode(value); this.writeRawBytes(bytes); }; DataBuffer.prototype.readUTF = function () { return this.readUTFBytes(this.readShort()); }; DataBuffer.prototype.readUTFBytes = function (length /*uint*/) { length = length >>> 0; var pos = this._position; if (pos + length > this._length) { assert(this.sec); this.sec.throwError('flash.errors.EOFError', Errors.EOFError); } this._position += length; return utf8encode(new Uint8Array(this._buffer, pos, length)); }; Object.defineProperty(DataBuffer.prototype, "length", { get: function () { return this._length; }, set: function (value /*uint*/) { value = value >>> 0; var capacity = this._buffer.byteLength; /* XXX: Do we need to zero the difference if length <= cap? */ if (value > capacity) { this._ensureCapacity(value); } this._length = value; this._position = clamp(this._position, 0, this._length); }, enumerable: false, configurable: true }); Object.defineProperty(DataBuffer.prototype, "bytesAvailable", { get: function () { return this._length - this._position; }, enumerable: false, configurable: true }); Object.defineProperty(DataBuffer.prototype, "position", { get: function () { return this._position; }, set: function (position /*uint*/) { this._position = position >>> 0; }, enumerable: false, configurable: true }); Object.defineProperty(DataBuffer.prototype, "buffer", { get: function () { return this._buffer; }, enumerable: false, configurable: true }); Object.defineProperty(DataBuffer.prototype, "bytes", { get: function () { return this._u8; }, enumerable: false, configurable: true }); Object.defineProperty(DataBuffer.prototype, "ints", { get: function () { this._requestViews(TypedArrayViewFlags.I32); return this._i32; }, enumerable: false, configurable: true }); Object.defineProperty(DataBuffer.prototype, "objectEncoding", { get: function () { return this._objectEncoding; }, set: function (version /*uint*/) { version = version >>> 0; this._objectEncoding = version; }, enumerable: false, configurable: true }); Object.defineProperty(DataBuffer.prototype, "endian", { get: function () { return this._littleEndian ? 'littleEndian' : 'bigEndian'; }, set: function (type) { type = axCoerceString(type); if (type === 'auto') { this._littleEndian = DataBuffer._nativeLittleEndian; } else { this._littleEndian = type === 'littleEndian'; } }, enumerable: false, configurable: true }); DataBuffer.prototype.toString = function () { return utf8encode(new Uint8Array(this._buffer, 0, this._length)); }; DataBuffer.prototype.toBlob = function (type) { return new Blob([new Uint8Array(this._buffer, this._position, this._length)], { type: type }); }; DataBuffer.prototype.writeMultiByte = function (value, charSet) { value = axCoerceString(value); charSet = axCoerceString(charSet); if (charSet == 'UTF-8') { var bytes = utf8decode(value); this.writeRawBytes(bytes); } else { console.log('packageInternal flash.utils.ObjectOutput::writeMultiByte only encoding supported is UTF-8'); } }; DataBuffer.prototype.readMultiByte = function (length /*uint*/, charSet) { length = length >>> 0; charSet = axCoerceString(charSet); console.log('packageInternal flash.utils.ObjectInput::readMultiByte'); return; }; DataBuffer.prototype.getValue = function (name) { name = name | 0; if (name >= this._length) { return undefined; } return this._u8[name]; }; DataBuffer.prototype.setValue = function (name, value) { name = name | 0; var length = name + 1; this._ensureCapacity(length); this._u8[name] = value; if (length > this._length) { this._length = length; } }; DataBuffer.prototype.readFixed = function () { return this.readInt() / 65536; }; DataBuffer.prototype.readFixed8 = function () { return this.readShort() / 256; }; DataBuffer.prototype.readFloat16 = function () { var uint16 = this.readUnsignedShort(); var sign = uint16 >> 15 ? -1 : 1; var exponent = (uint16 & 0x7c00) >> 10; var fraction = uint16 & 0x03ff; if (!exponent) { return sign * Math.pow(2, -14) * (fraction / 1024); } if (exponent === 0x1f) { return fraction ? NaN : sign * Infinity; } return sign * Math.pow(2, exponent - 15) * (1 + (fraction / 1024)); }; DataBuffer.prototype.readEncodedU32 = function () { var value = this.readUnsignedByte(); if (!(value & 0x080)) { return value; } value = (value & 0x7f) | this.readUnsignedByte() << 7; if (!(value & 0x4000)) { return value; } value = (value & 0x3fff) | this.readUnsignedByte() << 14; if (!(value & 0x200000)) { return value; } value = (value & 0x1FFFFF) | this.readUnsignedByte() << 21; if (!(value & 0x10000000)) { return value; } return (value & 0xFFFFFFF) | (this.readUnsignedByte() << 28); }; DataBuffer.prototype.readBits = function (size) { return (this.readUnsignedBits(size) << (32 - size)) >> (32 - size); }; DataBuffer.prototype.readUnsignedBits = function (size) { var buffer = this._bitBuffer; var length = this._bitLength; while (size > length) { buffer = (buffer << 8) | this.readUnsignedByte(); length += 8; } length -= size; var value = (buffer >>> length) & bitMasks[size]; this._bitBuffer = buffer; this._bitLength = length; return value; }; DataBuffer.prototype.readFixedBits = function (size) { return this.readBits(size) / 65536; }; DataBuffer.prototype.readString = function (length) { var position = this._position; if (length) { if (position + length > this._length) { assert(this.sec); this.sec.throwError('flash.errors.EOFError', Errors.EOFError); } this._position += length; } else { length = 0; for (var i = position; i < this._length && this._u8[i]; i++) { length++; } this._position += length + 1; } return utf8encode(new Uint8Array(this._buffer, position, length)); }; DataBuffer.prototype.align = function () { this._bitBuffer = 0; this._bitLength = 0; }; DataBuffer.prototype.deflate = function () { this.compress('deflate'); }; DataBuffer.prototype.inflate = function () { this.uncompress('deflate'); }; DataBuffer.prototype.compress = function (algorithm) { if (arguments.length === 0) { algorithm = 'zlib'; } else { algorithm = axCoerceString(algorithm); } var deflate; switch (algorithm) { case 'zlib': deflate = new Deflate(true); break; case 'deflate': deflate = new Deflate(false); break; default: return; } var output = new DataBuffer(); deflate.onData = output.writeRawBytes.bind(output); deflate.push(this._u8.subarray(0, this._length)); deflate.close(); this._ensureCapacity(output._u8.length); this._u8.set(output._u8); this.length = output.length; this._position = 0; }; DataBuffer.prototype.uncompress = function (algorithm) { if (arguments.length === 0) { algorithm = 'zlib'; } else { algorithm = axCoerceString(algorithm); } var inflate; switch (algorithm) { case 'zlib': inflate = Inflate.create(true); break; case 'deflate': inflate = Inflate.create(false); break; case 'lzma': inflate = new LzmaDecoder(false); break; default: return; } var output = new DataBuffer(); var error; inflate.onData = output.writeRawBytes.bind(output); inflate.onError = function (e) { return error = e; }; inflate.push(this._u8.subarray(0, this._length)); if (error) { assert(this.sec); this.sec.throwError('IOError', Errors.CompressedDataError); } inflate.close(); this._ensureCapacity(output._u8.length); this._u8.set(output._u8); this.length = output.length; this._position = 0; }; DataBuffer._nativeLittleEndian = new Int8Array(new Int32Array([1]).buffer)[0] === 1; /* The initial size of the backing, in bytes. Doubled every OOM. */ DataBuffer.INITIAL_SIZE = 128; DataBuffer._arrayBufferPool = new ArrayBufferPool(); return DataBuffer; }()); export { DataBuffer };