РефератыИнформатика, программированиеDeDelphi. Немного относительно методов упаковки данных

Delphi. Немного относительно методов упаковки данных

Running - Это самый простой из методов упаковки информации . Предположите что Вы имеете строку текста, и в конце строки стоит 40 пробелов. Налицо явная избыточность имеющейся информации. Проблема сжатия этой строки решается очень просто - эти 40 пробелов ( 40 байт ) сжимаются в 3 байта с помощью упаковки их по методу повторяющихся символов (running). Первый байт, стоящий вместо 40 пробелов в сжатой строке, фактически будет явлться пробелом ( последовательность была из пробелов ) . Второй байт - специальный байт "флажка" который указывает что мы должны развернуть предыдущий в строке байт в последовательность при восстановлении строки . Третий байт - байт счета ( в нашем случае это будет 40 ). Как Вы сами можете видеть, достаточно чтобы любой раз, когда мы имеем последовательность из более 3-х одинаковых символов, заменять их выше описанной последовательностью , чтобы на выходе получить блок информации меньший по размеру, но допускающий восстановление информации в исходном виде.


Оставляя все сказанное выше истинным , добавлю лишь то, что в данном методе основной проблемой является выбор того самого байта "флажка", так как в реальных блоках информации как правило используются все 256 вариантов байта и нет возможности иметь 257 вариант - "флажок". На первый взгляд эта проблема кажется неразрешимой , но к ней есть ключик , который Вы найдете прочитав о кодировании с помощью алгоритма Хаффмана ( Huffman ).


LZW - История этого алгоритма начинается с опубликования в мае 1977 г. Дж. Зивом ( J. Ziv ) и А. Лемпелем ( A. Lempel ) статьи в журнале "Информационные теории " под названием " IEEE Trans ". В последствии этот алгоритм был доработан Терри А. Велчем ( Terry A. Welch ) и в окончательном варианте отражен в статье " IEEE Compute " в июне 1984 . В этой статье описывались подробности алгоритма и некоторые общие проблемы с которыми можно


столкнуться при его реализации. Позже этот алгоритм получил название - LZW (Lempel - Ziv - Welch) .


Алгоритм LZW представляет собой алгоритм кодирования последовательностей неодинаковых символов. Возьмем для примера строку " Объект TSortedCollection порожден от TCollection.". Анализируя эту строку мы можем видеть, что слово "Collection" повторяется дважды. В этом слове 10 символов - 80 бит. И если мы сможем заменить это слово в выходном файле, во втором его включении, на ссылку на первое включение, то получим сжатие информации. Если рассматривать входной блок информации размером не более 64К и ограничится длинной кодируемой строки в 256 символов, то учитывая байт "флаг" получим, что строка из 80 бит заменяется 8+16+8 = 32 бита. Алгоритм LZW как-бы "обучается" в процессе сжатия файла. Если существуют повторяющиеся строки в файле , то они будут закодированны в таблицу. Очевидным преимуществом алгоритма является то, что нет необходимости включать таблицу кодировки в сжатый файл. Другой важной особенностью является то, что сжатие по алгоритму LZW является однопроходной операцией в противоположность алгоритму Хаффмана ( Huffman ) , которому требуется два прохода.


Huffman - Сначала кажется что создание файла меньших размеров из исходного без кодировки последовательностей или исключения повтора байтов будет невозможной задачей. Но давайте мы заставим себя сделать несколько умственных усилий и понять алгоритм Хаффмана ( Huffman ). Потеряв не так много времени мы приобретем знания и дополнительное место на дисках.


Сжимая файл по алгоритму Хаффмана первое что мы должны сделать - это необходимо прочитать файл полностью и подсчитать сколько раз встречается каждый символ из расширенного набора ASCII. Если мы будем учитывать все 256 символов, то для нас не будет разницы в сжатии текстового и EXE файла.


После подсчета частоты вхождения каждого символа, необходимо просмотреть таблицу кодов ASCII и сформировать мнимую компоновку между кодами по убыванию. То есть не меняя местонахождение каждого символа из таблицы в памяти отсортировать таблицу ссылок на них по убыванию. Каждую ссылку из последней таблицы назовем "узлом". В дальнейшем ( в дереве ) мы будем позже размещать указатели которые будут указывает на этот "узел". Для ясности давайте рассмотрим пример:


Мы имеем файл длинной в 100 байт и имеющий 6 различных символов в


