Created
March 6, 2012 19:59
-
-
Save jonnyreeves/1988661 to your computer and use it in GitHub Desktop.
Loads DisplayObjects from foreign domains
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package uk.co.jonnyreeves | |
{ | |
import flash.display.Loader; | |
import flash.events.ErrorEvent; | |
import flash.events.Event; | |
import flash.events.EventDispatcher; | |
import flash.events.IEventDispatcher; | |
import flash.events.IOErrorEvent; | |
import flash.events.SecurityErrorEvent; | |
import flash.net.URLRequest; | |
import flash.net.URLStream; | |
import flash.utils.ByteArray; | |
import flash.utils.Dictionary; | |
import flash.utils.Endian; | |
/** | |
* DisplayObject Loader which works around the Flash SecuritySandbox limitations faced when loading DisplayObjects | |
* from foreign domains. The loaded DisplayObject will act as if it was loaded in the local SecurityDomain, | |
* allowing direct access the Stage. | |
* | |
* @author John Reeves. | |
*/ | |
public class DisplayObjectStreamLoaderImpl extends EventDispatcher | |
{ | |
/** | |
* Dispatched when the remote DisplayObject has been loaded and is ready for use. | |
*/ | |
[Event(name="DisplayObjectLoaderEvent::COMPLETE", type="com.moshigames.api.service.DisplayObjectLoaderEvent")] | |
/** | |
* Dispatched if the remote DisplayObject could not be loaded. | |
*/ | |
[Event(name="error", type="flash.events.ErrorEvent")] | |
private var stream : URLStream = new URLStream(); | |
private var byteLoader : Loader = new Loader(); | |
private var listenerMap : Dictionary = new Dictionary(); | |
/** | |
* Loads the Content SWF at the supplied url into the current Application and Security Domains. | |
* | |
* @param urlRequest URLRequest object to use when communicating with the endpoint. | |
*/ | |
public function load(urlRequest : URLRequest) : void | |
{ | |
stream.endian = Endian.LITTLE_ENDIAN; | |
mapListener(stream, Event.COMPLETE, onStreamLoadCompleteEvent); | |
mapListener(stream, IOErrorEvent.IO_ERROR, onErrorEvent); | |
mapListener(stream, SecurityErrorEvent.SECURITY_ERROR, onErrorEvent); | |
try | |
{ | |
stream.load(urlRequest); | |
} | |
catch (e : Error) | |
{ | |
onLoadError(e.message); | |
} | |
} | |
private function onStreamLoadCompleteEvent(event : Event) : void | |
{ | |
// Dump the loaded stream into a new ByteArray which we can then load. | |
const contentBytes : ByteArray = new ByteArray(); | |
stream.readBytes(contentBytes); | |
// Release the stream. | |
unMapListenersOf(stream); | |
stream = null; | |
loadContentSWFBytes(contentBytes); | |
} | |
/** | |
* Second phase of the load operation requires us to re-load the ByteArray as a SWF; the bytes will be loaded | |
* into the current Application and Security domain allowing the content to execute. | |
*/ | |
private function loadContentSWFBytes(contentBytes : ByteArray) : void | |
{ | |
mapListener(byteLoader.contentLoaderInfo, Event.COMPLETE, onBytesLoadedEvent); | |
mapListener(byteLoader.contentLoaderInfo, SecurityErrorEvent.SECURITY_ERROR, onErrorEvent); | |
try | |
{ | |
byteLoader.loadBytes(contentBytes); | |
} | |
catch (e : Error) | |
{ | |
onLoadError(e.message); | |
} | |
} | |
/** | |
* All load operations complete. | |
*/ | |
private function onBytesLoadedEvent(event : Event) : void | |
{ | |
dispatchEvent(new DisplayObjectLoaderEvent(DisplayObjectLoaderEvent.COMPLETE, byteLoader.content)); | |
releaseAll(); | |
} | |
private function onErrorEvent(event : ErrorEvent) : void | |
{ | |
onLoadError(event.text); | |
} | |
private function onLoadError(errorMessage : String) : void | |
{ | |
releaseAll(); | |
dispatchEvent(new ErrorEvent(ErrorEvent.ERROR, false, false, errorMessage)); | |
} | |
private function releaseAll() : void | |
{ | |
unMapListenersOf(stream); | |
unMapListenersOf(byteLoader.contentLoaderInfo); | |
listenerMap = null; | |
stream = null; | |
byteLoader = null; | |
} | |
private function mapListener(target : IEventDispatcher, type : String, listener : Function) : void | |
{ | |
const mappings : Object = listenerMap[target] ||= new Dictionary(); | |
mappings[type] = listener; | |
target.addEventListener(type, listener); | |
} | |
private function unMapListenersOf(target : IEventDispatcher) : void | |
{ | |
const mappings : Object = listenerMap[target]; | |
if (mappings) | |
{ | |
for (var type : String in mappings) | |
{ | |
target.removeEventListener(type, mappings[type]); | |
} | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment