[ActionScript3.0]ForcibleLoaderで読み込んだ外部SWFをSharedObjectに保存する
外部SWFをFlashのクッキーである、SharedObjectに保存できるとはおもいもしませんでした。。。
これにより、私の研究のFlashでのオンライン同期も実現することができます。
参考サイト
外部SWFをSharedObjectに保存
[結果]
サンプル – swf_to_so.swf
ソース – swf_to_so.zip
[概要]
ForcbleLoaderで読み込んだByteArrayのものを、インデックスアクセスにて、Array型の配列に格納し、それをSharedObjectに保存する。
[詳細]
参考サイトによると、SharedObjectに保存するために、バイナリ型で読み込んだSWFを配列から1文字ずつ取り出して文字列にして結合しているようだ。
まず、バイナリ型で読み込むには、URLLoaderを使えばいいのだが、AS3からAS1,2で作成されたムービーを読み込んで扱うには、ForcibleLoaderを使わなくてはいけない。
(ForcibleLoaderについてはこちら)
そこで、まず読み込んだ外部SWFをバイナリで扱うために、ForcibleLoaderをちょっと改造した。
ForcibleLoaderは一度バイナリで読み込んだ後、バイナリの値をあちこちをいじっている。
そして、いじったあとを再びLoaderにloadByteさせることで読み込ませているようだ。
そこで、バイナリの値をいじくったあとのバイナリ型SWFを保存させて・・・
後から取り出せるように変えた。
以下がそのソースである。
ForcibleLoader.as (改造Ver)
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149 package{import flash.display.Loader;import flash.net.URLRequest;import flash.net.URLStream;import flash.events.IOErrorEvent;import flash.events.SecurityErrorEvent;import flash.events.Event;import flash.utils.ByteArray;import flash.utils.Endian;import flash.errors.EOFError;import flash.display.LoaderInfo;public class ForcibleLoader{public function ForcibleLoader(loader:Loader){this.loader = loader;_stream = new URLStream();_stream.addEventListener(Event.COMPLETE, completeHandler);_stream.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);_stream.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);}private var _loader:Loader;public var _stream:URLStream;private var aByte:ByteArray = new ByteArray();public function get loader():Loader{return _loader;}public function set loader(value:Loader):void{_loader = value;}public function load(request:URLRequest):void{_stream.load(request);}private function completeHandler(event:Event):void{var inputBytes:ByteArray = new ByteArray();_stream.readBytes(inputBytes);_stream.close();inputBytes.endian = Endian.LITTLE_ENDIAN;if (isCompressed(inputBytes)) {uncompress(inputBytes);}var version:uint = uint(inputBytes[3]);if (version <= 10) {if (version == 8 || version == 9 || version == 10){flagSWF9Bit(inputBytes);}else if (version <= 7) {insertFileAttributesTag(inputBytes);}updateVersion(inputBytes, 9);}this.aByte = inputBytes;loader.loadBytes(inputBytes);}private function isCompressed(bytes:ByteArray):Boolean{return bytes[0] == 0x43;}private function uncompress(bytes:ByteArray):void{var cBytes:ByteArray = new ByteArray();cBytes.writeBytes(bytes, 8);bytes.length = 8;bytes.position = 8;cBytes.uncompress();bytes.writeBytes(cBytes);bytes[0] = 0x46;cBytes.length = 0;}private function getBodyPosition(bytes:ByteArray):uint{var result:uint = 0;result += 3; // FWS/CWSresult += 1; // version(byte)result += 4; // length(32bit-uint)var rectNBits:uint = bytes[result] >>> 3;result += (5 + rectNBits * 4) / 8; // stage(rect)result += 2;result += 1; // frameRate(byte)result += 2; // totalFrames(16bit-uint)return result;}private function findFileAttributesPosition(offset:uint, bytes:ByteArray):uint{bytes.position = offset;try {for (;;) {var byte:uint = bytes.readShort();var tag:uint = byte >>> 6;if (tag == 69) {return bytes.position - 2;}var length:uint = byte & 0x3f;if (length == 0x3f) {length = bytes.readInt();}bytes.position += length;}}catch (e:EOFError) {}return NaN;}private function flagSWF9Bit(bytes:ByteArray):void{var pos:uint = findFileAttributesPosition(getBodyPosition(bytes), bytes);if (!isNaN(pos)) {bytes[pos + 2] |= 0x08;}}private function insertFileAttributesTag(bytes:ByteArray):void{var pos:uint = getBodyPosition(bytes);var afterBytes:ByteArray = new ByteArray();afterBytes.writeBytes(bytes, pos);bytes.length = pos;bytes.position = pos;bytes.writeByte(0x44);bytes.writeByte(0x11);bytes.writeByte(0x08);bytes.writeByte(0x00);bytes.writeByte(0x00);bytes.writeByte(0x00);bytes.writeBytes(afterBytes);afterBytes.length = 0;}private function updateVersion(bytes:ByteArray, version:uint):void{bytes[3] = version;}private function ioErrorHandler(event:IOErrorEvent):void{loader.contentLoaderInfo.dispatchEvent(new IOErrorEvent(IOErrorEvent.IO_ERROR));}private function securityErrorHandler(event:SecurityErrorEvent):void{loader.contentLoaderInfo.dispatchEvent(new SecurityErrorEvent(SecurityErrorEvent.SECURITY_ERROR));}public function getInputBytes():ByteArray{return this.aByte;}}}
これでバイナリ型の外部SWFを扱えるようになった。
今度は、SharedObjectへの保存だが、参考サイトではString型で値をつなげて保存しているようである。
readStrでも使ってるのかな?
しかし、バイナリ型のデータは普通にインデックスアクセスもできる。
インデックスアクセスすると数値がでるので、それをArrayに保存することにした。
このほうが簡単でわかりやすい!
ちなみに、保存する前にcompressかけることによってサイズを小さくしてます(`・ω・´)
そして、保存した配列をSharedObjectに保存!
次にFlashを読み込んだときは、SharedObjectから逆の操作をして復元!
以下にソースを示す。
main.as
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950 package{import com.yahoo.astra.fl.managers.AlertManager;import flash.display.*;import flash.events.*;import flash.net.URLRequest;import flash.system.Security;import ForcibleLoader;public class main extends Sprite {private var fLoader:ForcibleLoader;private var loader:Loader = new Loader();private var bynarySwf:SwfToBynary;public function main(){var url:String;this.loader.contentLoaderInfo.addEventListener(Event.COMPLETE, _swfComplete);this.bynarySwf = new SwfToBynary( loaderInfo.url );if ( !this.bynarySwf.isSwfExist() ) { //swf_dataがなければ、ロードするurl = "pptest.swf";AlertManager.createAlert( root, "SharedObjectにSWFがない為読み込みます。" );this.forceSwfload( url );} else { //swf_dataがあれば、SharedObjectからロードするAlertManager.createAlert( root, "SharedObjectからSWFを読み込みます。" );this.loader.loadBytes( this.bynarySwf.getSwf() );}}/*** AS2Swfの強制読み込み* @param url SWFアドレス*/public function forceSwfload( url:String ):void{this.fLoader = new ForcibleLoader(this.loader);this.fLoader.load(new URLRequest( url ));}/*** 外部SWF読み込み完了後処理モジュール* @param event SWFの読み込みが終わった際に出るEvent.COMPLETE*/public function _swfComplete(event:Event):void{var mc:MovieClip = new MovieClip();if ( !this.bynarySwf.isSwfExist() ) { //外部SWFが保存されてぁEかったらSharedObjectに保存するthis.bynarySwf.toConvertData( this.fLoader.getInputBytes() );}mc = event.currentTarget.content as MovieClip;addChild( mc );}}}
SwfToBynary.as
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131 package{import flash.display.MovieClip;import flash.display.Sprite;import flash.utils.ByteArray;import flash.events.*;import flash.net.SharedObject;import flash.net.SharedObjectFlushStatus;import flash.external.ExternalInterface;import flash.display.Loader;import flash.net.URLLoader;import flash.net.URLRequest;import flash.net.URLLoaderDataFormat;/*** MovieClipをByteArrayに変換してSharedObjectに保存する* @author Mogmet*/public class SwfToBynary extends Sprite{private var so:SharedObject;private var byteLaoder:Loader = new Loader();/*** コンストラクタ* @param url loader.info*/public function SwfToBynary ( url:String ){this.so = SharedObject.getLocal( "swf_data" );}/*** バイナリ型のMovieClipをintの配列に変える* @param data ByteArray型のMovieClip*/public function toConvertData ( data:ByteArray ):void{var aResult:Array = new Array();var i:int = 0;data.compress(); //データの圧縮for ( i = 0; i < data.length; i++ ) {aResult[i] = data[i];}this.saveSwf( aResult );}/*** SharedObjectに圧縮SWFを保存する* @param swf_data 圧縮SWF配列*/public function saveSwf ( swf_data:Array ):void{var obj = new Object();if ( this.so ) {obj = this.so.data;obj["swf"] = new Array();obj["swf"] = swf_data;try {var str = this.so.flush();switch (str) {case SharedObjectFlushStatus.FLUSHED :trace( "正常にハードディスクに書き込めました。");break;case SharedObjectFlushStatus.PENDING :trace( "ユーザーにSWFを書き込むためのハードディスク書き込み要求を出します。");this.so.addEventListener(NetStatusEvent.NET_STATUS, this._flushStatus);break;}} catch (e) {trace( "書き込みに失敗しました。");}}}/*** HDD書き込み要求がでた場合のユーザーの選択によって表示メッセージを変える。* @param event ハードディスク書き込み要求イベント*/public function _flushStatus(event:NetStatusEvent):void {switch (event.info.code) {case "SharedObject.Flush.Success":trace( "正常にハードディスクに書き込めました。");break;case "SharedObject.Flush.Failed":trace( "test", "ユーザーの拒否により書き込みに失敗しました。");break;}}/*** SharedObjectからByteArray型のSWFを復元する* @return ByteArray型のSWF*/public function getSwf():ByteArray{var obj:Object = new Object();var aByte:ByteArray = new ByteArray();if ( this.so ) {obj = this.so.data;if ( obj["swf"] ) {for ( var i = 0; i < obj["swf"].length; i++ ) {aByte[i] = obj["swf"][i];}try {aByte.uncompress();} catch (e) {trace( "かいとうえらー");}return aByte;} else {return null;}}return null;}/*** SharedObjectに外部SWFがあるかどうかをチェックする* @return 判定結果*/public function isSwfExist ():Boolean{var so:SharedObject;var obj:Object = new Object();if ( this.so ) {obj = this.so.data;if ( obj["swf"] != null ) {return true;} else {return false;}} else {return false;}}}}
こんなかんじでSharedObjectに外部SWFを保存できました。
バイナリで読み込めればなんでもSharedObjectに保存できそうですね。
まいにち食べたい“ごはんのような”クッキーとビスケットの本