@awayfl/avm2
Version:
Virtual machine for executing AS3 code
157 lines (150 loc) • 5.19 kB
text/typescript
import { AXSecurityDomain } from '../run/AXSecurityDomain';
import { jsGlobal } from '@awayfl/swf-loader';
import { Errors } from '../errors';
import { wrapJSGlobalFunction } from './wrapJSGlobalFunction';
import { checkValue } from '../run/checkValue';
import { release, assertUnreachable, notImplemented } from '@awayfl/swf-loader';
import { isNullOrUndefined } from '@awayjs/graphics';
import { AXClass } from '../run/AXClass';
import { axCoerceString } from '../run/axCoerceString';
import { getCurrentABC } from '../run/getCurrentABC';
import { NamespaceType } from '../abc/lazy/NamespaceType';
import { Multiname } from '../abc/lazy/Multiname';
import { describeType as describeTypeIntern } from '../natives/describeType';
const getQualifiedClassName = function(_: AXSecurityDomain, value: any): string {
release || checkValue(value);
const valueType = typeof value;
switch (valueType) {
case 'undefined':
return 'void';
case 'object':
if (value === null) {
return 'null';
}
return value.classInfo.instanceInfo.multiname.toFQNString(true);
case 'number':
return (value | 0) === value ? 'int' : 'Number';
case 'string':
return 'String';
case 'boolean':
return 'Boolean';
}
release || assertUnreachable('invalid value type ' + valueType);
};
/**
* Other natives can live in this module
*/
export const Natives = {
print: function(sec: AXSecurityDomain, expression: any, arg1?: any, arg2?: any, arg3?: any, arg4?: any) {
let message;
const objects = [];
if (arguments.length == 2) {
message = arguments[1] ? arguments[1].toString() : arguments[1];
if (['string', 'boolean', 'number', 'null', 'undefined'].indexOf(typeof arguments[1]) === -1)
objects.push(arguments[1]);
} else {
message = '';
for (let i = 1; i < arguments.length;i++) {
message += arguments[i] ? arguments[i].toString() : arguments[i];
if (['string', 'boolean', 'number', 'null', 'undefined'].indexOf(typeof arguments[i]) === -1)
objects.push(arguments[i]);
if (i != arguments.length - 1)
message += ' ';
}
}
console.log('%c Trace from SWF:', 'color: DodgerBlue', message, objects.length == 0 ? '' : objects);
if (message == 'debugger') {
debugger;
}
},
debugBreak: function(v: any) {
/* tslint:disable */
debugger;
/* tslint:enable */
},
bugzilla: function(_: AXSecurityDomain, n) {
switch (n) {
case 574600: // AS3 Vector::map Bug
return true;
}
return false;
},
decodeURI: function(sec: AXSecurityDomain, encodedURI: string): string {
try {
return jsGlobal.decodeURI(encodedURI);
} catch (e) {
sec.throwError('URIError', Errors.InvalidURIError, 'decodeURI');
}
},
decodeURIComponent: function(sec: AXSecurityDomain, encodedURI: string): string {
try {
return jsGlobal.decodeURIComponent(encodedURI);
} catch (e) {
sec.throwError('URIError', Errors.InvalidURIError, 'decodeURIComponent');
}
},
encodeURI: function(sec: AXSecurityDomain, uri: string): string {
try {
return jsGlobal.encodeURI(uri);
} catch (e) {
sec.throwError('URIError', Errors.InvalidURIError, 'encodeURI');
}
},
encodeURIComponent: function(sec: AXSecurityDomain, uri: string): string {
try {
return jsGlobal.encodeURIComponent(uri);
} catch (e) {
sec.throwError('URIError', Errors.InvalidURIError, 'encodeURIComponent');
}
},
isNaN: wrapJSGlobalFunction(jsGlobal.isNaN),
isFinite: wrapJSGlobalFunction(jsGlobal.isFinite),
parseInt: wrapJSGlobalFunction(jsGlobal.parseInt),
parseFloat: wrapJSGlobalFunction(jsGlobal.parseFloat),
escape: wrapJSGlobalFunction(jsGlobal.escape),
unescape: wrapJSGlobalFunction(jsGlobal.unescape),
isXMLName: function () {
return false; // "FIX ME";
},
notImplemented: wrapJSGlobalFunction(notImplemented),
/**
* Returns the fully qualified class name of an object.
*/
getQualifiedClassName(_: AXSecurityDomain, value: any): string {
return getQualifiedClassName(_, value);
},
/**
* Returns the fully qualified class name of the base class of the object specified by the
* |value| parameter.
*/
getQualifiedSuperclassName(sec: AXSecurityDomain, value: any) {
if (isNullOrUndefined(value)) {
return 'null';
}
value = sec.box(value);
// The value might be from another domain, so don't use passed-in the current
// AXSecurityDomain.
const axClass = value.sec.AXClass.axIsType(value) ?
(<AXClass>value).superClass :
value.axClass.superClass;
return getQualifiedClassName(sec, axClass);
},
/**
* Returns the class with the specified name, or |null| if no such class exists.
*/
getDefinitionByName(sec: AXSecurityDomain, name: string): AXClass {
name = axCoerceString(name).replace('::', '.');
const mn = Multiname.FromFQNString(name, NamespaceType.Public);
return getCurrentABC().env.app.getClass(mn);
},
describeType(sec: AXSecurityDomain, value: any, flags: number): any {
return describeTypeIntern(sec, value, flags);
},
describeTypeJSON(sec: AXSecurityDomain, value: any, flags: number) {
console.log('describeTypeJSON not implemented');
return null;//describeTypeJSON(sec, value, flags);
},
getArgv(): any [] {
return null;
}
};