Отправлено 04 March 2017 - 08:50
Пожертвование пришло - большое спасибо за поддержку проекта!
Кстати, обновил распаковщик - ничего серьёзного, опечатка в сообщении об ошибке.
Насчёт распаковщика - уж очень там муторное сжатие, так что в попытке его расковырять я в какой-то момент понял, что проще будет выдернуть сам алгоритм.
Оставлю небольшие комментарии из того, что я успел разобрать, до того как махнул рукой на всё. Само сжатие напоминает LZSS/LZX от Blizzard / Microsoft, только тут не фиксированный битовый флаг (0 или 1), а он может быть плавающей длинны - до первого 0-го бита (см. ниже объяснение).
sub_16993 - это функция распаковки. На вход она принимает два параметра: входной и выходной буфер, причём в выходном буфере первые два байта должны быть теми, которые прочитаны из файла (не знаю, нужно это или нет, но на всякий случай повторил то, как оригинальный распаковщик работал). Весь остальной файл, кроме упомянутых первых двух байт, передаётся как входной буфер.
Перед началом работы функция сама себя модифицирует. Подозреваю, что это сделано потому что алгоритмы распаковки очень похожи и чтобы не копипастить код разработчики решили таким оригинальным образом "на лету" сами себя пропатчить.
_698B - это массив из трёх смещений, которые функция патчит.
Три вызова call @sub_16A3E - это три патча в памяти. Там я в комментариях указал шестнадцатеричный код что было и стало - мне это нужно было для проверки корректности выдернутого кода. Проверял я только на файле "KGBSDB.SQX", т.к. он был первым, который игра распаковывала будучи запущенной под отладчиком (в SETUP настроил включить звук, т.к. этот файл - это драйвер, как я понял, от Sound Blaster).
Так вот, на этом файле алгоритм распаковки работал (под отладчиком) как-то так:
- читается слово (WORD, 2 байта) из выходного потока, т.к. там какие-то ещё служебные поля в начале были, то первое слово было, кажется, 0x2100;
- далее это слово сдвигается вправо, до тех пор, пока не ноль (т.е. пока там есть хотя бы 1 не нулевой бит);
- если при сдвиге сдвинутый (самый правый) бит был 0 - то тупо копируется байт из входного буфера в выходной;
- если бит 1, то сдвигается опять и смотрится следующий бит - если он 1, то снова сдвигается и так несколько раз; т.е. как только появился 0 - то сдвиг прекращается и, в зависимости от сдвинутых битов, что-то делается. И, это важно, проверяется, что после каждого такого сдвига слово не превратилось в ноль - иначе, как я понял, читается следующее(?), вроде бы.
После того как до меня дошло, что в коде это будет куча if..., if..., if..., то осознал, что нафиг не хочу с этим алгоритмом возиться (а если ещё учесть самоизменяющийся код...) и тупо его выдрал.