себе . Мы подсчитали вхождение каждого из символов в файл и получили


следующее :


+-----------------+-----+-----+-----+-----+-----+-----+


| cимвол | A | B | C | D | E | F |


+-----------------+-----+-----+-----+-----+-----+-----|


| число вхождений | 10 | 20 | 30 | 5 | 25 | 10 |


+-----------------+-----+-----+-----+-----+-----+-----+


Теперь мы берем эти числа и будем называть их частотой вхождения для каждого символа. Разместим таблицу как ниже.


+-----------------+-----+-----+-----+-----+-----+-----+


| cимвол | C | E | B | F | A | D |


+-----------------+-----+-----+-----+-----+-----+-----|


| число вхождений | 30 | 25 | 20 | 10 | 10 | 5 |


+-----------------+-----+-----+-----+-----+-----+-----+


Мы возьмем из последней таблицы символы с наименьшей частотой. В нашем случае это D (5) и какой либо символ из F или A (10), можно взять любой из них например A. Сформируем из "узлов" D и A новый "узел", частота вхождения для которого будет равна сумме частот D и A :


Частота 30 10 5 10 20 25


Символа C A D F B E


| |


+--+--+


++-+


|15| = 5 + 10


+--+


Номер в рамке - сумма частот символов D и A. Теперь мы снова ищем два символа с самыми низкими частотами вхождения. Исключая из просмотра D и A и рассматривая вместо них новый "узел" с суммарной частотой вхождения. Самая низкая частота теперь у F и нового "узла". Снова сделаем операцию слияния узлов :


Частота 30 10 5 10 20 25


Символа C A D F B E


| | |


| | |


| +--+| |


+-|15++ |


++-+ |


| |


| +--+ |


+----|25+-+ = 10 + 15


+--+


Рассматриваем таблицу снова для следующих двух символов ( B и E ). Мы продолжаем в этот режим пока все "дерево" не сформировано, т.е. пока все не сведется к одному узлу.


Частота 30 10 5 10 20 25


Символа C A D F B E


| | | | | |


| | | | | |


| | +--+| | | |


| +-|15++ | | |


| ++-+ | | |


| | | | |


| | +--+ | | +--+ |


| +----|25+-+ +-|45+-+


| ++-+ ++-+


| +--+ | |


+----|55+------+ |


+-++ |


| +------------+ |


+---| Root (100) +----+


+------------+


Теперь когда наше дерево создано, мы можем кодировать файл . Мы должны всегда начинать из корня ( Root ) . Кодируя первый символ (лист дерева С) Мы прослеживаем вверх по дереву все повороты ветвей и если мы делаем левый поворот, то запоминаем 0-й бит, и аналогично 1-й бит для правого поворота. Так для C, мы будем идти влево к 55 ( и запомним 0 ), затем снова влево (0) к самому символу . Код Хаффмана для нашего символа C - 00. Для следующего символа ( А ) у нас получается - лево,право,лево,лево , что выливается в последовательность 0100. Выполнив выше сказанное для всех символов получим


C = 00 ( 2 бита )


A = 0100 ( 4 бита )


D = 0101 ( 4 бита )


F = 011 ( 3 бита )


B = 10 ( 2 бита )


E = 11 ( 2 бита )


Каждый символ изначально представлялся 8-ю битами ( один байт ), и так как мы уменьшили число битов необходимых для представления каждого символа, мы следовательно уменьшили размер выходного файла . Сжатие складывется следующим образом :


+----------+----------------+-------------------+--------------+


| Частота | первоначально | уплотненные биты | уменьшено на |


+----------+----------------+-------------------+--------------|


| C 30 | 30 x 8 = 240 | 30 x 2 = 60 | 180 |


| A 10 | 10 x 8 = 80 | 10 x 3 = 30 | 50 |


| D 5 | 5 x 8 = 40 | 5 x 4 = 20 | 20 |


| F 10 | 10 x 8 = 80 | 10 x 4 = 40 | 40 |


| B 20 | 20 x 8 = 160 | 20 x 2 = 40 | 120 |


| E 25 | 25 x 8 = 200 | 25 x 2 = 50 | 150 |


+----------+----------------+-------------------+--------------+


Первоначальный размер файла : 100 байт - 800 бит;


Размер сжатого файла : 30 байт - 240 бит;


