2010-07-16 6 views
1

Мы создаем систему с основным swf для приложения и загружаем отдельные инструменты из отдельных swf - там будет быть версиями в будущем, поскольку отдельные swfs исходят из cms (особенно сейчас, поскольку мы все еще развиваемся, но также и в будущем, когда другие разработчики могут создать несовместимый инструмент). Я стараюсь предотвратить их как можно больше, но мне бы очень хотелось иметь возможность отображать сообщение пользователю системы, когда загружается несовместимая swf.Ручка VerifyError: Ошибка # 1014 при загрузке swfs с использованием AS3

Это будет означать, что нам нужно поймать, что VerifyError или по крайней мере определить загрузку по какой-то причине, - я понятия не имею, как с этим справиться в данный момент. Я подозреваю, что это возможно, используя 10.1 и систему uncaughtError, но мы в настоящее время нацелены на flash-плеер 10. Кто-нибудь имеет хорошую идею? (мы уже обрабатываем IOErrorEvent.IO_ERROR)

ОБНОВЛЕНИЕ: Я создал решение, которое сканирует байт-код перед импортом, похоже, что это сработает. Я отправлю решение позже.

+0

ли вы когда-нибудь/разработать решение этой проблемы? И вы разместили его где-то, как вы упомянули? Это было бы очень полезно для меня. Ура! –

+0

Я нашел рабочее решение _semi_, но в конце концов пришлось прибегать к большому количеству проверок во всех источниках и очень жесткому пути обновления, который в основном не позволяет API изменять. Моя проблема заключалась в том, что я не мог понять всю специфику ABC, которую я разбирал, поэтому я мог сканировать наиболее тривиальное использование некоторых классов, но не смог убедиться, что я действительно проверил используемые классы _all_. Я посмотрю, посмотрю, смогу ли я опубликовать то, что покажет (часть), пытающуюся решить эту проблему. –

+0

Хорошо, если вы когда-либо публиковали, что мне очень интересно! –

ответ

0

Чтобы ответить на мой вопрос, это класс полезности, который я использовал для обнаружения возможных ошибок. Я загружаю SWF как bytearray и просматриваю содержимое перед загрузкой в ​​качестве фактического MovieClip.

Как вы можете видеть мой код сильно зависит от com.segfaultlabs.swfutils package

Важно: Я перестал использовать этот метод предотвращения ошибок, выбор в пользу более ручного подхода проверки файлов на самом деле пытается загрузить их и посмотреть, если они работают. Это связано с тем, что утилита не является полной, и мои текущие знания формата 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; 
     } 
    } 
} 
0

Я работал с таким приложением в прошлом, но я думаю, что было бы лучше исправить загруженный SWF, а не обрабатывать VerifyError. VeriyError указывает, что загруженный SWF поврежден или искажен.

И естественно, что сам SWF искажен, а не SWF поврежден во время передачи. Я предполагаю, что вы пытаетесь загрузить png или другой формат с именем «.swf» или SWF генерируется некоторым программным обеспечением, отличным от компилятора Flex или Flash, например swfmill (в последнем случае будет ошибка в этом программном обеспечении).

+0

спасибо за ваш ответ, однако, «исправление» swf не является вариантом, так как я не буду этим заниматься - я в порядке, если он не работает, я просто хочу справиться с ошибкой разумным способом. (Если я обрабатываю checkerror, я могу показать сообщение об ошибке «эта вещь не работает больше») –

0

Я думаю, что есть способ обхода этой проблемы.

  1. загрузить swf с помощью URLLoader или URLStream в ByteArray.
  2. Используйте любую библиотеку с открытым исходным кодом для разбора SWF-двоичного кода, например this или this.
  3. проверить, проверяет ли он, что весь массив байтов представляет действительный файл SWF.
  4. Если тест выше, то загрузите этот ByteArray в загрузчик с помощью метода loadBytes .
  5. Else показать пользователю, что это не работает.

Отказ от ответственности: двоичного файл может быть действительным SWF до сих пор не может быть в состоянии рендеринга, но с этим вы можете отбросить все недействительный СФБ или любые другие форматы, чьи расширения заменяются на швейцарские франки.

+0

Я не беспокоюсь о том, что это не swf-файл, но как бы определить, что swf имеет зависимости от классов, которые недоступно в загрузке swf? Проверяющий запрос обычно появляется из-за отсутствия зависимостей в моем случае. –

1

Лучший способ сделать это - использовать одну из предложенных библиотек bhups. Для следующего примера я использовал senocular's. Кроме того, поскольку библиотека senocular предоставляет только основные операции для разобранного SWF, вам может понадобиться SWF Format Spec (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 

    } 
    } 
} 

}

+0

Спасибо за ваше предложение, но как это поможет мне предотвратить VerifyError? Я не вижу способа найти классы swf _depends_ on - просто возможность указать классные имена в swf не помогает мне, или я чего-то не хватает? –

+0

Ну, если вы загрузите swf с помощью URLStream, вы не получите ошибки, это точно. Затем вы можете проверить содержимое, посмотреть, действительно ли это, ApplicationDomain.hasDefinition и ApplicationDomain. \t getDefinition может пригодиться здесь (вы можете использовать эти методы без разбора swf, но разбор swf дает вам возможность читать любую необходимую информацию) Вот как я это сделаю.Я имею в виду, может быть, я не понимаю вопроса, но если вы хотите убедиться, что сторонние SWF-классы имеют классы, которые вам нужно использовать в них, я думаю, что так оно и есть. –

+0

Что мне нужно - наоборот - сторонний swf зависит от класса, который должен быть в моем swf - если этот класс отсутствует, я получаю VerifyError. Вот почему мне нужно знать классы, в которых он нуждается, но у меня нет, я посмотрю, что я могу найти с помощью swfreader, но я подозреваю, что мне нужно прочитать ABC, чтобы узнать нужную мне информацию. –

1

я неправильно то, что вы пытаетесь сделать.

Ну, на самом деле, я думаю, что для проверки ошибки нет и для ее обнаружения вам нужно сражаться с байтовыми кодами.

Кстати, у меня есть идея, которая не является ответом на ваш вопрос, но может вам помочь.

a 3rd party swf is depending on a class that should be in my swf -- if that class is missing I get the VerifyError.

С этого момента, я могу посоветовать, что если вы связываете «недостающее класс» в ваш SWF и загрузите 3 участника швейцарских франков в ApplicationDomain.currentDomain или новый ApplicationDomain (ApplicationDomain.currentDomain), вы можете избежать " Проверить ошибку ". (Это связано с тем, что флеш-плеер найдет определение недостающего класса в родительском swf.)

Вот мой пример кода, который загружает swf с подтверждением ошибки (http://teionclub.com/test/xml/main.swf).

Avoiding VerifyError - wonderfl build flash online
+1

Спасибо за ваше предложение, ваше предложение работает, если известна сторонняя SWF, и мне нужно только исправить пару из них. К сожалению, это не случай. В эти выходные я разработал решение для своей собственной проблемы, которое сканирует байт-код avm2 и проверяет все классы, используемые в иерархии классов. Я отправлю свое решение позже. –

+0

Ничего себе! increadible !! Это должно быть большим усилием! – 9re

 Смежные вопросы

  • Нет связанных вопросов^_^