UNPKG

@awayfl/avm2

Version:

Virtual machine for executing AS3 code

173 lines (172 loc) 6.77 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 { StringUtilities } from '@awayfl/swf-loader'; var textDecoder = null; if (typeof TextDecoder !== 'undefined') { textDecoder = new TextDecoder(); } var AbcStream = /** @class */ (function () { function AbcStream(bytes) { this._bytes = bytes; this._view = new DataView(bytes.buffer, bytes.byteOffset); this._position = 0; } AbcStream._getResultBuffer = function (length) { if (!AbcStream._resultBuffer || AbcStream._resultBuffer.length < length) { AbcStream._resultBuffer = new Uint32Array(length * 2); } return AbcStream._resultBuffer; }; Object.defineProperty(AbcStream.prototype, "position", { get: function () { return this._position; }, enumerable: false, configurable: true }); AbcStream.prototype.remaining = function () { return this._bytes.length - this._position; }; AbcStream.prototype.seek = function (position) { this._position = position; }; AbcStream.prototype.advance = function (length) { this._position += length; }; AbcStream.prototype.readU8 = function () { return this._bytes[this._position++]; }; AbcStream.prototype.readU8s = function (count) { var b = new Uint8Array(count); b.set(this._bytes.subarray(this._position, this._position + count), 0); this._position += count; return b; }; AbcStream.prototype.viewU8s = function (count) { var view = this._bytes.subarray(this._position, this._position + count); this._position += count; return view; }; AbcStream.prototype.readS8 = function () { return this._bytes[this._position++] << 24 >> 24; }; AbcStream.prototype.readU32 = function () { return this.readS32() >>> 0; }; AbcStream.prototype.readU30 = function () { var result = this.readU32(); if (result & 0xc0000000) { // TODO: Spec says this is a corrupt ABC file, but it seems that some content // has this, e.g. 1000-0.abc // error("Corrupt ABC File"); return result; } return result; }; AbcStream.prototype.readU30Unsafe = function () { return this.readU32(); }; AbcStream.prototype.readS16 = function () { return (this.readU30Unsafe() << 16) >> 16; }; /** * Read a variable-length encoded 32-bit signed integer. The value may use one to five bytes (little endian), * each contributing 7 bits. The most significant bit of each byte indicates that the next byte is part of * the value. The spec indicates that the most significant bit of the last byte to be read is sign extended * but this turns out not to be the case in the real implementation, for instance 0x7f should technically be * -1, but instead it's 127. Moreover, what happens to the remaining 4 high bits of the fifth byte that is * read? Who knows, here we'll just stay true to the Tamarin implementation. */ AbcStream.prototype.readS32 = function () { var result = this.readU8(); if (result & 0x80) { result = result & 0x7f | this.readU8() << 7; if (result & 0x4000) { result = result & 0x3fff | this.readU8() << 14; if (result & 0x200000) { result = result & 0x1fffff | this.readU8() << 21; if (result & 0x10000000) { result = result & 0x0fffffff | this.readU8() << 28; result = result & 0xffffffff; } } } } return result; }; AbcStream.prototype.readWord = function () { var result = this._view.getUint32(this._position, true); this._position += 4; return result; }; AbcStream.prototype.readS24 = function () { var u = this.readU8() | (this.readU8() << 8) | (this.readU8() << 16); return (u << 8) >> 8; }; AbcStream.prototype.readDouble = function () { var result = this._view.getFloat64(this._position, true); this._position += 8; return result; }; AbcStream.prototype.readUTFString = function (length) { /** * Use the TextDecoder API whenever available. * http://encoding.spec.whatwg.org/#concept-encoding-get */ if (textDecoder) { var position = this._position; this._position += length; return textDecoder.decode(this._bytes.subarray(position, position + length)); } var pos = this._position; var end = pos + length; var bytes = this._bytes; var i = 0; var result = AbcStream._getResultBuffer(length * 2); while (pos < end) { var c = bytes[pos++]; if (c <= 0x7f) { result[i++] = c; } else if (c >= 0xc0) { // multibyte var code = 0; if (c < 0xe0) { // 2 bytes code = ((c & 0x1f) << 6) | (bytes[pos++] & 0x3f); } else if (c < 0xf0) { // 3 bytes code = ((c & 0x0f) << 12) | ((bytes[pos++] & 0x3f) << 6) | (bytes[pos++] & 0x3f); } else { // 4 bytes // turned into two characters in JS as surrogate pair code = (((c & 0x07) << 18) | ((bytes[pos++] & 0x3f) << 12) | ((bytes[pos++] & 0x3f) << 6) | (bytes[pos++] & 0x3f)) - 0x10000; // High surrogate result[i++] = ((code & 0xffc00) >>> 10) + 0xd800; // Low surrogate code = (code & 0x3ff) + 0xdc00; } result[i++] = code; } // Otherwise it's an invalid UTF8, skipped. } this._position = pos; return StringUtilities.fromCharCodeArray(result.subarray(0, i)); }; AbcStream._resultBuffer = new Uint32Array(256); return AbcStream; }()); export { AbcStream };