240 - 30% из 800 , так что мы сжали этот файл на 70%.


Все это довольно хорошо, но неприятность находится в том факте, что для восстановления первоначального файла, мы должны иметь декодирующее дерево, так как деревья будут различны для разных файлов . Следовательно мы должны сохранять дерево вместе с файлом . Это превращается в итоге в увеличение размеров выходного файла .


В нашей методике сжатия и каждом узле находятся 4 байта указателя, по этому, полная таблица для 256 байт будет приблизительно 1 Кбайт длинной. Таблица в нашем примере имеет 5 узлов плюс 6 вершин ( где и находятся наши символы ) , всего 11 . 4 байта 11 раз - 44 . Если мы добавим после небольшое количество байтов для сохранения места узла и некоторую другую статистику - наша таблица будет приблизительно 50 байтов длинны. Добавив к 30 байтам сжатой информации, 50 байтов таблицы получаем, что общая длинна архивного файла вырастет до 80 байт . Учитывая , что первоначальная длинна файла в рассматриваемом примере была 100 байт - мы получили 20% сжатие информации. Не плохо . То что мы действительно выполнили - трансляция символьного ASCII набора в наш новый набор требующий меньшее количество знаков по сравнению с стандартным.


Что мы можем получить на этом пути ?


Рассмотрим максимум которй мы можем получить для различных разрядных комбинацй в оптимальном дереве, которое является несимметричным.


Мы получим что можно иметь только :


4 - 2 разрядных кода;


8 - 3 разрядных кодов;


16 - 4 разрядных кодов;


32 - 5 разрядных кодов;


64 - 6 разрядных кодов;


128 - 7 разрядных кодов;


Необходимо еще два 8 разрядных кода.


4 - 2 разрядных кода;


8 - 3 разрядных кодов;


16 - 4 разрядных кодов;


32 - 5 разрядных кодов;


64 - 6 разрядных кодов;


128 - 7 разрядных кодов;


--------


254


Итак мы имеем итог из 256 различных комбинаций которыми можно кодировать байт. Из этих комбинаций лишь 2 по длинне равны 8 битам. Если мы сложим число битов которые это представляет, то в итоге получим 1554 бит или 195 байтов. Так в максимуме , мы сжали 256 байт к 195 или 33%, таким образом максимально идеализированный Huffman может достигать сжатия в 33% когда используется на уровне байта Все эти подсчеты производились для не префиксных кодов Хаффмана т.е. кодов, которые нельзя идентифицировать однозначно. Например код A - 01011 и код B - 0101 . Если мы будем получать эти коды побитно, то получив биты 0101 мы не сможем сказать какой код мы получили A или B , так как следующий бит может быть как началом следующего кода, так и продолжением предыдущего.


Необходимо добавить, что ключем к построению префиксных кодов служит обычное бинарное дерево и если внимательно рассмотреть предыдущий пример с построением дерева , можно убедится , что все получаемые коды там префиксные.


Одно последнее примечание - алгоритм Хаффмана требует читать входной файл дважды, один раз считая частоты вхождения символов , другой разпроизводя непосредственно кодирование.


P.S. О "ключике" дающем дорогу алгоритму Running.


---- Прочитав обзорную информацию о Huffman кодировании подумайтенад тем, что на нашем бинарном дереве может быть и 257 листиков.


Список литературы


1) Описание архиватора Narc фирмы Infinity Design Concepts, Inc.;


2) Чарльз Сейтер, 'Сжатие данных', "Мир ПК", N2 1991;


Приложение


{$A+,B-,D+,E+,F-,G-,I-,L+,N-,O-,R+,S+,V+,X-}


{$M 16384,0,655360}


{******************************************************}


{* Алгоритм уплотнения данных по методу *}


{* Хафмана. *}


{******************************************************}


Program Hafman;


Uses Crt,Dos,Printer;


Type PCodElement = ^CodElement;


CodElement = record


NewLeft,NewRight,


P0, P1 : PCodElement; {элемент входящий одновременно}


LengthBiteChain : byte; { в массив , очередь и дерево }


BiteChain : word;


CounterEnter : word;


Key : boolean;


Index : byte;


end;


TCodeTable = array [0..255] of PCodElement;


Var CurPoint,HelpPoint,


LeftRange,RightRange : PCodElement;


CodeTable : TCodeTable;


Root : PCodElement;


InputF, OutputF, InterF : file;


