1 /* 2 * Copyright the original author or authors. 3 * 4 * Licensed under the MOZILLA PUBLIC LICENSE, Version 1.1 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.mozilla.org/MPL/MPL-1.1.html 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 import org.as2lib.io.file.AbstractFileLoader; 18 import org.as2lib.data.type.Byte; 19 import org.as2lib.data.holder.Iterator; 20 import org.as2lib.env.event.impulse.FrameImpulse; 21 import org.as2lib.env.event.impulse.FrameImpulseListener; 22 import org.as2lib.io.file.FileLoader; 23 import org.as2lib.io.file.FileNotLoadedException; 24 import org.as2lib.data.type.Time; 25 import org.as2lib.app.exec.Executable; 26 import org.as2lib.data.holder.Map; 27 import org.as2lib.io.file.File; 28 import org.as2lib.io.file.SwfFile; 29 30 /** 31 * {@code SwfLoader} is a implementation of {@link FileLoader} to load 32 * files with {@code loadMovie} (usually {@code .swf} files}. 33 * 34 * <p>Any content to be loaded with {@code MovieClip#loadMovie} can be load with 35 * {@code SwfLoader} to a concrete {@code MovieClip} instance that has to be 36 * passed-in with the constructor. 37 * 38 * <p>{@code SwfLoader} represents the time consuming part of accessing external 39 * {@code .swf}' ({@code SwfFile} is the handleable part} and therefore 40 * contains a event system to add listeners to listen to the concrete events. 41 * It is possible to add listeners using {@code addListener}. 42 * 43 * <p>Example listener: 44 * <code> 45 * import org.as2lib.io.file.AbstractFileLoader; 46 * import org.as2lib.io.file.LoadProgressListener; 47 * import org.as2lib.io.file.LoadStartListener; 48 * import org.as2lib.io.file.LoadCompleteListener; 49 * import org.as2lib.io.file.LoadErrorListener; 50 * import org.as2lib.io.file.FileLoader; 51 * import org.as2lib.io.file.SwfFile; 52 * 53 * class MySwfListener implements 54 * LoadProgressListener, LoadStartListener, 55 * LoadCompleteListener, LoadErrorListener { 56 * 57 * public function onLoadComplete(fileLoader:FileLoader):Void { 58 * var swf:SwfFile = SwfFile(fileLoader.getFile()); 59 * if (swf != null) { 60 * // Proper swf available 61 * } else { 62 * // Wrong event handled 63 * } 64 * } 65 * 66 * public function onLoadError(fileLoader:FileLoader, errorCode:String, error):Void { 67 * if (errorCode == AbstractFileLoader.FILE_NOT_FOUND) { 68 * var notExistantUrl = error; 69 * // Use that url 70 * } 71 * } 72 * 73 * public function onLoadStart(fileLoader:FileLoader) { 74 * // show that this file just gets loaded 75 * } 76 * 77 * public function onLoadProgress(fileLoader:FileLoader) { 78 * // update the percentage display with fileLoader.getPercentage(); 79 * } 80 * } 81 * </code> 82 * 83 * <p>Example of the usage: 84 * <code> 85 * import org.as2lib.io.file.SwfLoader; 86 * 87 * var swfLoader:SwfLoader = new SwfLoader(); 88 * swfLoader.addListener(new MySwfListener()); 89 * swfLoader.load("test.swf"); 90 * </code> 91 * 92 * @author Martin Heidegger 93 * @version 1.1 94 */ 95 class org.as2lib.io.file.SwfFileLoader extends AbstractFileLoader 96 implements FileLoader, FrameImpulseListener { 97 98 /** Time until the method breaks with "File not found". */ 99 public static var TIMEOUT:Time = new Time(3000); 100 101 /** Helper for loading the {@code File}. */ 102 private var holder:MovieClip; 103 104 /** Loaded {@code File}. */ 105 private var result:File; 106 107 /** 108 * Constructs a new {@code SwfLoader} instance. 109 * 110 * @param holder {@code MovieClip} instance to load the {@code .swf} into 111 */ 112 public function SwfFileLoader(holder:MovieClip) { 113 this.holder = holder; 114 } 115 116 /** 117 * Loads a certain {@code .swf} by a http request. 118 * 119 * <p>It sends http request by using the passed-in {@code uri}, {@code method} 120 * and {@code parameters} with {@code .loadMovie}. 121 * 122 * <p>If you only need to listen if the {@code SwfFile} finished loading 123 * you can apply a {@code callBack} that gets called if the {@code File} is loaded. 124 * 125 * @param uri location of the file to load 126 * @param parameters (optional) parameters for loading the file 127 * @param method (optional) POST/GET as method for submitting the parameters, 128 * default method used if {@code method} was not passed-in is POST. 129 * @param callBack (optional) {@link Executable} to be executed after the 130 * the file was loaded. 131 */ 132 public function load(uri:String, method:String, parameters:Map, callBack:Executable):Void { 133 super.load(uri, method, parameters, callBack); 134 result = null; 135 if(parameters) { 136 var keys:Iterator = parameters.keyIterator(); 137 while (keys.hasNext()) { 138 var key = keys.next(); 139 holder[key.toString()] = parameters.get(key); 140 } 141 } 142 holder.loadMovie(uri, method); 143 sendStartEvent(); 144 FrameImpulse.getInstance().addFrameImpulseListener(this); 145 } 146 147 /** 148 * Returns the loaded file. 149 * 150 * @return file that has been loaded 151 * @throws FileNotLoadedException if the file has not been loaded yet 152 */ 153 public function getFile(Void):File { 154 if (!result) { 155 throw new FileNotLoadedException("No File has been loaded.", this, arguments); 156 } 157 return result; 158 } 159 160 /** 161 * Returns the total amount of bytes that has been loaded. 162 * 163 * <p>Returns {@code null} if its not possible to get the loaded bytes. 164 * 165 * @return amount of bytes that has been loaded 166 */ 167 public function getBytesLoaded(Void):Byte { 168 var result:Number = holder.getBytesLoaded(); 169 if (result >= 0) { 170 return new Byte(result); 171 } 172 return null; 173 } 174 175 /** 176 * Returns the total amount of bytes that will approximately be loaded. 177 * 178 * <p>Returns {@code null} if its not possible to get the total amount of bytes. 179 * 180 * @return amount of bytes to load 181 */ 182 public function getBytesTotal(Void):Byte { 183 var total:Number = holder.getBytesTotal(); 184 if (total >= 0) { 185 return new Byte(total); 186 } 187 return null; 188 } 189 190 /** 191 * Handles a {@code frame} execution. 192 * 193 * <p>Helper that checks every frame if the {@code .swf} finished loading. 194 * 195 * @param impulse {@code FrameImpulse} that sent the event 196 */ 197 public function onFrameImpulse(impulse:FrameImpulse):Void { 198 if (checkFinished()) { 199 successLoading(); 200 return; 201 } 202 if (checkTimeout()) { 203 failLoading(); 204 } 205 } 206 207 /** 208 * Checks if the {@code .swf} finished loading. 209 * 210 * @return {@code true} if the {@code .swf} finished loading 211 */ 212 private function checkFinished():Boolean { 213 holder = eval(""+holder._target); 214 if ( holder.getBytesTotal() > 10 215 && holder.getBytesTotal() - holder.getBytesLoaded() < 10) { 216 return true; 217 } 218 return false; 219 } 220 221 /** 222 * Checks if the {@code TIMEOUT} has been exceeded by the durating. 223 * 224 * @return {@code true} if the duration exceeded the {@code TIMEOUT} value 225 */ 226 private function checkTimeout():Boolean { 227 if (holder.getBytesTotal() > 10) { 228 return false; 229 } 230 return (getDuration().valueOf() > TIMEOUT); 231 } 232 233 /** 234 * Handles if the loading of file was successful. 235 */ 236 private function successLoading(Void):Void { 237 finished = true; 238 started = false; 239 result = new SwfFile(holder, uri, getBytesTotal()); 240 endTime = getTimer(); 241 sendCompleteEvent(); 242 tearDown(); 243 } 244 245 /** 246 * Handles if the loading of the file failed. 247 */ 248 private function failLoading(Void):Void { 249 finished = true; 250 started = false; 251 endTime = getTimer(); 252 sendErrorEvent(FILE_NOT_FOUND_ERROR, uri); 253 tearDown(); 254 } 255 256 /** 257 * Removes instance from listening to {@code FrameImpulse}. 258 * 259 * @see #onFrameImpulse 260 */ 261 private function tearDown(Void):Void { 262 FrameImpulse.getInstance().removeListener(this); 263 } 264 265 }