Итак, как вы уже наверняка догадались из темы этого поста — речь пойдёт о применении библиотеки as3swf для редактирования SWF файла.
Для начала, расскажу немного о самой библиотеке.
Она предназначена для расковыривания SWF файлов в реальном времени — с помощью as3swf вы можете распарсить SWF файл из массива байт, пробежаться по всем его тэгам, выяснить все его характеристики (такие как частота кадров, версия и т.д.), а также, что весьма приятно, вы можете внести изменения в распарсенный SWF — удалить, добавить, заменить или изменить любой тэг, и после всех изменений сохранить SWF в массив байт. Можно даже создать SWF с нуля.
as3swf доступна для всевозможных действий на гитхабе: https://github.com/claus/as3swf
Библиотека поддерживается, автор (Claus Wahlers) доступен для общения, так что ваши Pull реквесты он заметит, если таковые будут
К слову, не так давно (буквально вчера) автор принял мой Pull реквест на добавление поддержки LZMA сжатия (подробнее про LZMA — тут)
Правда попробовать работу с LZMA в деле можно будет лишь после релиза 11.4.
Единственное, чего мне не хватало в этой библиотеке для ряда задач, так это полноценной поддержки парсинга и изменения ABC байткода, который содержится в тэге DoABC.
Автор as3swf начинал когда-то реализовывать подобный функционал в качестве отдельной библиотеки, но затем прекратил её поддерживать, и в данный момент этот проект уже не актуален.
С другой стороны, мне вполне понятны причины его решения — ведь для этих же целей есть замечательная библиотека as3commons bytecode, которая хоть как-то, но развивается и поддерживается: http://as3-commons.googlecode.com/svn/trunk/as3-commons-bytecode/changelog.txt
Её-то я и использовал для своих целей, но сейчас речь не о том случае.
Я расскажу, зачем мне понадобилась такая библиотека, как as3swf — у меня была задача реализовать замену одного тега на полностью новый аналог, с другим содержимым, если говорить конкретнее — то заменялся тэг DefineBinaryData.
Итак, вот как выглядит код, распарсивающий SWF файл:
var swf:SWF = new SWF(swfByteArray);Где swfByteArray — это массив байт с целевым SWF файлом.
Куда уж проще, да?
После распарсивания SWF, мне необходимо было заменить определенный контент, заэмбеденный во флэшку с помощью флексового тэга
[Embed(source="./data.dat", mimeType="application/octet-stream")] private var EmbeddedDataClass:Class;При использовании такого способа включения контента в SWF, в результате во флэшке появляется ряд особенных вещей, которые необходимо знать, чтобы правильно заменить такой вот заэмбеденный контент.
Во-первых, появляется тэг DefineBinaryData со своим ID символа.
Также в результате использования тэга Embed появляется as3 класс с названием = НазваниеКласса_НазваниеПеременной и расширяющий класс mx.core.ByteArrayAsset.
Если представить, что мы использовали тэг Embed в классе MySuperClass пакета ru.codestage, то полное название будет ru.codestage.MySuperClass_EmbeddedDataClass.
И наконец,, появляется или дополняется тэг SymbolClass, который связывает символы с as3 классами по их id. В этот же тэг добавляются записи, когда вы прописываете линкейдж у символов библиотеки во Flash Pro.
Зная все это, нам не составит труда заменить заэмбеденный файл и ничего не сломать.
Вот, как это можно сделать средствами as3swf:
var newSWFByteArray:ByteArray = new ByteArray();
// эта строка нам уже знакома
var swf:SWF = new SWF(swfByteArray);
var symbolClass:TagSymbolClass;
var defineBinaryData:TagDefineBinaryData;
// пробегаемся по всем тэгам SWFки ...
var leni:uint = swf.tags.length;
var i:uint;
outerLoop: for (i = 0; i < leni; i++ )
{
// ... и ищем тэг SymbolClass
if (swf.tags[i].type == TagSymbolClass.TYPE)
{
symbolClass = (swf.tags[i] as TagSymbolClass);
// после обнаружения тэга SymbolClass, начинаем бегать
// по списку символов в нём
var lenj:uint = symbolClass.symbols.length;
var j:uint;
for (j = 0; j < lenj; j++ )
{
// проверяем имя каждого символа, пока не найдём подходящий
var symbol:SWFSymbol = symbolClass.symbols[j];
if (symbol.name == "ru.codestage.MySuperClass_EmbeddedDataClass")
{
// как только встретился нужный нам символ, мы получаем его ID из поля symbol.tagId
// и тут же пробуем получить символ с таким id из SWF с помощью метода swf.getCharacter()
defineBinaryData = (swf.getCharacter(symbol.tagId) as TagDefineBinaryData);
break outerLoop;
}
}
}
}
// если swf.getCharacter() вернул нам что-то стоящее, то мы перезаписываем данные в нем
if (defineBinaryData)
{
defineBinaryData.binaryData.clear();
defineBinaryData.binaryData.writeUTFBytes(_dataString);
// и сохраняем все изменения в некий ByteArray
swf.publish(newSWFByteArray);
trace("Done!");
}
else
{
trace("[ERROR] No ru.codestage.MySuperClass_EmbeddedDataClass symbol found!");
}
Код достаточно прозрачный и простой, не думаю, что у кого-то его понимание может вызвать сложности.Как видите, as3swf — это мощный и гибкий инструмент (а ведь я продемонстрировал лишь малую часть всего возможного функционала), пользуйтесь им на здоровье!)
Не так давно я с его помощью реализовал для себя систему автоматического сайт-лочинга примерно за один день (бОльшая часть которого ушла на GUI )
Если у вас остались какие-либо вопросы или есть какие-нибудь замечания, предложения — оставляйте свои комментарии — я их обязательно прочту!
Источник:
Если вы ведёте свой блог, микроблог, либо участвуете в какой-то популярной социальной сети, то вы можете быстро поделиться данной заметкой со своими друзьями и посетителями. Для этого воспользуйтесь предлагаемыми ниже кнопками:
Блог: http://romanlovetext.blogspot.com/