TimeUnPakFile : longint;


AttrUnPakFile : word;


NumRead, NumWritten: Word;


InBuf : array[0..10239] of byte;


OutBuf : array[0..10239] of byte;


BiteChain : word;


CRC,


CounterBite : byte;


OutCounter : word;


InCounter : word;


OutWord : word;


St : string;


LengthOutFile, LengthArcFile : longint;


Create : boolean;


NormalWork : boolean;


ErrorByte : byte;


DeleteFile : boolean;


{-------------------------------------------------}


procedure ErrorMessage;


{ --- выводсообщенияобошибке --- }


begin


If ErrorByte <> 0 then


begin


Case ErrorByte of


2 : Writeln('File not found ...');


3 : Writeln('Path not found ...');


5 : Writeln('Access denied ...');


6 : Writeln('Invalid handle ...');


8 : Writeln('Not enough memory ...');


10 : Writeln('Invalid environment ...');


11 : Writeln('Invalid format ...');


18 : Writeln('No more files ...');


else Writeln('Error #',ErrorByte,' ...');


end;


NormalWork:=False;


ErrorByte:=0;


end;


end;


procedure ResetFile;


{ --- открытиефайладляархивации --- }


Var St : string;


begin


Assign(InputF, ParamStr(3));


Reset(InputF, 1);


ErrorByte:=IOResult;


ErrorMessage;


If NormalWork then Writeln('Pak file : ',ParamStr(3),'...');


end;


procedureResetArchiv;


{ --- открытие файла архива, или его создание --- }


begin


St:=ParamStr(2);


If Pos('.',St)<>0 then Delete(St,Pos('.',St),4);


St:=St+'.vsg';


Assign(OutputF, St);


Reset(OutPutF,1);


Create:=False;


If IOResult=2 then


begin


Rewrite(OutputF, 1);


Create:=True;


end;


If NormalWork then


If Create then Writeln('Create archiv : ',St,'...')


else Writeln('Open archiv : ',St,'...')


end;


procedure SearchNameInArchiv;


{ --- вдальнейшем - поиски

менифайлавархиве --- }


begin


Seek(OutputF,FileSize(OutputF));


ErrorByte:=IOResult;


ErrorMessage;


end;


procedure DisposeCodeTable;


{ --- уничтожение кодовой таблицы и очереди --- }


Var I : byte;


begin


For I:=0 to 255 do Dispose(CodeTable[I]);


end;


procedure ClosePakFile;


{ --- закрытиеархивируемогофайла --- }


Var I : byte;


begin


If DeleteFile then Erase(InputF);


Close(InputF);


end;


procedure CloseArchiv;


{ --- закрытиеархивногофайла --- }


begin


If FileSize(OutputF)=0 then Erase(OutputF);


Close(OutputF);


end;


procedure InitCodeTable;


{ --- инициализация таблицы кодировки --- }


VarI : byte;


begin


For I:=0 to 255 do


begin


New(CurPoint);


CodeTable[I]:=CurPoint;


With CodeTable[I]^ do


begin


P0:=Nil;


P1:=Nil;


LengthBiteChain:=0;


BiteChain:=0;


CounterEnter:=1;


Key:=True;


Index:=I;


end;


end;


For I:=0 to 255 do


begin


If I>0 then CodeTable[I-1]^.NewRight:=CodeTable[I];


If I<255 then CodeTable[I+1]^.NewLeft:=CodeTable[I];


end;


LeftRange:=CodeTable[0];


RightRange:=CodeTable[255];


CodeTable[0]^.NewLeft:=Nil;


CodeTable[255]^.NewRight:=Nil;


end;


procedureSortQueueByte;


{ --- пузырьковая сортировка по возрастанию --- }


Var Pr1,Pr2 : PCodElement;


begin


CurPoint:=LeftRange;


While CurPoint <> RightRange do


begin


If CurPoint^.CounterEnter > CurPoint^.NewRight^.CounterEnter then


begin


HelpPoint:=CurPoint^.NewRight;


HelpPoint^.NewLeft:=CurPoint^.NewLeft;


CurPoint^.NewLeft:=HelpPoint;


If HelpPoint^.NewRight<>Nil then HelpPoint^.NewRight^.NewLeft:=CurPoint;


CurPoint^.NewRight:=HelpPoint^.NewRight;


HelpPoint^.NewRight:=CurPoint;


