UNPKG

@awayfl/avm2

Version:

Virtual machine for executing AS3 code

176 lines (149 loc) 6.43 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 { Multiname } from '../abc/lazy/Multiname'; import { CONSTANT } from '../abc/lazy/CONSTANT'; import { internNamespace } from '../abc/lazy/internNamespace'; import { NamespaceType } from '../abc/lazy/NamespaceType'; import { defineNonEnumerableProperty } from '@awayfl/swf-loader'; import { ASObject } from '../nat/ASObject'; import { Errors } from '../errors'; import { Bytecode } from '../abc/ops'; const proxyNamespace = internNamespace(NamespaceType.Public, 'http://www.adobe.com/2006/actionscript/flash/proxy'); const proxyPrefix = '$' + proxyNamespace.mangledName; /** * The Proxy class lets you override the default behavior of ActionScript operations * (such as retrieving and modifying properties) on an object. */ export class ASProxy extends ASObject { static classInitializer() { const proto: any = this.dPrototype; const asProto: any = ASProxy.prototype; defineNonEnumerableProperty(proto, proxyPrefix + 'getProperty', asProto.native_getProperty); defineNonEnumerableProperty(proto, proxyPrefix + 'setProperty', asProto.native_setProperty); defineNonEnumerableProperty(proto, proxyPrefix + 'callProperty', asProto.native_callProperty); defineNonEnumerableProperty(proto, proxyPrefix + 'hasProperty', asProto.native_hasProperty); defineNonEnumerableProperty(proto, proxyPrefix + 'deleteProperty', asProto.native_deleteProperty); defineNonEnumerableProperty(proto, proxyPrefix + 'getDescendants', asProto.native_getDescendants); defineNonEnumerableProperty(proto, proxyPrefix + 'nextNameIndex', asProto.native_nextNameIndex); defineNonEnumerableProperty(proto, proxyPrefix + 'nextName', asProto.native_nextName); defineNonEnumerableProperty(proto, proxyPrefix + 'nextValue', asProto.native_nextValue); } native_getProperty() { this.sec.throwError('flash.errors.IllegalOperationError', Errors.ProxyGetPropertyError); } native_setProperty() { this.sec.throwError('flash.errors.IllegalOperationError', Errors.ProxySetPropertyError); } native_callProperty() { this.sec.throwError('flash.errors.IllegalOperationError', Errors.ProxyCallPropertyError); } native_hasProperty() { this.sec.throwError('flash.errors.IllegalOperationError', Errors.ProxyHasPropertyError); } native_deleteProperty() { this.sec.throwError('flash.errors.IllegalOperationError', Errors.ProxyDeletePropertyError); } native_getDescendants() { this.sec.throwError('flash.errors.IllegalOperationError', Errors.ProxyGetDescendantsError); } native_nextNameIndex() { // Enumeration traverses the prototype chain. For proxies, this causes problems // because a Proxy-extending class has the MOP override for `axNextNameIndex`, but can't // have the `nextNameIndex` hook defined and thus hits this default hook. In that case, // we'd incorrectly throw an error instead of just returning null if we didn't // special-case here. if (this === <any> this.axClass.dPrototype) { return; } this.sec.throwError('flash.errors.IllegalOperationError', Errors.ProxyNextNameIndexError); } native_nextName() { this.sec.throwError('flash.errors.IllegalOperationError', Errors.ProxyNextNameError); } native_nextValue() { this.sec.throwError('flash.errors.IllegalOperationError', Errors.ProxyNextValueError); } public axGetProperty(mn: Multiname) { let value: any; const trait = typeof mn.name === 'string' ? this.traits.getTrait(mn.namespaces, mn.name) : null; if (trait) { const name = trait.multiname.getMangledName(); value = this[name]; if (typeof value === 'function') { return this.axGetMethod(name); } } else { value = this[proxyPrefix + 'getProperty'](this.sec.AXQName.FromMultiname(mn)); } return value; } public axGetNumericProperty(name: number): any { return this[proxyPrefix + 'getProperty']((+name) + ''); } public axSetNumericProperty(name: number, value: any) { this[proxyPrefix + 'setProperty']((+name) + '', value); } public axSetProperty(mn: Multiname, value: any, bc: Bytecode) { const trait = typeof mn.name === 'string' ? this.traits.getTrait(mn.namespaces, mn.name) : null; if (trait) { super.axSetProperty(mn, value, bc); return; } this[proxyPrefix + 'setProperty'](this.sec.AXQName.FromMultiname(mn), value); } public axCallProperty(mn: Multiname, args: any[], isLex: boolean): any { const trait = typeof mn.name === 'string' ? this.traits.getTrait(mn.namespaces, mn.name) : null; if (trait) { return super.axCallProperty(mn, args, isLex); } const callArgs = [this.sec.AXQName.FromMultiname(mn)].concat(args); return this[proxyPrefix + 'callProperty'](...callArgs); } public axHasProperty(mn: Multiname): any { return this.axHasOwnProperty(mn); } public axHasPublicProperty(nm: string): any { rn.name = nm; if (this.axHasPropertyInternal(rn)) { return true; } return this[proxyPrefix + 'hasProperty'](nm); } public axHasOwnProperty(mn: Multiname): any { const trait = typeof mn.name === 'string' ? this.traits.getTrait(mn.namespaces, mn.name) : null; if (trait) { return true; } return this[proxyPrefix + 'hasProperty'](this.sec.AXQName.FromMultiname(mn)); } public axDeleteProperty(mn: Multiname): any { const trait = typeof mn.name === 'string' ? this.traits.getTrait(mn.namespaces, mn.name) : null; if (trait) { return delete this[trait.multiname.getMangledName()]; } return this[proxyPrefix + 'deleteProperty'](this.sec.AXQName.FromMultiname(mn)); } public axNextName(index: number): any { return this[proxyPrefix + 'nextName'](index); } public axNextValue(index: number): any { return this[proxyPrefix + 'nextValue'](index); } public axNextNameIndex(index: number): number { return this[proxyPrefix + 'nextNameIndex'](index); } } const rn = new Multiname(null, 0, CONSTANT.RTQNameL, [], null, null, true);