Итак, как вы уже наверняка догадались из темы этого поста — речь пойдёт о применении библиотеки 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/