If HelpPoint^.NewLeft<>Nil then HelpPoint^.NewLeft^.NewRight:=HelpPoint;


If CurPoint=LeftRange then LeftRange:=HelpPoint;


If HelpPoint=RightRange then RightRange:=CurPoint;


CurPoint:=CurPoint^.NewLeft;


If CurPoint = LeftRange then CurPoint:=CurPoint^.NewRight


else CurPoint:=CurPoint^.NewLeft;


end


else CurPoint:=CurPoint^.NewRight;


end;


end;


procedure CounterNumberEnter;


{ --- подсчетчастотвхожденийбайтоввблоке --- }


Var C : word;


begin


For C:=0 to NumRead-1 do


Inc(CodeTable[(InBuf[C])]^.CounterEnter);


end;


functionSearchOpenCode : boolean;


{ --- поиск в очереди пары открытых по Key минимальных значений --- }


begin


CurPoint:=LeftRange;


HelpPoint:=LeftRange;


HelpPoint:=HelpPoint^.NewRight;


While not CurPoint^.Key do


CurPoint:=CurPoint^.NewRight;


While (not (HelpPoint=RightRange)) and (not HelpPoint^.Key) do


begin


HelpPoint:=HelpPoint^.NewRight;


If (HelpPoint=CurPoint) and (HelpPoint<>RightRange) then


HelpPoint:=HelpPoint^.NewRight;


end;


If HelpPoint=CurPoint then SearchOpenCode:=False else SearchOpenCode:=True;


end;


procedureCreateTree;


{ --- создание дерева частот вхождения --- }


begin


While SearchOpenCode do


begin


New(Root);


With Root^ do


begin


P0:=CurPoint;


P1:=HelpPoint;


LengthBiteChain:=0;


BiteChain:=0;


CounterEnter:=P0^.CounterEnter + P1^.CounterEnter;


Key:=True;


P0^.Key:=False;


P1^.Key:=False;


end;


HelpPoint:=LeftRange;


While (HelpPoint^.CounterEnter < Root^.CounterEnter) and


(HelpPoint<>Nil) do HelpPoint:=HelpPoint^.NewRight;


If HelpPoint=Nil then { добавлениевконец }


begin


Root^.NewLeft:=RightRange;


RightRange^.NewRight:=Root;


Root^.NewRight:=Nil;


RightRange:=Root;


end


else


begin { вставкаперед HelpPoint }


Root^.NewLeft:=HelpPoint^.NewLeft;


HelpPoint^.NewLeft:=Root;


Root^.NewRight:=HelpPoint;


If Root^.NewLeft<>Nil then Root^.NewLeft^.NewRight:=Root;


end;


end;


end;


procedure ViewTree( P : PCodElement );


{ --- просмотр дерева частот и присваивание кодировочных цепей листьям --- }


Var Mask,I : word;


begin


Inc(CounterBite);


If P^.P0<>Nil then ViewTree( P^.P0 );


If P^.P1<>Nil then


begin


Mask:=(1 SHL (16-CounterBite));


BiteChain:=BiteChain OR Mask;


ViewTree( P^.P1 );


Mask:=(1 SHL (16-CounterBite));


BiteChain:=BiteChain XOR Mask;


end;


If (P^.P0=Nil) and (P^.P1=Nil) then


begin


P^.BiteChain:=BiteChain;


P^.LengthBiteChain:=CounterBite-1;


end;


Dec(CounterBite);


end;


procedure CreateCompressCode;


{ --- обнуление переменных и запуск просмотра дерева с вершины --- }


begin


BiteChain:=0;


CounterBite:=0;


Root^.Key:=False;


ViewTree(Root);


end;


procedure DeleteTree;


{ --- удаление дерева --- }


VarP : PCodElement;


begin


CurPoint:=LeftRange;


While CurPoint<>Nil do


begin


If (CurPoint^.P0<>Nil) and (CurPoint^.P1<>Nil) then


begin


If CurPoint^.NewLeft <> Nil then


CurPoint^.NewLeft^.NewRight:=CurPoint^.NewRight;


If CurPoint^.NewRight <> Nil then


CurPoint^.NewRight^.NewLeft:=CurPoint^.NewLeft;


If CurPoint=LeftRange then LeftRange:=CurPoint^.NewRight;


If CurPoint=RightRange then RightRange:=CurPoint^.NewLeft;


