«Фавориты Успеха» logo Саморазжимающиеся данные
© FAVOR.com.ua
 
Саморазжимающиеся данные
  

Многие программисты пользуются программой 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 ]
https://favor.com.ua/ru/article/4941.html