Распаковщик LZP сделал. Меня, правда, озадачило, что распакованный файл оказался 8 килобайт в размере (там куча нулей в конце) и с другим начальным адресом (исходник и распакованный файл в аттаче). Возможно, архиватор определяет, что его пытаются заархивировать и как-то по особому себя ведет.
-----------
Пару мыслей по архиватору и формату архива. Это 100% не RLE, не байтовый упаковщик, а точно вариант алгоритма LZSS.
Меня, конечно, любопытство загрызло: насколько это оригинальная разработка? И стоит ли писать распаковщик, может, он давно в интернете лежит :) Все-таки, в 1992-м не так много было информации по этим алгоритмам. Лично я на тот момент знал только про RLE, а что-то почитать по Лемпелю с Зивом удалось только парой лет позже. То есть почитать-то можно было и раньше, но для этого надо было откуда-то узнать эти фамилии.
Я попытался найти какие-то "корни", но все оказалось очень туманно. Вариантов LZSS было написано видимо-невидимо. Известно, что большая их часть создавалась на базе кода, который в 1989 году написал японец Харухико Окумура. В 90-м году под MSX был сделан упаковщик исполняемых файлов PMEXE, но описания его формата архива я не нашел.
Сам алгоритм состоит в том, что берутся байты из входного потока, проверяется, не встречалась ли такая же последовательность байт раньше, и если встречалась, то вместо самих байт пишутся битовый флаг, смещение относительно текущей позиции и длина последовательности. Это называется обратная ссылка или back reference. Если повтор найти не удалось, то пишется другой битовый флаг и исходный байт. Это называется литерал.
В LZP используется тот же формат ссылок, что и в оригинальном LZSS (12 бит - смещение, 4 бита - длина). Но в дополнение к этому формату ссылок добавлено еще два - с 8-битовым смещением и 2-битовой длиной, и с 12-битовым смещением и 8-битной длиной. В общем, схожесть с LZSS прослеживается, но явно добавлено что-то свое.
При распаковке, насколько я понял, упакованные данные переписываются так, чтобы уместиться до адреса $BFFF. Потом распаковщик их читает и распаковывает в нужный адрес.
В коде распаковщика несколько приколов. Сам он переписывается по адресу $200, а потом, путем патчинга инструкций, ему передаются адрес упакованных данных, значение контрольной суммы и адрес для передачи управления.
До смешного доходит - вот как передается адрес упакованных данных:
LDA STARTADDR
STA PATCH1 + 1
LDA STARTADDR + 1
STA PATCH2 + 1
Ответная часть в распаковщике выглядит так:
PATCH1 LDA #0
STA $D4
PATCH2 LDA #0
STA $D5
Казалось бы, почему бы сразу не вписать адрес в ячейки $D4, $D5? Особенно учитывая, что целевой адрес для распаковки прописывается сразу в нулевую страницу, без патчинга :)
Такая же ерунда с адресом выполнения. По умолчанию там захардкожен JMP по адресу $E003. Похоже на адрес входа в Бейсик Apple, кстати :) А потом адрес патчится на правильный. Но, блин, рядышком стоит косвенный JMP по адресу $FFFC! Почему нельзя было сделать два косвенных JMP?
Кстати, идея проверять контрольную сумму после распаковки, мне кажется, не слишком удачная. Потому что, если повреждены упакованные данные, то при распаковке может случиться что угодно. Например, данных распакуется больше, чем нужно и что-то в памяти будет затерто, либо цикл распаковки не остановится вообще.
В распаковщике есть проверка, чтобы текущий адрес распакованных данных не превысил текущий адрес упакованных. Но почему-то только в одной из веток кода.