Разработчик Джордан Элдридж (автор проекта Webamp) рассказал с подробными техническими деталями, как он смог запустить рендеринг «современных» скинов Winamp в браузере после реверс-инжиниринга байт-кода MAKI (Make a killer interface) и внедрения нужного интерпретатора в javascript. Обсуждение этой темы на Reddit.
Изначально проект Webamp просто реализует классические скины Winamp, которые по сути представляют собой набор спрайт-листов. Они могли изменять внешний вид проигрывателя, но не макет, и они не могли добавлять никаких пользовательских взаимодействий.
Разработчики Winamp 5 представили новый, значительно более мощный движок скинов, который работает на XML-файлах, описывающих пользовательский интерфейс, который становился интерактивным с помощью определённых скиннером скриптов, написанных на специальном языке MAKI. Вместе XML и Maki работали во многом как HTML и javascript. Они позволяли «скинеру» создавать высокодинамичные пользовательские интерфейсы. Это включало интерфейсы с пользовательской анимацией, интерактивными элементами и многим другим.
После работы над классическими скинами Winamp Элдриджу стало интересно узнать о современных скинах. Например, он захотел выяснить, можно ли запустить современные скины в браузере.
Прочитав о том, как были реализованы эти скины, Элдридж узнал, что современные скины распространялись в виде файлов .zip с расширением .wal, которые состояли из файлов .xml и .maki вместе с изображениями. Файлы скриптов .maki содержали скомпилированный байт-код. Некоторые скины также включали исходные файлы .m, но не все. Авторам скинов требовалось скомпилировать свои скины перед их загрузкой. Элдридж понял, что, если ему нужно визуализировать эти скины в браузере, то придётся понять их байт-код и провести реверс-инжиниринг Maki.
Элдридж пояснил, что он был новичком в концепциях байт-кода, интерпретаторов и реверс инжиниринга, поэтому нашёл древний дизассемблер Maki, написанный Ральфом Энгельсом.
Этот скрипт на Perl брал файл байт-кода Maki и пытался создать из него исходный файл. Целевой аудиторией были скиннеры, которые хотели учиться на существующем скрипте скина, который не распространялся с исходным кодом. Поскольку код на Perl должен был понимать семантику байт-кода, чтобы создать эквивалентный исходный код, Элдридж смог прочитать код Perl и разработал свой собственный парсер javascript, способный преобразовывать файлы байт-кода Maki в структурированное представление. Используя большую коллекцию реальных файлов .maki, извлечённых из загруженных скинов, Элдридж смог спустя множество ошибок и подводных камней прийти к нужной реализации проекта.
Имея на руках структурированную версию байт-кода, Элдридж начал работу над интерпретатором. Будучи новичком в этом типе программирования, он склонился к подходу «обучение на практике». Любому читателю, заинтересованному в чтении такого рода работ, Элдридж настоятельно рекомендует книгу Боба Нистрома «Создание интерпретаторов».«Частично потому, что язык немного странный, а в основном потому, что я понятия не имел, что делаю, я потратил довольно много времени, зацикливаясь на таких вещах, как:
Как работают указатели возврата (они идут в стек? Есть ли какой-то другой стек возврата?).
Некоторые загадочные байт-коды, которые декомпилятор подразумевал как имеющие отношение к «защите стека».
Как моделировать скаляры и сложные объекты в стеке.
Каждая из них была интересной головоломкой для общего решения! В какой-то момент я даже попытался дизассемблировать сам Winamp с помощью Ghidra, и хотя мне удалось найти основной цикл интерпретатора, моих навыков C++/дизассемблирования было недостаточно, чтобы это дало много информации.
Но с достаточным количеством итераций и достаточным количеством тестовых случаев (опять же, добытых из моей коллекции реальных скинов) мне удалось заставить его в основном работать!»,
— уточнил Элдридж.
Ссылка на текущую версию интерпретатора на GitHub.
Оказалось, что наличие интерпретатора было на самом деле только началом. Так же, как наличие движка javascript недостаточно для создания браузера, Элдриджу нужно было выяснить, как парсить сопутствующие файлы XML, привязывать их к скриптам в файлах .maki, а также реализовать всю «стандартную библиотеку» Maki. Это включало в себя вещи от базовых служебных функций, вплоть до различных классов, которые моделировали все различные типы объектов пользовательского интерфейса. Порядка 65 классов с множеством методов каждый (их полный список).
«По сути, каждый из этих классов нужно было реализовать и определить некоторое отображение/привязку из его свойств и методов к эквивалентному представлению DOM. Я применил прагматичный подход. Я выбрал самый простой скин, который смог найти, и начал реализовывать классы и методы, необходимые только для рендеринга этого одного скина. Медленно, но верно мне удалось добиться рендеринга одного скина! После этого первого скина я выбрал ещё один небольшой скин, и со временем у меня работала небольшая горстка, а затем и десятки!», — пояснил Элдридж.
«Но в конечном итоге это то, где я потерял запал. Поверхность API была слишком большой для меня, чтобы закончить её за имеющееся у меня время, и даже для того, чтобы выяснить, каково ожидаемое поведение любого класса/метода/свойства, требовались часы ручных проб и ошибок в Winamp. Но что ещё важнее, я так и не нашел удовлетворительного способа подключить эти вложенные объекты к DOM, который был бы масштабируемым для надёжной реализации, производительным, не давал утечек и сохранял бы тонкую разницу в работе DOM и Maki. Я подозреваю, что способ существует, просто я не смог его найти», — сообщил Элдридж.
После того, как проект был в основном заморожен, разработчик под ником x2nie решил его продолжить, чтобы всё работало вместе вместо тщательно продуманных постепенных улучшений, сосредоточенные на детальном паритете с Winamp и элегантной архитектуре на стороне javascript.
В итоге x2nie добился значительного прогресса, заставив работать множество дополнительных функций, но проект все ещё испытывал трудности, чтобы ощущаться надёжным или завершённым.«У меня всё ещё нет чёткого представления о том, как структурировать код JS, чтобы сделать его масштабируемым, чтобы заполнить все необходимые пробелы, оставаясь при этом в значительной степени «правильным». И хотя сейчас работает больше функций, чем когда я в последний раз активно работал над ним, мне, вероятно, сложнее привести код в ту форму, которую я себе представляю. В основном потому, что это больше не код, который я написал.
Тем не менее, за прошедшие годы изменилось несколько вещей. LLM сделали очень повторяющиеся/производные задачи программирования более простыми для масштабирования, а исходный код Winamp был выпущен как «открытый», поэтому теоретически я мог бы взглянуть на фактический исходный код и получить более авторитетные ответы на то, каким должно быть ожидаемое поведение Winamp, и, возможно, иметь более высокую вероятность того, что смогу охватить все необходимое для получения полностью рабочей версии.
К сожалению, лицензия выпущенного кода Winamp на самом деле не является разрешительной, и они фактически изъяли код из GitHub. На данный момент создание производных работ кажется юридически более рискованным, чем до «открытия» исходного кода.
Я всё ещё надеюсь, что в какой-то момент в будущем у меня появится мотивация вернуться к проекту и получить озарение. Но в то же время я очень рад, что проект зашел так далеко!», — подытожил Элдридж.
Источник новости: habr.com