Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>To finally answer my own question, this is the utility class I've been using to detect possible errors. I load the SWF as a bytearray and scan the contents before loading it as an actual MovieClip.</p> <p>As you can see my code heavily depends on the <a href="http://segfaultlabs.com/swfutils" rel="nofollow">com.segfaultlabs.swfutils package</a> </p> <p>Important: I've stopped using this method of preventing errors, opting for the more manual approach of checking the files by actually trying to load them and see if they work. This is because the utility is not complete, and my current knowledge of the ABC format is not good enough to make sure I can develop a check that will always be correct.</p> <p>Posting my code here as starting point for others who want to take a stab at it :-)</p> <pre><code>package nl.ijsfontein.utils { import com.segfaultlabs.swfutils.ABC.ABCCPool; import com.segfaultlabs.swfutils.ABC.ABCClass; import com.segfaultlabs.swfutils.ABC.ABCInstance; import com.segfaultlabs.swfutils.ABC.ABCMethodInfo; import com.segfaultlabs.swfutils.ABC.ABCMultiname; import com.segfaultlabs.swfutils.ABC.ABCParser; import com.segfaultlabs.swfutils.ABC.ABCTraitConstSlot; import com.segfaultlabs.swfutils.ABC.ABCTraitsInfo; import com.segfaultlabs.swfutils.ABC.ABCinfo; import com.segfaultlabs.swfutils.SWFDataInput; import com.segfaultlabs.swfutils.SWFFile; import flash.system.ApplicationDomain; import flash.utils.ByteArray; /** * utility to see which classes a swf uses, but doesn't contain itself * - this can be used to detect possible VerifyErrors before they happen. */ public class SwfDependencyUtil { public function SwfDependencyUtil() { } // return null if ok, or name of needed class if external depencendy private static function resolveSuper(abc:ABCinfo, superClass:String):String { //if (superClass.indexOf("flash.") == 0 || superClass.indexOf("*") == 0 || superClass.indexOf("Object") == 0) if (superClass.indexOf("*") == 0) { trace(' super: ' + superClass + " (ignore)"); } else { var superClassClass:ABCClass = null; for each ( var c:ABCClass in abc.classes ) { if (c.name == superClass) { superClassClass = c; } } if (superClassClass) { trace(' super: ' + superClass + " (resolved internally)"); return resolveSuper(abc, superClassClass.iref.base); } else { trace(' super: ' + superClass + " (NOTFOUND)"); return superClass; } } return null; } /* * checks: classes, superclasses, static variables, member variables * TODO: function arguments * won't check: method bodies * * TODO: refactor to multiple methods */ public static function getDependencies(swfBytes:ByteArray):Array /* of String */ { var result:Array = []; swfBytes.position = 0; var swfr:SWFFile = new SWFFile(swfBytes); var arr:Array; if ( swfr.compressed ) { swfr.dataInput = swfr.uncompress(); swfr.readHeader(); }; arr = swfr.parseTags(); if ( arr[82] != null ) { var abc:ABCinfo = new ABCinfo(); var cpool:ABCCPool = new ABCCPool(); var abcparse:ABCParser = new ABCParser(); abcparse.readMethodBytes = true; abcparse.readExceptions = false; for ( var j:int = 0; j &lt; arr[82].length; j += 1 ) { swfr.dataInstance.position = arr[82][j].position; try { abcparse.parse( swfr.dataInput as SWFDataInput, abc, cpool, new FakeLogger() ); for each ( var c:ABCClass in abc.classes ) { trace('class:', c.name); var superClass:String = c.iref.base; var dependency:String = resolveSuper(abc, superClass); if (dependency) { result.push(dependency); } for each (var mn:ABCMultiname in c.iref.interfaces) { var interfaceName:String = mn.nsset[0] != "" ? mn.nsset[0] + "::" + mn.name : mn.name; var interfaceDependency:String = resolveSuper(abc, interfaceName); if (interfaceDependency) { result.push(interfaceDependency); } } for each (var ti:ABCTraitsInfo in c.traits) { if (ti is ABCTraitConstSlot) { var constName:String if (QName(ABCTraitConstSlot(ti).type).uri) { constName = QName(ABCTraitConstSlot(ti).type).uri + "::" + QName(ABCTraitConstSlot(ti).type).localName } else { constName = QName(ABCTraitConstSlot(ti).type).localName } var constDependency:String = resolveSuper(abc, constName); if (constDependency) { result.push(constDependency); } } else if (ti is ABCMethodInfo) { trace('method', ABCMethodInfo(ti).name); } else { trace(ti); } // trace(ti.type.localName); } // const (static?) members: c.traits } for each ( var i:ABCInstance in abc.instances ) { // trace(i); for each (var instanceTi:ABCTraitsInfo in i.traits) { if (instanceTi is ABCTraitConstSlot) { trace('instance:', createClassNameFromQname(ABCTraitConstSlot(instanceTi).type)); var csdep:String = resolveSuper(abc, createClassNameFromQname(ABCTraitConstSlot(instanceTi).type)); if (csdep) { result.push(csdep); } } else if (instanceTi is ABCMethodInfo) { } else { trace('unexpected trait type'); } } } abc.dispose(); } catch ( e:Error ) { trace( " Error ",e.getStackTrace() ); }; }; cpool.dispose(); } else { trace("No DoABC block... ;("); } return result; } private static function createClassNameFromQname(qn:QName):String { var result:String if (qn.uri) { result = qn.uri + "::" + qn.localName } else { result = qn.localName } return result; } public static function getUnsatisfiedDependencies(swfBytes:ByteArray):Array /* of String */ { var result:Array = []; var dependencies:Array = SwfDependencyUtil.getDependencies(swfBytes) for each (var dependency:String in dependencies) { if (ApplicationDomain.currentDomain.hasDefinition(dependency)) { trace('ok: ', dependency); } else { trace('ERROR: unsatisfied dependency: ', dependency); result.push(dependency); } } return result; } } } </code></pre>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload