А как бы было неплохо, показывать билд или дату компиляции .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());
Пример работы:

Где-то полтора года назад внедрили в свои проекты чтение даты компиляции)
ОтветитьУдалитьПолезненько. Формат вообще очень интересно почитать.
ОтветитьУдалитьА вот решение от Alessandro Crugnola вести учет версии приложения и дату компиляции.
ОтветитьУдалить2Slon_vsapogah, а вот и про формат http://www.adobe.com/devnet/swf/pdf/swf_file_format_spec_v9.pdf
ОтветитьУдалить