Блог от AS3Coder'a о JavaScript, HTML, CSS... и немного о Flash.

четверг, 10 декабря 2009 г.

Как узнать дату компиляции внутри AS3-приложения?

Работая над отладкой AS3-приложения, мы обычно заливаем обновленный .swf-файл на сервер, и идем проверять исчезла ли, только что исправленная, ошибка. Обнаруживаем, что не исчезла. Вспоминаем про кеш браузера, чистим его. Проверяем снова. Опять не исчезла. Думаем как же так получилось... Всё таки приходим к мнению, что кеш не сбросился, и повторяем всё снова...

А как бы было неплохо, показывать билд или дату компиляции .swf-файла.

Оказывается такое возможно благодаря трудам Igor Costa и Paul Sivtsov. Можно узнать дату компиляции внутри .swf-файла.

Компилирую .swf-файл при помощи Flex SDK в результирующий файл записывается некоторая информация. Во Flash IDE, такого не происходит. После полной загрузки .swf-файла, внутри родительского класса можно прочитать байты. А дальше, использую класс flash.utils.ByteArray, можно вытащить те самые данные которые записываются Flex SDK. В них можно найти и дату компиляции.

Для корректной работы в браузерах (исходный класс, взятый с сайта Igor Costa, работал только в дебаг-плеере), я немного изменил класс:

package org.igorcosta.hacks
{
  import flash.display.DisplayObject;
  import flash.display.LoaderInfo;
  import flash.utils.ByteArray;
  import flash.utils.Endian;
  /**
  * Direct reading of SWF file
  * Distributed under the new BSD License
  * @author Paul Sivtsov - ad@ad.by
  */
  public class SWF
  {
    /////////////////////////////////////////////
    // Reference to the parent class
    private var root:DisplayObject;
    //
    /////////////////////////////////////////////
    // Constructor
    function SWF (root:DisplayObject)
    {
      this.root = root;
    }
    //
    /////////////////////////////////////////////
    // Returns compilation date of current module
    public function readCompilationDate(serialNumber: ByteArray = null): Date
    {
      const compilationDate: Date = new Date;
      const DATETIME_OFFSET: uint = 18;
      //
      if (serialNumber == null)
        serialNumber = readSerialNumber();
      //
      /* example of filled SWF_SERIALNUMBER structure
      struct SWF_SERIALNUMBER
      {
        UI32 Id;         // "3"
        UI32 Edition;    // "6"
                         // "flex_sdk_4.0.0.3342"
        UI8 Major;       // "4."
        UI8 Minor;       // "0."
        UI32 BuildL;     // "0."
        UI32 BuildH;     // "3342"
        UI32 TimestampL;
        UI32 TimestampH;
      };
      */
      //
      // the SWF_SERIALNUMBER structure exists in FLEX swfs only, not FLASH
      if (serialNumber == null)
        return null;
      //
      // date stored as uint64
      serialNumber.position = DATETIME_OFFSET;
      serialNumber.endian = Endian.LITTLE_ENDIAN;
      compilationDate.time = serialNumber.readUnsignedInt() + serialNumber.readUnsignedInt() * (uint.MAX_VALUE + 1);
      //
      return compilationDate;
    }
    //
    ///////////////////////////////////////////////////////////////////////////
    // Returns contents of Adobe SerialNumber SWF tag
    public function readSerialNumber(): ByteArray
    {
      const TAG_SERIAL_NUMBER: uint = 0x29;
      return findAndReadTagBody(TAG_SERIAL_NUMBER);
    }
    //
    ///////////////////////////////////////////////////////////////////////////
    // Returns the tag body if it is possible
    public function findAndReadTagBody(theTagCode: uint): ByteArray
    {
      // getting direst access to unpacked SWF file
      //const src: ByteArray = LoaderInfo.getLoaderInfoByDefinition(SWF).bytes;
      const src: ByteArray = root.loaderInfo.bytes;
      //
      /*
      SWF File Header
      Field      Type  Offset   Comment
      -----      ----  ------   -------
      Signature  UI8   0        Signature byte: “F” indicates uncompressed, “C” indicates compressed (SWF 6 and later only)
      Signature  UI8   1        Signature byte always “W”
      Signature  UI8   2        Signature byte always “S”
      Version    UI8   3        Single byte file version (for example, 0x06 for SWF 6)
      FileLength UI32  4        Length of entire file in bytes
      FrameSize  RECT  8        Frame size in twips
      FrameRate  UI16  8+RECT   Frame delay in 8.8 fixed number of frames per second
      FrameCount UI16  10+RECT  Total number of frames in file
      */
      //
      // skip AVM2 SWF header
      // skip Signature, Version & FileLength
      src.position = 8;
      // skip FrameSize
      const RECT_UB_LENGTH:uint = 5;
      const RECT_SB_LENGTH:uint = src.readUnsignedByte() >> (8 - RECT_UB_LENGTH);
      const RECT_LENGTH: uint = Math.ceil((RECT_UB_LENGTH + RECT_SB_LENGTH * 4) / 8);
      src.position += (RECT_LENGTH - 1);
      // skip FrameRate & FrameCount
      src.position += 4;
      //
      while (src.bytesAvailable > 0)
        with (readTag(src, theTagCode))
      {
        if (tagCode == theTagCode)
          return tagBody;
      }
      //
      return null;
    }
    //
    ///////////////////////////////////////////////////////////////////////////
    // Returns tag from current read position
    private function readTag(src: ByteArray, theTagCode: uint): Object
    {
      src.endian = Endian.LITTLE_ENDIAN;
      //
      const tagCodeAndLength: uint = src.readUnsignedShort();
      const tagCode: uint = tagCodeAndLength >> 6;
      const tagLength: uint = function(): uint {
        const MAX_SHORT_TAG_LENGTH: uint = 0x3F;
        const shortLength:uint = tagCodeAndLength & MAX_SHORT_TAG_LENGTH;
        return (shortLength == MAX_SHORT_TAG_LENGTH) ? src.readUnsignedInt() : shortLength;
      }();
      //
      const tagBody: ByteArray = new ByteArray;
      if (tagLength > 0)
        src.readBytes(tagBody, 0, tagLength);
      //
      return {
        tagCode: tagCode,
        tagBody: tagBody
      };
    }
  }
}

SWF.as

Пример использования класса:

var swf:SWF = new SWF (root); // @param root  ссылка на родительский класс приложения.
trace("Complilation Date = " + swf.readCompilationDate().toString());

Пример работы:


    

4 комментария:

  1. Где-то полтора года назад внедрили в свои проекты чтение даты компиляции)

    ОтветитьУдалить
  2. Полезненько. Формат вообще очень интересно почитать.

    ОтветитьУдалить
  3. А вот решение от Alessandro Crugnola вести учет версии приложения и дату компиляции.

    ОтветитьУдалить

Можно использовать некоторые HTML-теги, например <b>, <i>, <a>

Поиск по блогу

Обо мне



Farid Shamsutdinov (AS3Coder)
Russia, Tatarstan, Kazan
as3coder@gmail.com

Подробнее...

Постоянные читатели

© 2014 Farid Shamsutdinov. При копировании материалов, ссылка на источник обязательна. Технологии Blogger.