Многие программисты пользуются программой PKLite фирмы PKWare. Эта программа сжимает EXE – и COM-файлы. При сжатии этих файлов PKLITE’ом их объём уменьшается, а работают они так же, как и раньше. Разжимает программу в памяти PKLITE практически мгновенно. А нельзя ли использовать эту удобную утилиту для уменьшения объёма файлов, содержащих данные? Конечно, при этом можно сжимать не любые данные, а только те, которые будут использоваться в ВАШЕЙ программе. Сделать это очень просто. Для этого нужно дописать в начало данных маленький блок, сжать данные PKLITE’ом, а затем из главной программы с помощью процедуры EXEC загрузить и выполнить данные. Блок кода, который дописывается в начало данных, узнаёт, в какой точке находятся загруженные данные, и выходит в родительскую программу. Вот пример кода, дописываемого в начало файла для размера данных не более 64 K (создание COM-файла):
xor ax, ax
mov ds, ax
mov word ptr ds:[7Ch], cs
ret
В шестнадцатеричном коде это выглядит так: 33, C0, 8E, D8, 8C, 0E, 7C, 00, C3. Как видите, при запуске и выполнении этого файла с данными он запишет по адресу 0000:007C значение сегмента кода. После возврата в главную программу будет известно, где начинаются загруженные данные. Адрес 0000:007C — это вектор прерывания графических символов 1Fh. Мы посылаем CS туда потому, что переменные родительской программы будут недоступны. Такой способ сжатия очень удобен для загрузки картинок и оверлеев. При этом программисту не нужно писать свой упаковщик. Я, например, успешно применяю PKLITE для сжатия картинок в играх. Но и у этого способа есть два основных недостатка. Первый: нужно всегда оставлять немного свободной памяти, необходимой для разворачивания файла. Второй: все сжатые файлы с данными должны создаваться во время написания главной программы. Вот программа, которая демонстрирует запуск и вывод на экран картинки для CGA адаптера размером 16000 байт: {$M 1024,0,0} {Heap — 0 байт. Всегда должно быть достаточно памяти,
чтобы запустить и распаковать картинку.}
uses Dos;
var
OldVec,w:word;
Begin
OldVec:=memW[0,$7C]; {Запоминаем старый вектор 1Fh}
Exec(’SCREEN’); {«Запуск» и разжатие картинки}
asm
mov ax, 4 {Переход в графический CGA режим}
int 10h
end;
w:=memW[0:$7C]+$10; {Узнаём сегмент кода
загруженной программы + размер PSP}
move(mem[w:9],mem[$B800:0],8000); {Вывод картинки}
move(mem[w:8009],mem[$BA00:0],8000); {...}
asm
xor ax, ax {Ожидание нажатия [любой] клавиши [перед завершением программы]}
int 16h
mov ax, 3 {Возврат в текстовый режим}
int 10h
end;
memW[0:$7C]:=OldVec {Возвращаем старое значение вектора 1Fh}
End.
[Hackers Club, IndexPro 1’95 ] |