P:=CurPoint;


CurPoint:=P^.NewRight;


Dispose(P);


end


else CurPoint:=CurPoint^.NewRight;


end;


end;


procedure SaveBufHeader;


{ --- записьвбуферзаголовкаархива --- }


Type


ByteField = array[0..6] of byte;


Const


Header : ByteField = ( $56, $53, $31, $00, $00, $00, $00 );


begin


If Create then


begin


Move(Header,OutBuf[0],7);


OutCounter:=7;


end


else


begin


Move(Header[3],OutBuf[0],4);


OutCounter:=4;


end;


end;


procedure SaveBufFATInfo;


{ --- запись в буфер всей информации по файлу --- }


Var I : byte;


St : PathStr;


R : SearchRec;


begin


St:=ParamStr(3);


For I:=0 to Length(St)+1 do


begin


OutBuf[OutCounter]:=byte(Ord(St[I]));


Inc(OutCounter);


end;


FindFirst(St,$00,R);


Dec(OutCounter);


Move(R.Time,OutBuf[OutCounter],4);


OutCounter:=OutCounter+4;


OutBuf[OutCounter]:=R.Attr;


Move(R.Size,OutBuf[OutCounter+1],4);


OutCounter:=OutCounter+5;


end;


procedure SaveBufCodeArray;


{ --- сохранить массив частот вхождений в архивном файле --- }


Var I : byte;


begin


For I:=0 to 255 do


begin


OutBuf[OutCounter]:=Hi(CodeTable[I]^.CounterEnter);


Inc(OutCounter);


OutBuf[OutCounter]:=Lo(CodeTable[I]^.CounterEnter);


Inc(OutCounter);


end;


end;


procedure CreateCodeArchiv;


{ --- создание кода сжатия --- }


begin


InitCodeTable; { инициализация кодовой таблицы }


CounterNumberEnter; { подсчет числа вхождений байт в блок }


SortQueueByte; { cортировка по возрастанию числа вхождений }


SaveBufHeader; { сохранить заголовок архива в буфере }


SaveBufFATInfo; { сохраняется FAT информация по файлу }


SaveBufCodeArray; { сохранить массив частот вхождений в архивном файле }


CreateTree; { создание дерева частот }


CreateCompressCode; { cоздание кода сжатия }


DeleteTree; { удаление дерева частот }


end;


procedurePakOneByte;


{ --- сжатие и пересылка в выходной буфер одного байта --- }


Var Mask : word;


Tail : boolean;


begin


CRC:=CRC XOR InBuf[InCounter];


Mask:=CodeTable[InBuf[InCounter]]^.BiteChain SHR CounterBite;


OutWord:=OutWord OR Mask;


CounterBite:=CounterBite+CodeTable[InBuf[InCounter]]^.LengthBiteChain;


If CounterBite>15 then Tail:=True else Tail:=False;


While CounterBite>7 do


begin


OutBuf[OutCounter]:=Hi(OutWord);


Inc(OutCounter);


If OutCounter=(SizeOf(OutBuf)-4) then


begin


BlockWrite(OutputF,OutBuf,OutCounter,NumWritten);


OutCounter:=0;


end;


CounterBite:=CounterBite-8;


If CounterBite<>0 then OutWord:=OutWord SHL 8 else OutWord:=0;


end;


If Tail then


begin


Mask:=CodeTable[InBuf[InCounter]]^.BiteChain SHL


(CodeTable[InBuf[InCounter]]^.LengthBiteChain-CounterBite);


OutWord:=OutWord OR Mask;


end;


Inc(InCounter);


If (InCounter=(SizeOf(InBuf))) or (InCounter=NumRead) then


begin


InCounter:=0;


BlockRead(InputF,InBuf,SizeOf(InBuf),NumRead);


end;


end;


procedure PakFile;


{ --- процедуранепосредственногосжатияфайла --- }


begin


ResetFile;


SearchNameInArchiv;


If NormalWork then


begin


BlockRead(InputF,InBuf,SizeOf(InBuf),NumRead);


OutWord:=0;


CounterBite:=0;


OutCounter:=0;


InCounter:=0;


CRC:=0;


CreateCodeArchiv;


While (NumRead<>0) do PakOneByte;


OutBuf[OutCounter]:=Hi(OutWord);


Inc(OutCounter);


OutBuf[OutCounter]:=CRC;


