Skip to content

Instantly share code, notes, and snippets.

@jonnyreeves
Created March 6, 2012 19:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jonnyreeves/1988661 to your computer and use it in GitHub Desktop.
Save jonnyreeves/1988661 to your computer and use it in GitHub Desktop.
Loads DisplayObjects from foreign domains
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