Обработка VerifyError: Ошибка № 1014 при загрузке SWF-файлов с использованием AS3 - PullRequest
1 голос
/ 16 июля 2010

Мы создаем систему, которая имеет основной SWF-файл для приложения и загружает отдельные инструменты из отдельных SWF-файлов - в будущем у будут проблемы с версиями, поскольку отдельные SWF-файлы поступают из CMSособенно сейчас, так как мы все еще разрабатываем, но также и в будущем, когда другие разработчики могут создать несовместимый инструмент).Я изо всех сил стараюсь предотвратить их как можно больше, но мне бы очень хотелось иметь возможность отображать сообщение пользователю системы при загрузке несовместимого SWF-файла.

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

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

Ответы [ 5 ]

1 голос
/ 26 июля 2010

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

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

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

сторонний swf зависит от класса, который должен быть в моем swf - если этот класс отсутствует, я получаю VerifyError.

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

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

Избежание VerifyError - чудо-флеш-сборка онлайн
1 голос
/ 23 июля 2010

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

   }
  }
 }

}

0 голосов
/ 11 июня 2012

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

Как видите, мой код сильно зависит от пакета 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;
        }
    }
}
0 голосов
/ 21 июля 2010

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

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

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

0 голосов
/ 18 июля 2010

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

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

...