UNPKG

@awayfl/avm2

Version:

Virtual machine for executing AS3 code

356 lines (355 loc) 13 kB
import { getCONSTANTName } from './CONSTANT'; import { internNamespace } from './internNamespace'; import { release } from '@awayfl/swf-loader'; import { assert } from '@awayjs/graphics'; import { internPrefixedNamespace } from './internPrefixedNamespace'; import { axCoerceString } from '../../run/axCoerceString'; import { isNumeric } from '@awayfl/swf-loader'; import { Settings } from '../../Settings'; var Multiname = /** @class */ (function () { function Multiname(abc, index, kind, namespaces, name, parameterType, mutable) { if (parameterType === void 0) { parameterType = null; } if (mutable === void 0) { mutable = false; } this.abc = abc; this.index = index; this.kind = kind; this.namespaces = namespaces; this.name = name; this.parameterType = parameterType; this.mutable = mutable; this.id = Multiname._nextID++; this._mangledName = null; this.globalInfo = null; this.numeric = false; this.numericValue = 0; this.resolved = {}; this._scope = null; this._value = null; this._key = null; // ... } Multiname.prototype.set = function (name, namespace) { // try to cast name to numeric, required for objects with numeric key's // {0: 1} var isIndexator = (typeof name === 'number' || (typeof name === 'string' // name maybe as object for Map && !name.includes('.') // check case when name is `1.0` && Number.isInteger(+name) // check that real integer, same as isFinite )); if (typeof name === 'object') { //debugger; } this.namespaces = namespace ? [namespace] : []; this.name = name; this.numeric = false; if (isIndexator) { this.numericValue = +name; this.numeric = true; } }; /** * Drop field for RT name * @see https://github.com/awayfl/avm2/issues/4 */ Multiname.prototype.drop = function () { if (!this.mutable || !this.isRuntimeName) { // throw "DROP allowed only foe runtime name"; return; } this.numeric = false; this.name = undefined; this.namespaces = []; this.numericValue = NaN; this.resolved = {}; this._scope = null; }; Object.defineProperty(Multiname.prototype, "scope", { get: function () { return (!this._scope || !Multiname._isWeak) ? this._scope : this._scope.deref(); }, set: function (v) { if (Multiname._isWeak && v) { this._scope = new self.WeakRef(v); return; } this._scope = v; }, enumerable: false, configurable: true }); Object.defineProperty(Multiname.prototype, "value", { get: function () { return (!this._value || !Multiname._isWeak) ? this._value : this._value.deref(); }, set: function (v) { if (Multiname._isWeak && v) { this._value = new self.WeakRef(v); return; } this._value = v; }, enumerable: false, configurable: true }); Multiname.prototype.key = function () { if (this._key) return this._key; var r = this.toString(); if (!this.mutable) this._key = r; return r; }; Multiname.FromFQNString = function (fqn, nsType) { var lastDot = fqn.lastIndexOf('.'); var uri = lastDot === -1 ? '' : fqn.substr(0, lastDot); var name = lastDot === -1 ? fqn : fqn.substr(lastDot + 1); var ns = internNamespace(nsType, uri); return new Multiname(null, 0, 15 /* CONSTANT.RTQName */, [ns], name); }; Multiname.prototype._nameToString = function () { if (this.isAnyName()) { return '*'; } return this.isRuntimeName() ? '[' + this.name + ']' : this.name; }; Multiname.prototype.isRuntime = function () { switch (this.kind) { case 7 /* CONSTANT.QName */: case 13 /* CONSTANT.QNameA */: case 9 /* CONSTANT.Multiname */: case 14 /* CONSTANT.MultinameA */: return false; } return true; }; Multiname.prototype.isRuntimeName = function () { switch (this.kind) { case 17 /* CONSTANT.RTQNameL */: case 18 /* CONSTANT.RTQNameLA */: case 27 /* CONSTANT.MultinameL */: case 28 /* CONSTANT.MultinameLA */: return true; } return false; }; Multiname.prototype.isRuntimeNamespace = function () { /* switch (this.kind) { case CONSTANT.RTQName: case CONSTANT.RTQNameA: case CONSTANT.RTQNameL: case CONSTANT.RTQNameLA: return true; }*/ return this.kind >= 15 /* CONSTANT.RTQName */ && this.kind <= 18 /* CONSTANT.RTQNameLA */; }; Multiname.prototype.isAnyName = function () { return this.name === null; }; Multiname.prototype.isAnyNamespace = function () { if (this.isRuntimeNamespace() || this.namespaces.length > 1) { return false; } return this.namespaces.length === 0 || this.namespaces[0].uri === ''; // x.* has the same meaning as x.*::*, so look for the former case and give // it the same meaning of the latter. // return !this.isRuntimeNamespace() && // (this.namespaces.length === 0 || (this.isAnyName() && this.namespaces.length !== 1)); }; Multiname.prototype.isQName = function () { var kind = this.kind; var result = kind === 29 /* CONSTANT.TypeName */ || kind === 7 /* CONSTANT.QName */ || kind === 13 /* CONSTANT.QNameA */ || kind >= 15 /* CONSTANT.RTQName */ && kind <= 18 /* CONSTANT.RTQNameLA */; release || assert(!(result && this.namespaces.length !== 1)); return result; }; Object.defineProperty(Multiname.prototype, "namespace", { get: function () { release || assert(this.isQName()); return this.namespaces[0]; }, enumerable: false, configurable: true }); Object.defineProperty(Multiname.prototype, "uri", { get: function () { release || assert(this.isQName()); return this.namespaces[0].uri; }, enumerable: false, configurable: true }); Object.defineProperty(Multiname.prototype, "prefix", { get: function () { release || assert(this.isQName()); return this.namespaces[0].prefix; }, set: function (prefix) { release || assert(this.isQName()); var ns = this.namespaces[0]; if (ns.prefix === prefix) { return; } this.namespaces[0] = internPrefixedNamespace(ns.type, ns.uri, prefix); }, enumerable: false, configurable: true }); Multiname.prototype.equalsQName = function (mn) { release || assert(this.isQName()); return this.name === mn.name && this.namespaces[0].uri === mn.namespaces[0].uri; }; Multiname.prototype.matches = function (mn) { release || assert(this.isQName()); var anyName = mn.isAnyName(); if (anyName && !mn.isQName()) { return true; } if (!anyName && this.name !== mn.name) { return false; } var uri = this.namespaces[0].uri; // @todo: not sure about this. // seems like its needed to match for xml nodes that have uri=="" if (uri == '' || uri == 'default') return true; for (var i = mn.namespaces.length; i--;) { // @todo: not sure about this. needed for xml if (mn.namespaces[i].uri == '' || mn.namespaces[i].uri === uri) { return true; } } return false; }; Multiname.prototype.isAttribute = function () { switch (this.kind) { case 13 /* CONSTANT.QNameA */: case 16 /* CONSTANT.RTQNameA */: case 18 /* CONSTANT.RTQNameLA */: case 14 /* CONSTANT.MultinameA */: // Why? I not found a reason for L, in any cases is only A is figured //case CONSTANT.MultinameL: // eslint-disable-next-line no-fallthrough case 28 /* CONSTANT.MultinameLA */: return true; } return false; }; Multiname.prototype.getMangledName = function () { release || assert(this.isQName()); return this._mangledName || this._mangleName(); }; Multiname.prototype._mangleName = function () { release || assert(!this._mangledName); var mangledName = '$Bg' + axCoerceString(this.name); if (!this.isRuntime()) { this._mangledName = mangledName; } return mangledName; }; Multiname.prototype.getPublicMangledName = function () { if (isNumeric(this.name)) { return this.name; } return '$Bg' + axCoerceString(this.name); }; Multiname.isPublicQualifiedName = function (value) { return value.indexOf('$Bg') === 0; }; Multiname.getPublicMangledName = function (name) { if (isNumeric(name)) { return name; } return '$Bg' + name; }; Multiname.prototype.toFQNString = function (useColons) { release || assert(this.isQName()); var prefix = this.namespaces[0].uri; if (prefix.length) { prefix += (useColons ? '::' : '.'); } return prefix + this.name; }; Multiname.prototype.toString = function () { var str = getCONSTANTName(this.kind) + ' '; str += this.isAttribute() ? '@' : ''; if (this.isRuntimeNamespace()) { var namespaces = this.namespaces ? this.namespaces.map(function (x) { return String(x); }).join(', ') : null; str += '[' + namespaces + ']::' + this._nameToString(); } else if (this.isQName()) { str += this.namespaces[0] + '::'; str += this._nameToString(); } else if (this.namespaces) { str += '{' + this.namespaces.map(function (x) { return String(x); }).join(', ') + '}'; str += '::' + this._nameToString(); } else { str += '{' + this.namespaces + '}'; str += '::' + this._nameToString(); } if (this.parameterType) { str += '<' + this.parameterType + '>'; } return str; }; Multiname.prototype.toFlashlogString = function () { var namespaceUri = this.uri; return namespaceUri ? namespaceUri + '::' + this.name : this.name; }; /** * Removes the public prefix, or returns undefined if the prefix doesn't exist. */ Multiname.stripPublicMangledName = function (name) { if (name.indexOf('$Bg') === 0) { return name.substring(3); } return undefined; }; Multiname.FromSimpleName = function (simpleName) { var _a; var realName = ''; // hack when simple-name is a XMLList returned from "attribute" getter // when working with xml if (typeof simpleName !== 'string' && ((_a = simpleName._children) === null || _a === void 0 ? void 0 : _a.length) === 1) { simpleName = simpleName._children[0]._value || ''; } else { realName = simpleName; } //case for `com.package.name::className` var nameIndex = realName.lastIndexOf('::'); if (nameIndex > 0) { // trim extra : realName = realName.replace('::', ':'); } else { //case for `com.package.name.className` nameIndex = realName.lastIndexOf('.'); } if (nameIndex <= 0) { // todo Fix multiname resolver for simple name // case for `com.package.name className` // bugged on BBR, game has sounds named as 'bison 8-bit', 'bison victory' //nameIndex = realName.lastIndexOf(' '); } var uri = ''; var name = realName; if (nameIndex > 0 && nameIndex < realName.length - 1) { name = realName.substring(nameIndex + 1).trim(); uri = realName.substring(0, nameIndex).trim(); } var ns = internNamespace(0 /* NamespaceType.Public */, uri); return new Multiname(null, 0, 15 /* CONSTANT.RTQName */, [ns], name); }; Multiname._isWeak = self.WeakRef && Settings.USE_WEAK_REF; Multiname._nextID = 1; return Multiname; }()); export { Multiname };