import { ByteArray, AssetBase } from '@awayjs/core'; import { Font, SceneImage2D } from '@awayjs/scene'; import { MovieClip as AwayMovieClip } from '@awayjs/scene'; import { WaveAudio } from '@awayjs/core'; import { Sound } from '../media/Sound'; import { AXClass, ASObject, Multiname, AXApplicationDomain } from '@awayfl/avm2'; import { SecurityDomain } from '../SecurityDomain'; /** * The ApplicationDomain class is a container for discrete groups of class definitions. * Application domains are used to partition classes that are in the same security domain. * They allow multiple definitions of the same class to exist and allow children to reuse parent * definitions. * *

Application domains are used when an external SWF file is loaded through the Loader class. * All ActionScript 3.0 definitions in the loaded SWF file are stored in the application * domain, which is specified by the applicationDomain property of the LoaderContext * object that you pass as a context parameter of the Loader object's load() or * loadBytes() method. The LoaderInfo object also contains an * applicationDomain property, which is read-only. * All code in a SWF file is defined to exist in an application domain. The current application * domain is where your main application runs. The system domain contains all application domains, * including the current domain, which means that it contains all Flash Player classes.Every application domain, * except the system domain, has an associated parent domain. * The parent domain of your main application's application domain is the system domain. * Loaded classes are defined only when their parent doesn't already define them. * You cannot override a loaded class definition with a newer definition. * For usage examples of application domains, see the. * The ApplicationDomain() constructor function allows you to create an ApplicationDomain object.

* * @internal Security considerations for application domains are discussed in the * applicationDomain property entries of URLRequest and LoaderInfo. */ export class ApplicationDomain extends ASObject { private static _systemDomain: ApplicationDomain; private static getSystemDomain(): ApplicationDomain { if (ApplicationDomain._systemDomain == null) { if (!ApplicationDomain._currentDomain) { return null; } ApplicationDomain._systemDomain = new ( this._currentDomain.sec).flash.system.ApplicationDomain(null, true); } return ApplicationDomain._systemDomain; } private static _currentDomain: ApplicationDomain; private _parentDomain: ApplicationDomain; private _definitions: Object; private _font_definitions: Object; private _audio_definitions: Object; private _memoryView: DataView; private _memory: ByteArray; /*internal*/ axApplicationDomain: AXApplicationDomain; /** * Creates a new application domain. * @param parentDomain If no parent domain is passed in, * this application domain takes the system domain as its parent. */ constructor (parentDomain: ApplicationDomain = null, isSystemDomain: boolean = false) { super(); if (!isSystemDomain && parentDomain == null && ApplicationDomain._currentDomain != null) { //ApplicationDomain.currentDomain; parentDomain = ApplicationDomain.getSystemDomain(); } if (!ApplicationDomain._currentDomain) ApplicationDomain._currentDomain = this; this._parentDomain = parentDomain; this._definitions = {}; this._font_definitions = {}; this._audio_definitions = {}; if (isSystemDomain) { this.axApplicationDomain = this.sec.system; } else if (!parentDomain) { this.axApplicationDomain = this.sec.application; } else { this.axApplicationDomain = new AXApplicationDomain(this.sec, this.parentDomain.axApplicationDomain); } //@ts-ignore // store crossref back this.axApplicationDomain.awayApplicationDomain = this; } /** * Gets the current application domain in which your code is executing. * @internal Question: Do you call System.currentDomain? or Loader.currentDomain or request.currentDomain? */ public static get currentDomain (): ApplicationDomain { /*if(ApplicationDomain._systemDomain==null) ApplicationDomain._systemDomain=new ApplicationDomain(); if(ApplicationDomain._currentDomain==null) ApplicationDomain._currentDomain=new ApplicationDomain(ApplicationDomain._systemDomain);*/ return ApplicationDomain._currentDomain; } public static set currentDomain (value: ApplicationDomain) { ApplicationDomain._currentDomain = value; } /** * Gets and sets the object on which domain-global memory operations * will operate within this ApplicationDomain. */ public get domainMemory(): ByteArray { console.log('[UNSAFE IMPLEMENTATION!] domainMemory:flash/ApplicationDomain'); return this._memory; } public set domainMemory(mem: ByteArray) { console.log('[UNSAFE IMPLEMENTATION!] domainMemory:flash/ApplicationDomain'); // Missed types! ByteArray has buffer instead arraybuffer if (mem || ( this._memory).buffer !== (mem).buffer) { this._memoryView = new DataView((mem).buffer); } this._memory = mem; } /** * Internal DataView for using domainMemory in runtime */ public get internal_memoryView(): DataView { return this._memoryView; } /** * Gets the minimum memory object length required to be used as * ApplicationDomain.domainMemory. */ public static get MIN_DOMAIN_MEMORY_LENGTH (): number { console.log('MIN_DOMAIN_MEMORY_LENGTH not implemented yet in flash/ApplicationDomain'); return 0; } /** * Gets the parent domain of this application domain. */ public get parentDomain (): ApplicationDomain { return this._parentDomain; } public addDefinition (name: string, asset: AssetBase): void { this._definitions[name] = asset; } public addAudioDefinition (name: string, asset: WaveAudio): void { this._audio_definitions[name] = asset; } public addFontDefinition (name: string, asset: Font): void { this._font_definitions[name] = asset; } public hasSymbolForClass(className: string): boolean { return this._definitions[className] || this._font_definitions[className] || this._audio_definitions[className]; } public getSymbolAdaptee(className: string): any { const symbol = this._definitions[className]; if (symbol) { if (symbol.isAsset && symbol.isAsset(SceneImage2D) || !symbol.adapter) { return symbol; } const clone = symbol.adapter.clone(); if (clone.adaptee.isAsset(AwayMovieClip)) { (clone.adaptee).currentFrameIndex = 0; } return clone.adaptee; } else if (this._font_definitions[className]) { return this._font_definitions[className]; } else if (this._audio_definitions[className]) { return this._audio_definitions[className]; } return null; } public getSymbolDefinition(className: string): any { const symbol = this._definitions[className]; if (symbol) { if (symbol.isAsset && symbol.isAsset(SceneImage2D)) { return symbol; } const clone = symbol.adapter.clone(); if (clone.adaptee.isAsset(AwayMovieClip)) { (clone.adaptee).currentFrameIndex = 0; } return clone; } else if (this._font_definitions[className]) { return this._font_definitions[className]; } else if (this._audio_definitions[className]) { const sound = new Sound(); sound.adaptee = this._audio_definitions[className]; //sound.adaptee.adapter=sound; return sound; } } /** * Gets a public definition from the specified application domain. * The definition can be that of a class, a namespace, or a function. * @param name The name of the definition. * @return The object associated with the definition. * @internal throws SecurityError The definition belongs to a domain to which * the calling code does not have access. * @throws ReferenceError No public definition exists with the * specified name. */ public getDefinition (name: string): AXClass { /** * @todo Cache a FromSimpleName */ return this.axApplicationDomain.getClass(Multiname.FromSimpleName(name)); } public getFontDefinition (name: string): Font { return this._font_definitions[name]; } public getAwayJSAudio(name: string): WaveAudio { return this._audio_definitions[name]; } public getAudioDefinition (name: string): Sound { const sound: Sound = new Sound(); sound.adaptee = this._audio_definitions[name]; //sound.adaptee.adapter=sound; return sound; } public getQualifiedDefinitionNames (): string[] { const allDefinitionsnames: string[] = []; for (const key in this._definitions) { if (this._definitions.hasOwnProperty(key)) { allDefinitionsnames[allDefinitionsnames.length] = key; } } return allDefinitionsnames; } /** * Checks to see if a public definition exists within the specified application domain. * The definition can be that of a class, a namespace, or a function. * @param name The name of the definition. * @return A value of true if the specified definition exists; otherwise, false. */ public hasDefinition (name: string): boolean { // Exception will thrown when definition not exist. try { // slow, because run lookup return !!this.getDefinition(name); } catch (e) { return false; } } public hasFontDefinition (name: string): boolean { return this._font_definitions.hasOwnProperty(name); } public hasAudioDefinition (name: string): boolean { return this._audio_definitions.hasOwnProperty(name); } }