@awayfl/avm2
Version:
Virtual machine for executing AS3 code
356 lines (355 loc) • 13 kB
JavaScript
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 };