закодированным методом Хаффмана}

aInStream.Seek(0, soFromBeginning);

aInStream.ReadBuffer(Signature, sizeof(Signature));

if (Signature <> TDHuffHeader) then

raise EtdHuffmanException.Create( FmtLoadStr(tdeHuffBadEncodedStrm,[UnitName, 'TDHuffmanDecompress']));

aInStream.ReadBuffer(Size, sizeof(longint));

{если данные для восстановления отсутствуют, осуществить выход из подпрограммы}

if (Size = 0) then

Exit;

{подготовиться к восстановлению}

HTree := nil;

BitStrm := nil;

try

{создать поток битов}

BitStrm := TtdInputBitStream.Create(aInStream);

BitStrm.Name := 'Huffman compressed stream';

{создать дерево Хаффмана}

HTree := THuffmanTree.Create;

{считать данные дерева из входного потока}

HTree.LoadFromBitStream(BitStrm);

{если корневой узел дерева Хаффмана является листом, исходный поток состоит только из повторений одного символа}

if HTree.RootIsLeaf then

WriteMultipleChars(aOutStream, AnsiChar(HTree.Root), Size) {в противном случае выполнить восстановление символов входного потока посредством использования дерева Хаффмана}

else

DoHuffmanDecompression(BitStrm, aOutStream, HTree, Size);

finally

BitStrm.Free;

HTree.Free;

end;

end;

Прежде всего, мы проверяем, начинается ли поток с корректной сигнатуры. Если нет, не имеет смысла продолжать процесс, поскольку поток явно содержит ошибки.

Затем выполняется считывание длины несжатых данных, и если она равна нулю, задача выполнена. В противном случае необходимо проделать определенную работу. В этом случае мы создаем входной поток битов, содержащий входной поток. Затем мы создаем объект дерева Хаффмана, который будет выполнять большую часть работы, и вынуждаем его выполнить собственное считывание из входного потока битов (вызывая для этого метод LoadFromBitStream). Если дерево Хаффмана представляет единственный символ, исходный поток восстанавливается в виде повторений этого символа. В противном случае мы вызываем подпрограмму DoHuffmanDecoonpression для выполнения восстановления данных. Код этой подпрограммы приведен в листинге 11.13.

Листинг 11.13. Подпрограмма DoHuffmanDecompression

procedure DoHuffmanDecompression( aBitStream : TtdInputBitStream;

aOutStream : TStream; aHTree : THuffmanTree; aSize : longint);

var

CharCount : longint;

Ch : byte;

Buffer : PByteArray;

BufEnd : integer;

begin

GetMem(Buffer, HuffmanBufferSize);

try

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

BufEnd := 0;

CharCount := 0/

{повторять процесс до тех пор, пока не будут восстановлены все символы}

while (CharCount < aSize) do

begin

{считать следующий байт}

Ch := aHTree.DecodeNextByte (aBitStream);

Buffer^[BufEnd] :=Ch;

inc(BufEnd);

inc(CharCount);

{если буфер заполнен, необходимо выполнить его запись}

if (BufEnd = HuffmanBufferSize) then begin

aOutStream.WriteBuffer(Buffer^, HuffmanBufferSize);

BufEnd := 0;

end;

end;

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

if (BufEnd <> 0) then

aOutStream.WriteBuffer(Buffer^, BufEnd);

finally

FreeMem(Buffer, HuffmanBufferSize);

end;

end;

По существу подпрограмма представляет собой цикл, внутри которого многократно выполняется декодирование байтов и заполнение буфера. Когда буфер заполняется, мы записываем его в выходной поток и начинаем заполнять его снова. Декодирование выполняется при помощи метода DecodeNextByte класса THuffmanTree.

Листинг 11.14. Метод DecodeNextByte

function THuffmanTree.DecodeNextByte(aBitStream : TtdInputBitStream): byte;

var

NodeInx : integer;

begin

NodeInx := FRoot;

while (NodeInx >= 256) do

begin

if not aBitStream.ReadBit then

NodeInx := FTree[NodeInx].hnLeftInx else

NodeInx := FTree[NodeInx].hnRightInx;

end;

Result := NodeInx;

Добавить отзыв
ВСЕ ОТЗЫВЫ О КНИГЕ В ИЗБРАННОЕ

0

Вы можете отметить интересные вам фрагменты текста, которые будут доступны по уникальной ссылке в адресной строке браузера.

Отметить Добавить цитату