Inc(OutCounter);


BlockWrite(OutputF,OutBuf,OutCounter,NumWritten);


DisposeCodeTable;


ClosePakFile;


end;


end;


procedure ResetUnPakFiles;


{ --- открытие файла для распаковки --- }


begin


InCounter:=7;


St:='';


repeat


St[InCounter-7]:=Chr(InBuf[InCounter]);


Inc(InCounter);


until InCounter=InBuf[7]+8;


Assign(InterF,St);


Rewrite(InterF,1);


ErrorByte:=IOResult;


ErrorMessage;


If NormalWork then


begin


WriteLn('UnPak file : ',St,'...');


Move(InBuf[InCounter],TimeUnPakFile,4);


InCounter:=InCounter+4;


AttrUnPakFile:=InBuf[InCounter];


Inc(InCounter);


Move(InBuf[InCounter],LengthArcFile,4);


InCounter:=InCounter+4;


end;


end;


procedure CloseUnPakFile;


{ --- закрытиефайладляраспаковки --- }


begin


If not NormalWork then Erase(InterF)


else


begin


SetFAttr(InterF,AttrUnPakFile);


SetFTime(InterF,TimeUnPakFile);


end;


Close(InterF);


end;


procedure RestoryCodeTable;


{ --- воссозданиекодовойтаблицыпоархивномуфайлу --- }


Var I : byte;


begin


InitCodeTable;


For I:=0 to 255 do


begin


CodeTable[I]^.CounterEnter:=InBuf[InCounter];


CodeTable[I]^.CounterEnter:=CodeTable[I]^.CounterEnter SHL 8;


Inc(InCounter);


CodeTable[I]^.CounterEnter:=CodeTable[I]^.CounterEnter+InBuf[InCounter];


Inc(InCounter);


end;


end;


procedure UnPakByte( P : PCodElement );


{ --- распаковка одного байта --- }


VarMask : word;


begin


If (P^.P0=Nil) and (P^.P1=Nil) then


begin


OutBuf[OutCounter]:=P^.Index;


Inc(OutCounter);


Inc(LengthOutFile);


If OutCounter = (SizeOf(OutBuf)-1) then


begin


BlockWrite(InterF,OutBuf,OutCounter,NumWritten);


OutCounter:=0;


end;


end


else


begin


Inc(CounterBite);


If CounterBite=9 then


begin


Inc(InCounter);


If InCounter = (SizeOf(InBuf)) then


begin


InCounter:=0;


BlockRead(OutputF,InBuf,SizeOf(InBuf),NumRead);


end;


CounterBite:=1;


end;


Mask:=InBuf[InCounter];


Mask:=Mask SHL (CounterBite-1);


Mask:=Mask OR $FF7F; { установкавсехбитовкроместаршего }


If Mask=$FFFF then UnPakByte(P^.P1)


else UnPakByte(P^.P0);


end;


end;


procedure UnPakFile;


{ --- распаковкаодногофайла --- }


begin


BlockRead(OutputF,InBuf,SizeOf(InBuf),NumRead);


ErrorByte:=IOResult;


ErrorMessage;


If NormalWork then ResetUnPakFiles;


If NormalWork then


begin


RestoryCodeTable;


SortQueueByte;


CreateTree; { создание дерева частот }


CreateCompressCode;


CounterBite:=0;


OutCounter:=0;


LengthOutFile:=0;


While LengthOutFile LengthArcFile do


UnPakByte(Root);


BlockWrite(InterF,OutBuf,OutCounter,NumWritten);


DeleteTree;


DisposeCodeTable;


end;


CloseUnPakFile;


end;


{ ------------------------- main text ------------------------- }


begin


DeleteFile:=False;


NormalWork:=True;


ErrorByte:=0;


WriteLn;


WriteLn('ArcHaf version 1.0 (c) Copyright VVS Soft Group, 1992.');


ResetArchiv;


If NormalWork then


begin


St:=ParamStr(1);


Case St[1] of


'a','A' : PakFile;


'm','M' : begin


DeleteFile:=True;


PakFile;


end;


'e','E' : UnPakFile;


else ;


end;


end;


CloseArchiv;


end.

Сохранить в соц. сетях:
Обсуждение:
comments powered by Disqus

Название реферата: Delphi. Немного относительно методов упаковки данных

Слов:3150
Символов:32227
Размер:62.94 Кб.