Привет!
Давненько у нас не было хорошего разбойничьего налёта тематического контента — пора бы это исправить!)
Итак, как вы уже наверняка догадались из темы этого поста — речь пойдёт о применении библиотеки 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 :D)
Если у вас остались какие-либо вопросы или есть какие-нибудь замечания, предложения — оставляйте свои комментарии — я их обязательно прочту!
Спасибо, интересно.
Рад, что вам понравилось!
Было необходимо сделать генерацию swf с embed-тегами прямо в коде, а материала очень мало в сети. Спасибо большое за статью)
На здоровье! =)
Согласна с автором выше, материала очень мало, но документация adobe http://www.adobe.com/devnet/swf.html (спецификации байт кода) с успехом заменяют документацию по этим продуктам (т.к. названия все те же). Вопрос такой, as3-commons bytecode сайт почему-то отвалился, надолго ли это (swc вроде нашелся, но документации или исходников или примеров нет)? И насколько надежна as3abc в нынешнем виде? Нужно модифицировать именно as3 код. Спасибо
Вы желаете изменить код «на лету», или требуется статичное изменение? Во втором случае можно использовать дизассемблеры и другие инструменты.
На счёт первого случая — я давно не слежу за ситуацией с соответствующими библиотеками и к сожалению не смогу ничего подсказать.
Мне надо динамически генерировать swf на основе введенных пользователем данных (пишу конструктор учебных тренажеров). Сейчас программа пишет код выходной программы и код исполняемого файла jsfl (который загружает картинки и запускает компиляцию во fla документе). Все нормально, но для этого нужно 1) air (настольное приложение, т.к. flash с файловой системой работать так близко отказывается); и 2) запускать компилятор через jsfl вручную. Если б сразу флешку генерировал, было бы просто супер.
Понятно, да, для таких целей вам нужно что-то типа as3commons для генерации тэга DoABC, который затем можно добавить во флэшку с помошью as3swf.
К сожалению, как я уже упоминал, я давно перестал следить за такими инструментами, надеюсь, вы найдёте что-то подходящее.
а можно ли таким способом заменить заэмбеженый фонт? у меня не получилось, но может я как-то не так делаю.
На сегодняшний день я бы рекомендовал использовать последний FFDec, он многое теперь умеет.
не могу найти, что такое FFDec
Первая ссылка в гугле правильная — https://www.free-decompiler.com/flash/
это я видел, но мне надо заменять шрифт в заэмбеженой флешке рантайм.
Не совсем понял задачу. Вам нужно во время выполнения флэшки подменить шрифт в другой, заэмбеженной флэшке? И ни в первую ни во вторую нельзя вмешиваться до запуска?
Да. Вообще задача такая — грузить шрифт в рантайме.
Ну тогда надо подправить код, чтобы шрифт подгружался и удостовериться что текстовые поля смогут его отобразить. В FFDec можно эмбедить новые шрифты и менять наборы символов у текстовых полей.
Наверное лучше переместиться в почту\скайп а то в коментах беседу трудно вести.