Inferno #05
30 апреля 2004

Sofтинка - Hrum 3.5i - самый быстрый LZ-распаковщик с битовым потоком.

                Hrum 3.5i
 

   Для  распаковщика Hrum автором заявлена
особенно высокая скорость: 33 k/с. К сожа- 
лению,я не обладаю информацией,какие имен- 
но типы данных имелись в виду,но в общем и 
целом  автор  прав - это самый быстрый LZ- 
распаковщик с битовым потоком. За счёт уп- 
рощенного  в связи с этим формата он также 
и чрезвычайно короткий. К несчастью,автор- 
ский  пакет не предлагает распаковщика без 
перекидывания для использования его на не- 
сколько блоков. 

   Перекидывание  -  функциональная  черта
очевидных  предшественников  Hrum  на ниве
сжатия 48k игрушек.Идеология этого процес-
са  такова: кодовый блок ОБЯЗАН находиться
непосредственно за распаковщиком;распаков-
щик при запуске перекидывает свою активную
часть в тихое место (как правило,#5bxx), а
упакованный  блок - в конец выделенной па-
мяти  для распаковки; все адреса для этого
рассчитаны заранее (пакером) и лежат в те-
ле распаковщика.
 

   В Hrum введено три оригинальных ухищре-
 ния: 
  1. 5 байт конца файла (это  важная часть
файла, создаваемая для разрыва между адре- 
сами "откуда" и "куда  распаковывать") ко- 
пируются вместе  с распаковщиком  в "тихое 
 место" одной командой LDIR. 
  2. Предложен  ещё  более короткий способ
реализации стандартного дерева из 16 вари- 
антов, с которым мы ещё встретимся: 
────────────────────────────────────────── 
                LD E,1
        pair    LD A,#80 
        pair0   <getbit> 
                RLA
                JR C,pair0 ;2 прохода
                CP 3       ;A=0..3
                JR C,treeend
                ADD A,E
                LD E,A
                XOR C      ;=#10 !!!
                JR NZ,pair
        treeend ADD A,E
────────────────────────────────────────── 
   Хитрость  в команде XOR C. Т.е. получи-
лось короче,чем в PCD6.2 (там было SUB 15) 
и тем более чем в MS Pack (там не было ци- 
кла  и был лишний XOR A ). Kонстанта C=#10 
используется и в другом месте: при обрабо- 
 тке битового потока. 
  3. Один  и  тот  же  цикл взятия 3-4 бит
(ближе  к концу  распаковщика)  используе- 
тся как для взятия dispH (при putsЄ4 ),так 
и для взятия dispL (при puts=1 ),причём за 
всю работу этого цикла ни разу не портится 
флаг Z! В этом  флаге и лежит признак, что 
делать с результатом... 

   Словарь (окно) всего 4k.
   Имеется два чередующихся потока данных:
битовый и байтовый. Битовый поток хранится
кусками  по 16 бит и снимается в регистро-
вую  пару  HL. Пока  HL сдвигается, 16 бит
отсчитываются  в регистре B командой DJNZ.
Когда они кончаются, из потока берётся но-
вое значение HL.
 

   Упакованный блок с распаковщиком содер-
жит: 
Инициализацию распаковщика. 
Активную часть распаковщика. 
5 байт конца файла. 
2 байта начала битового потока. 
 1 байт - первый байт файла. 
   И далее согласно битовому потоку:
%1 - вставить байт из байтового потока. 
 %000,-disp3 - копировать  1 байт  с адреса 
 минус 1..8.
 %001 - копировать  2 байта: -disp8 берется 
 из байтового потока.
%010 - копировать 3 байта аналогично. 
 %01100 - копировать  N байт ( N берётся из 
  битового потока, N=0 - конец файла).Здесь
  и далее  после определения длины произво-
  дидся гадание по биту из битового потока:
  %0 - -dispL берётся  из байтового потока;
  %1 - аналогично, но перед  этим  -dispH в
  количестве  4 бит берётся из битового по-
  тока. Обратите внимание,избыточность фор-
  мата: -dispH=#FF кодируется двояко, автор
  сэкономил  1 байт распаковщика. Непонятен
  также юмор автора с командой RES 5,A, ко-
 торая могла бы выглядеть как LD A,#1f.
%01101 - копировать 4 байта как выше. 
%01110 - копировать 5. 
%0111100 - копировать 6. 
%0111101 - копировать 7. 
%0111110 - копировать 8. 
%011111100 - копировать 9. 
%011111101 - копировать 10. 
%011111110 - копировать 11. 
%01111111100 - копировать 12. 
%01111111101 - копировать 13. 
%01111111110 - копировать 14. 
%01111111111 - копировать 15. 

                Hrust 1.x
 

   Распаковщик  Hrust 1.x  -  самый хитрый
распаковщик  на  ZX. Несмотря на небольшой 
размер, он вполне способен запутать любого 
заглянувшего. 

   Уникальность формата в том,что он прямо
предназначен для сжатия кодов.Для этого он
снабжён кодами копирования с разрывом, ка-
ких больше нигде нет. Дополнительно приме-
нены расширяющиеся коды смещений,которые в
начале  файла короткие и указывают недале-
ко, а ближе к концу - длинные.
   В авторском  комплекте имеется два рас-
паковщика - с входным потоком в стеке  и с
входным потоком в IX. Еще один распаковщик
в виде бейсик-загрузчика сделал из первого
Alone Coder. Все они эквивалентны. 
   Распаковщик  начинается   с  переброски
упакованного блока в конец памяти,выделен-
ной для распаковки. Переброска идёт только
в случае, если  адрес  конца  упакованного
блока изначально меньше адреса конца памя-
ти  для  распаковки. Бейсик-вариант  этого
фрагмента не содержит,там нужно самому ко-
нтролировать,чтобы упакованный блок в про-
цессе распаковки не портился.Тем не менее,
есть шанс, что он запорется  и в авторских
распаковщиках, после переброски. Для этого
конец блока должен плохо паковаться.

   Битовый  поток  берётся  кусками  по 16
бит. C  содержит  константу 16. D содержит
один сброшенный бит,положение которого от-
носительно  левого  края  байта определяет
длину расширяемых ссылок. Изначально D=#bf
(назовём это состояние "2 бита расширяемой
ссылки"),далее периодическо происходит RRC
D ("3..8 бит расширяемой ссылки"). 

   Упакованные блоки имеют заголовок:

+0 "HR". 
+2 распакованная длина. 
+4 упакованная длина. 
+6 шесть последних байт блока. 
+12 два байта начала битового потока. 
+13 первый байт блока. 
+14 сами упакованные данные. 

   Обработка  упакованных данных осуществ-
ляется согласно указаниям битового потока:

 %1 - получить  байт  из байтового потока и 
 поместить куда распаковываем.
 %000,-disp3 - копировать  1 байт со смеще- 
 ния -1..8
 %001 - копировать C=2 байта. disp кодируе- 
  тся так:
  %00Ў%01: -dispH=#fdЎ#fe, -dispL в битовом
   потоке;
  %10: -dispH=#ff, далее исходя из байтово-
   го  потока: числа  <#e0  понимаются  как
  -dispL  (ссылка  обычная),  Є#e0  хитро:
   RLCA:XOR C, при  A=-1  расширяется длина
   ссылки, иначе  SUB 15 и получаем -dispL=
   =#b2Ў#ee (ссылка со вставным байтом:байт
   из $-disp, байт из байтового потока,байт
   из $+2-disp );
  %11,-disp5: обычная ссылка (через %10 та-
  кие короткие disp описать нельзя);
 %010 - копировать C=3 байта. Здесь и далее 
  disp кодируется так:
  %00: -dispH=#fe, -dispL в битовом потоке;
  %01: -dispH=#ff, далее исходя из байтово-
   го  потока: числа  <#e0  понимаются  как
  -dispL  (ссылка  обычная),  Є#e0  хитро:
   RLCA:XOR C, при  A=-1  расширяется длина
   ссылки  (на самом деле не используется),
   иначе  SUB 15  и получаем -dispL=#b1Ў#ef
   (со вставным байтом:байт из $-disp, байт
   из байтового потока, байт из $+2-disp );
  %10,-disp5;
  %11: расширяющаяся ссылка. -dispH берётся
   из битового потока, число битов согласно
   D  (#bf..#fe  соответствует  2..8  бит).
   -dispL  берётся  из  байтового потока. В
  остальном ссылка как ссылка.
 %01100 - копировать  C=4  байта  как выше. 
  Здесь и далее коды ссылок со вставным ба-
 йтом невыгодны, но есть.
%01110 - копировать 5. 
%0111100 - копировать 6. 
%0111101 - копировать 7. 
%0111110 - копировать 8. 
%011111100 - копировать 9. 
%011111101 - копировать 10. 
%011111110 - копировать 11. 
%01111111100 - копировать 12. 
%01111111101 - копировать 13. 
%01111111110 - копировать 14. 
%01111111111 - копировать 15. 
   И особенные случаи:
%01101000001111 - конец файла. 
 %0110100,len7 - если len7>15, то len будет 
  равно  len7*256+байт_из_байтового_потока.
  В  любом  случае  результат ляжет в BC, а
 далее см. случаи с len=3..15.
 %0110101xxxx - 12Ў42 (чётное число) байтов 
 из байтового потока.
 %011011,-disp4: ссылка со вставным байтом: 
  байт из $-disp, байт из байтового потока,
  байт из $+2-disp. Сделано из-за того, что
  в %001 предусмотрены  только -dispL=#b2..
  #ee, причем чётные, а в %010 только #b1..
 #ef, нечётные.

                Hrust 2.x
 

   Формат  предназначался для сжатия текс-
тов.Несмотря на то,что авторский упаковщик 
был неудобный,а формат (1998) с появлением 
RIP (2000)  и ZXRar (2003) устарел, он всё 
же стал единственным действительно СТАНДА- 
РТНЫМ форматом упакованных данных на ZX. И 
 не только для текстов. 
   Одних  упаковщиков Hrust 2.x сейчас из-
вестно девять (!), все они выросли из кода 
оригинального  упаковщика.  Количество  же 
программ,поддерживающих формат на распако- 
 вку, я не определил. 
   Идеология принята противоположная Hrum:
выгрузка упакованных блоков ТОЛЬКО без ра- 
спаковщика, распаковщик отдельный,не испо- 
льзует  стек. Может  быть, из-за сочетания 
этих идей формат победил остальные? 

   На практике имеется две версии заголов-
ков упакованных блоков: v2.1 и v2.3. Стан-
дартом является первая.Вторая используется
только в архивах Hrip.

                  v2.1:
 смещение  длина 
   +0       3     "hr2";
  +3       1     "1". Если bit7=1, то файл
                 был просто "сохранен";
                  (а значит - w[+4]=w[+6])
   +4       2     длина исходного файла;
   +6       2     длина упакованного файла;
  +8     w[+6]   упакованный файл.

   Перед  упакованным блоком хранятся пос-
ледние 6 байт файла,сами эти 6 байт не па-
куются.
   Максимальная длина повторяющегося фраг-
мента,кодируемого одной ссылкой: 4095 байт
(#fff). Максимальная  ссылка назад: -65535 
байт (окно  в авторском  упаковщике: 16384
байт, в других  известных упаковщиках дос-
тигает 32768, но уменьшается при приближе-
нии  упакованного  куска к непакованному -
упаковка идет в тот же буфер)

 011000nnnn - несколько  непакованных байт, 
  а точнее, 12+nnnn*2 (не более 42, как ви-
 дно), в байтовом потоке - эти байты.
 1 - просто  один непакованный байт (в бай- 
 товом потоке - этот байт).
000xxx - 1 повтор (xxx=disp3). 
001 - 2 повтора (в байтовом потоке disp8). 
010... - 3 повтора. 
01101... - 4 повтора. 
01110... - 5 повторов. 
0111100... - 6 повторов. 
0111101... - 7 повторов. 
   и т.д.
01111111110... - 14 повторов. 
01111111111... - 15 повторов. 
 011001... - от 16 до 255  повторов (в бай- 
 товом потоке - число этих повторов).
 011001... - от 256 до 4097 повторов (в ба- 
  йтовом потоке: сначала старший байт,потом
  младший байт числа повторов. Очевидно,что
  старший байт всегда меньше 16, что позво-
  ляет  отличить последовательность от пре-
 дыдущего случая).
 011001 - это также конец файла,если байт в 
  байтовом  потоке  равен нулю. Из этого, в
  частности,следует,что последний байт упа-
 кованного блока всегда равен нулю.

   Выше под многоточием понималось следую-
щее указание disp'а (отрицательного):

1 - disp8 (#ff00-ffff) в байтовом потоке. 
 011x - disp9 (#fd00-feff), где x - старший 
  разряд (0 соответствует #fd), остальные 8
 - в байтовом потоке.
 010xx - disp10 (#f900-fcff), где xx - ста- 
  ршие  разряды (00 соответствует #f9), ос-
 тальные 8 - в байтовом потоке.
 001xxx - disp11 (#f100-#f8ff),  где  xxx - 
  старшие  разряды (000 соответствует #f1),
 остальные 8 - в байтовом потоке.
 000xxxx - disp12 (#e200-#f0ff), где xxxx - 
  старшие разряды (0000 соответствует #e2),
 остальные 8 - в байтовом потоке.
 0000000 - disp16, хранится в байтовом по- 
 токе,сначала старший байт,потом младший.

                v2.3/Hrip:

   Файл  разбивается  на  блоки. У каждого
блока свой заголовок.Блоки могут быть раз-
ной длины. Желательно, однако, чтобы длина
блока была кратна #100. Просто упакованный
файл  длиной более #а000 также разбивается
на блоки. Последовательно записанные блоки
образуют упакованный файл,а последователь-
ность упакованных файлов - архив.

              Заголовок блока:
           --------------------
+0(5) - "Hrst2". 
 +5(1) - байт флагов: 
  bit0=1: блок сохранен без сжатия;
  bit1=1: блок в файле был последним;
 bit5=1: файл удален.
+6(2) - длина исходного блока. 
 +8(2) - длина упакованного блока (без дли- 
 ны заголовка).
 +10(1) - длина дополнительной информации: 
                  -----
 +11(2) - CRC16  упакованного  блока (можно 
 быстро проверить сохранность архива);
+13(2) - CRC16 исходного блока; 
 +15(14) - дескриптор файла (как в TR-DOS). 
                  -----
+[+10]+11 (берем байт из [+10], прибавляем 
 11) - упакованный блок.

   Длина дополнительной информации равна:
=0  для просто пакованных файлов; 
=2  +хотим иметь CRC16 упакованного блока; 
=4  +еще и знаем CRC16 исходного блока; 
=18 +знаем имя файла. 

   В  Hrip максимальный размер блока - 16k
без заголовка. Заголовок занимает 29 байт.
В заголовке блока хранится следующая допо-
лнительная информация: CRC пакованного,CRC
исходного, копия заголовка из каталога.
   Параметр  в заголовке файла, отвечающий
за реальную длину блока,должен быть кратен
256. 

             Заголовок архива:
           --------------------
IDARCH  DB "HRi" 
 IDALL   DB 0 ;количество файлов в архиве 
  ;(используется в Hrip'е при дополнении
 ;архива, чтобы не было больше 255 файлов)
SMESH   DB 0 ;см.далее 
LAST    DW 0 ;см.далее 
CAT     DB 0 ;1 - каталог есть в архиве, 
             ;0 - каталог отсутствует.

   Следующая формула показывает, как можно
определить конец архива (в байтах от нача-
ла архива):
 END_ARCH=[LAST]*256-(256-[SMESH]) bytes
   Расположение каталога,если таков прису-
тствует,можно определить по формуле:
        START_CAT=[LAST]*256 bytes

              Формат каталога:
           --------------------
   Заголовок каталога:

IDCAT   DB "Hrip" 
FILES   DB 0 ;файлов в архиве = IDALL 
SECLEN  DB 0 ;длина каталога в секторах. 

   Далее  идет  список  файлов в архиве, в
следующем формате:

IDFILE  DS 11 ;имя файла 
SMSEC   DW 0 ;на сколько секторов от 
             ;начала архива находится файл
SMBYTE  DB 0 ;в каком байте в этом секторе 
LENPACK DB 0 ;длина упак. файла в секторах 
LENREAL DB 0 ;реальная длина файла в сект. 

   Смещение  файла относительно начала ар-
хива вычисляется по следующей формуле:
    SM_FILE=[SMSEC]*256+[SMBYTE] bytes

   Количество файлов задается в переменной
FILES (в заголовке каталога), но этого ма- 
ло,необходимо,чтобы был 0 после последнего
описателя файла.

                       Подготовил А. Кодер




Темы: Игры, Программное обеспечение, Пресса, Аппаратное обеспечение, Сеть, Демосцена, Люди, Программирование

Похожие статьи:
Презентация - Авторские программы: SQUARDS
Экспертиза - подробный разбор второй часть игры "HACKER". Вам предстоит стать участником захватывающей детективной истории.
Authors - авторы газеты.

В этот день...   19 ноября