2

我们正在制作一个系统,该系统具有用于应用程序的主 swf,并从单独的 swf 加载单独的工具——将来会有版本控制问题,因为单独的 swf 来自 cms(尤其是现在,因为我们仍在开发,但将来其他开发人员可能会创建不兼容的工具时)。我正在努力尽可能地阻止它们,但我真的希望能够在加载不兼容的 swf 时向系统用户显示一条消息。

这意味着我们需要捕获该 VerifyError 或至少确定由于某种原因加载失败 - 我目前不知道如何处理。我怀疑使用 10.1 和 uncaughtError 系统可能是可能的,但我们目前的目标是 flash player 10。有没有人有好主意?(我们已经在处理 IOErrorEvent.IO_ERROR)

更新:我已经构建了一个在导入之前扫描字节码的解决方案,看起来可以工作。我稍后会发布解决方案。

4

5 回答 5

1

最好的方法是使用 bhups 建议的库之一。我在下一个例子中使用了 senocular 的。此外,由于 senocular 的库仅提供解析后的 SWF 的基本操作,您可能需要 SWF 格式规范 (adobe.com/devnet/swf/pdf/swf_file_format_spec_v10.pdf) 从加载的 SWF 中获取所需的信息。

下一个示例列出了加载的 SWF 中的所有类名:

package swf
{
 import flash.events.Event;
 import flash.net.URLRequest;
 import flash.net.URLStream;
 import flash.utils.ByteArray;
 import flash.utils.Endian;

 import swf.SWFReader;

 public class GetSWFInfo
 {

  private var swfInfo:SWFReader;

  public function GetSWFInfo()
  {
   var urlRequest:URLRequest = new URLRequest("theswf.swf");
   var loader:URLStream = new URLStream();   
   loader.load(urlRequest);
   loader.addEventListener(Event.COMPLETE, onComplete);
  }


  public function onComplete(e:Event):void {
   var recivedByteArray :ByteArray = new ByteArray();
   URLStream(e.currentTarget).readBytes(recivedByteArray);


   //create a new instance of SWFReader
   swfInfo = new SWFReader();
   //readTag it's a callback function that will be called when a tag is read during the SWF parse process.
   //read more on tags in the SWF specification document
   swfInfo.tagCallback =  readTag;
   //start parsing
   swfInfo.parse(recivedByteArray); 
  }



  public function readTag(tag:uint, bytes:ByteArray):void {


   //76 it's the tag type for SymbolClass tag
   //read more in the SWF specification document
   if (76 == tag) {


    var classesArray:Array = new Array();
    var symbolsNumber:uint = 0;
    var currentId:uint = 0;

    bytes.endian = Endian.LITTLE_ENDIAN;

    //read the symbols Number
    //again read more in the SWF specification document
    symbolsNumber = bytes.readShort();

    bytes.position = 4;

    while (true) {

     var i:uint = bytes.position;

     //every string name ends with a null byte
     //again read more in the SWF specification document
     while(bytes[i] != 0) i++;

     var readAmount:uint = i - bytes.position;

     classesArray.push(bytes.readUTFBytes(readAmount));

     //the last ID is always the base class Id, and it's 0
     currentId=bytes.readUnsignedShort();

     bytes.position++;     

     if (currentId==0) {
      break;
     }
    }

    //this two should be equal
    trace(classesArray.length + 1);//the number of elements in the classesArray
    trace(symbolsNumber);//the number of classes retrived from the SWF

    //list the names
    var name:String;
    for each (name in classesArray) {
     trace(name);
    }

    //now you have an array with all the class names that you can use to compare

   }
  }
 }

}

于 2010-07-23T05:19:06.137 回答
1

我确实误解了您要做什么。

好吧,实际上,我想没有用于验证错误的处理程序,要检测它,您必须与字节码作斗争。

顺便说一句,我有一个想法,这不是您问题的答案,但可能会对您有所帮助。

第 3 方 swf 取决于应该在我的 swf 中的类——如果缺少该类,我会得到 VerifyError。

从这一点来看,我可以建议,如果您将“缺少的类”链接到您的 swf 并将第 3 方 swf 加载到 ApplicationDomain.currentDomain 或 new ApplicationDomain(ApplicationDomain.currentDomain),您可以避免“验证错误”。(这是因为 flash 播放器会在父 swf 中找到缺失类的区别。)

这是我的示例代码,它加载带有验证错误的 swf ( http://teionclub.com/test/xml/main.swf )。

避免 VerifyError - wonderfl build flash online
于 2010-07-26T07:27:03.603 回答
0

我过去曾使用过这种应用程序,但我认为修复加载的 SWF 比处理 VerifyError 更好。VeriyError 表示加载的 SWF 已损坏或格式错误。

SWF 本身格式不正确而不是 SWF 在传输过程中损坏是很自然的。我猜您正在尝试加载 png 或其他名为“.swf”的格式,或者 SWF 是由 Flex 编译器或 Flash 以外的某些软件生成的,例如 swfmill(在后一种情况下,该软件中会有一个错误)。

于 2010-07-18T06:29:36.190 回答
0

我认为有办法解决这个问题。

  1. 使用 URLLoader 或 URLStream 将 swf 加载到 ByteArray 中。
  2. 使用任何开源库来解析像thisthis 这样的 SWF 二进制文件。
  3. 检查它是否验证整个字节数组代表有效的 SWF 文件。
  4. 如果上述测试成功,则使用 loadBytes 方法将此 ByteArray 加载到加载器中。
  5. 否则向用户显示这不起作用。

免责声明:二进制文件可以是有效的 SWF,但仍可能无法呈现,但您可以丢弃所有无效的 SWF 或扩展名更改为 swf 的任何其他格式。

于 2010-07-21T06:31:06.223 回答
0

为了最终回答我自己的问题,这是我一直用来检测可能错误的实用程序类。我将 SWF 作为字节数组加载,并在将其加载为实际的 MovieClip 之前扫描内容。

如您所见,我的代码在很大程度上取决于com.segfaultlabs.swfutils 包

重要提示:我已经停止使用这种防止错误的方法,而是选择了更手动的方法来检查文件,方法是实际尝试加载它们并查看它们是否有效。这是因为该实用程序不完整,而且我目前对 ABC 格式的了解还不足以确保我可以开发出始终正确的检查。

在这里发布我的代码作为其他想要尝试它的人的起点:-)

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 < 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;
        }
    }
}
于 2012-06-10T20:04:39.750 回答