{ DOS-text Словарь фрагментов для компрессии/декомпрессии Лемпеля-Зива (LZ78) Отдельная реализация основных процедуры кодировки/декодировки, для возможности предоставить их студентам только в компилированном виде. Основные процедуры кодировки/декодировки. 1) function ByteToCodes(:tByte; var ACodes:tLZCodesArray):tCodesCount; - кодирование байта AByte. Возвращает: 1) число кодов 2) коды в массиве ACodes. 1a) function GetLastCodes(var ACodes:tLZCodesArray):tCodesCount; - возврат кода последнего фрагмента. Возвращает: 1) число кодов 2) коды в массиве ACodes. ПРИМЕЧАНИЕ! конец кодируемой последовательности может присутствовать в словаре, тогда возврат ByteToCodes для последнего байта кодируемой последовательности будет 0 и сама последовательность не попадет в кодированную последовательность (конец будет усечен). Для избежания этой ситуации в конце кодирования следует вызвать GetLastCodes, которая возвратит оставшиеся коды. 2) function CodeToBytes(ACode:tIndex; var ABuffer; ABufferSize:tBufferIndex):tSignedBufferIndex; - декодирование фрагмента с обновлением словаря - возвращает значение >=0, если ACode декодирован, значение = числу байт помещенных в ABuffer; иначе возвращает значение <0, значение = размер недостающего пространства в буфере. Если возвращено значение <0, то ACode считается НЕДЕКОДИРОВАННЫМ и небходимо повторно вызвать CodeToBytes(ACode, ...) с новым буфером, достаточного размера. ВНИМАНИЕ! Нельзя одновременно вызывать ByteToCodes и CodeToBytes. } {--------------------------------------------------------------------------- (c) Copyright Aleksandrov O.E., 2000 Molecular Physics department, USTU, Ekaterinsburg, K-2, 620002, RUSSIA phone 75-47-15 E-mail: aleks@dpt.ustu.ru (c) Copyright Александров О.Е., 2000 620002, Екатеринбург, К-2, УГТУ, Кафедра молекулярной физики тел. 75-47-15 E-mail: aleks@dpt.ustu.ru ----------------------------------------------------------------------------} { Win-text ╤ыютрЁ№ ЇЁруьхэЄют фы  ъюьяЁхёёшш/фхъюьяЁхёёшш ╦хьяхы -╟штр (LZ78) ╬Єфхы№эр  ЁхрышчрЎш  юёэютэ√ї яЁюЎхфєЁ ъюфшЁютъш/фхъюфшЁютъш, фы  тючьюцэюёЄш яЁхфюёЄртшЄ№ шї ёЄєфхэЄрь Єюы№ъю т ъюьяшышЁютрээюь тшфх. ╬ёэютэ√х яЁюЎхфєЁ√ ъюфшЁютъш/фхъюфшЁютъш. 1) function ByteToCodes(AByte:tByte; var ACodes:tLZCodesArray):tCodesCount; - ъюфшЁютрэшх срщЄр AByte. ┬ючтЁр∙рхЄ: 1) ўшёыю ъюфют 2) ъюф√ т ьрёёштх ACodes. 1a) function GetLastCodes(var ACodes:tLZCodesArray):tCodesCount; - тючтЁрЄ ъюфр яюёыхфэхую ЇЁруьхэЄр. ┬ючтЁр∙рхЄ: 1) ўшёыю ъюфют 2) ъюф√ т ьрёёштх ACodes. ╧╨╚╠┼╫└═╚┼! ъюэхЎ ъюфшЁєхьющ яюёыхфютрЄхы№эюёЄш ьюцхЄ яЁшёєЄёЄтютрЄ№ т ёыютрЁх, Єюуфр тючтЁрЄ ByteToCodes фы  яюёыхфэхую срщЄр ъюфшЁєхьющ яюёыхфютрЄхы№эюёЄш сєфхЄ 0 ш ёрьр яюёыхфютрЄхы№эюёЄ№ эх яюярфхЄ т ъюфшЁютрээє■ яюёыхфютрЄхы№эюёЄ№ (ъюэхЎ сєфхЄ єёхўхэ). ─ы  шчсхцрэш  ¤Єющ ёшЄєрЎшш т ъюэЎх ъюфшЁютрэш  ёыхфєхЄ т√чтрЄ№ GetLastCodes, ъюЄюЁр  тючтЁрЄшЄ юёЄрт°шхё  ъюф√. 2) function CodeToBytes(ACode:tIndex; var ABuffer; ABufferSize:tBufferIndex):tSignedBufferIndex; - фхъюфшЁютрэшх ЇЁруьхэЄр ё юсэютыхэшхь ёыютрЁ  - тючтЁр∙рхЄ чэрўхэшх >=0, хёыш ACode фхъюфшЁютрэ, чэрўхэшх = ўшёыє срщЄ яюьх∙хээ√ї т ABuffer; шэрўх тючтЁр∙рхЄ чэрўхэшх <0, чэрўхэшх = ЁрчьхЁ эхфюёЄр■∙хую яЁюёЄЁрэёЄтр т сєЇхЁх. ┼ёыш тючтЁр∙хэю чэрўхэшх <0, Єю ACode ёўшЄрхЄё  ═┼─┼╩╬─╚╨╬┬└══█╠ ш эхсїюфшью яютЄюЁэю т√чтрЄ№ CodeToBytes(ACode, ...) ё эют√ь сєЇхЁюь, фюёЄрЄюўэюую ЁрчьхЁр. ┬═╚╠└═╚┼! ═хы№ч  юфэютЁхьхээю т√ч√трЄ№ ByteToCodes ш CodeToBytes. } {--------------------------------------------------------------------------- (c) Copyright Aleksandrov O.E., 2000 Molecular Physics department, USTU, Ekaterinsburg, K-2, 620002, RUSSIA phone 75-47-15 E-mail: aleks@dpt.ustu.ru (c) Copyright └ыхъёрэфЁют ╬.┼., 2000 620002, ┼ърЄхЁшэсєЁу, ╩-2, ╙├╥╙, ╩рЇхфЁр ьюыхъєы Ёэющ Їшчшъш Єхы. 75-47-15 E-mail: aleks@dpt.ustu.ru ----------------------------------------------------------------------------} Unit LZDic1; {$X+} {$IfDef NoChecking} {$R-,S-,Q-} {$EndIf Def NoChecking} INTERFACE USES ComTypes, LZTypes, LZDic0; type { СЛОВАРЬ-объект } { ╤╦╬┬└╨▄-юс·хъЄ } tLZDictionary=object(LZDic0.tLZDictionary) { ╚ёяюы№чєхЄё  фы  яхЁхфрўш ъюфют ByteToCodesEx ш GetLastCodesEx} pbCodes:tLZCodesArray; pbCodesCount:byte; { кодирование фрагмента - возвращает число кодов в массиве ACodes. ВНИМАНИЕ! Нельзя одновременно вызывать ByteToCodes и CodeToBytes } { ъюфшЁютрэшх ЇЁруьхэЄр - тючтЁр∙рхЄ ўшёыю ъюфют т ьрёёштх ACodes. ┬═╚╠└═╚┼! ═хы№ч  юфэютЁхьхээю т√ч√трЄ№ ByteToCodes ш CodeToBytes } function ByteToCodes(AByte:tByte; var ACodes:tLZCodesArray):tCodesCount; { ъюфшЁютрэшх ЇЁруьхэЄр - тючтЁр∙рхЄ ўшёыю ъюфют т ьрёёштх ACodes. ┬═╚╠└═╚┼! ═хы№ч  юфэютЁхьхээю т√ч√трЄ№ ByteToCodes ш CodeToBytes } function ByteToCodesEx(AByte:tByte):tCodesCount; { окончание кодирования - возвращает число кодов в массиве ACodes как если бы текущий фрагмент закончился - для возврата последнего кода в процессе кодирования.} { юъюэўрэшх ъюфшЁютрэш  - тючтЁр∙рхЄ ўшёыю ъюфют т ьрёёштх ACodes ъръ хёыш с√ Єхъє∙шщ ЇЁруьхэЄ чръюэўшыё  - фы  тючтЁрЄр яюёыхфэхую ъюфр т яЁюЎхёёх ъюфшЁютрэш .} function GetLastCodes(var ACodes:tLZCodesArray):tCodesCount; function GetLastCodesEx:tCodesCount; { фхъюфшЁютрэшх ЇЁруьхэЄр ё юсэютыхэшхь ёыютрЁ  - тючтЁр∙рхЄ чэрўхэшх >=0, хёыш ACode фхъюфшЁютрэ, чэрўхэшх = ўшёыє срщЄ яюьх∙хээ√ї т ABuffer; шэрўх тючтЁр∙рхЄ чэрўхэшх <0, чэрўхэшх = ЁрчьхЁ эхфюёЄр■∙хую яЁюёЄЁрэёЄтр т сєЇхЁх. ┼ёыш тючтЁр∙хэю чэрўхэшх <0, Єю ACode ёўшЄрхЄё  ═┼─┼╩╬─╚╨╬┬└══█╠ ш эхсїюфшью яютЄюЁэю т√чтрЄ№ CodeToBytes(ACode, ...) ё эют√ь сєЇхЁюь, фюёЄрЄюўэюую ЁрчьхЁр. ┬═╚╠└═╚┼! ═хы№ч  юфэютЁхьхээю т√ч√трЄ№ ByteToCodes ш CodeToBytes } function CodeToBytes(ACode:tIndex; var ABuffer; ABufferSize:tBufferIndex):tSignedBufferIndex; end; IMPLEMENTATION USES LZMiscFs, LZBase; function tLZDictionary.ByteToCodes(AByte:tByte; var ACodes:tLZCodesArray):tCodesCount; { Упаковка ввода. Методу передают очередной байт b из входных данных. Возвращает количество кодов (от 0 до 5 шт.): 1) Фрагмент найден: 0 - выводить код не надо; в переменой Codes - ничего не изменяется. 2) Фрагмент не найден (длина каждого кода всегда равна максимальной упаковка кодов производится при копировании в буфер): В переменой Codes: 1 - код фрагмента; 2 - код "ОЧИСТИТЬ СЛОВАРЬ" +код байта; 2 - код "НОВЫЙ БАЙТ" +код байта; 3 - код "УВЕЛИЧИТЬ ДЛИНУ КОДА" +число бит увеличения кода +код фрагмента; 3 - код фрагмента +код "ОЧИСТИТЬ СЛОВАРЬ" +код байта; 5 - код "УВЕЛИЧИТЬ ДЛИНУ КОДА" +число бит увеличения кода +код фрагмента +код "ОЧИСТИТЬ СЛОВАРЬ" +код байта; сами коды и их длина передаются в массиве ACodes; } { ╙яръютър ттюфр. ╠хЄюфє яхЁхфр■Є юўхЁхфэющ срщЄ b шч тїюфэ√ї фрээ√ї. ┬ючтЁр∙рхЄ ъюышўхёЄтю ъюфют (юЄ 0 фю 5 °Є.): 1) ╘ЁруьхэЄ эрщфхэ: 0 - т√тюфшЄ№ ъюф эх эрфю; т яхЁхьхэющ Codes - эшўхую эх шчьхэ хЄё . 2) ╘ЁруьхэЄ эх эрщфхэ (фышэр ърцфюую ъюфр тёхуфр Ёртэр ьръёшьры№эющ єяръютър ъюфют яЁюшчтюфшЄё  яЁш ъюяшЁютрэшш т сєЇхЁ): ┬ яхЁхьхэющ Codes: 1 - ъюф ЇЁруьхэЄр; 2 - ъюф "╬╫╚╤╥╚╥▄ ╤╦╬┬└╨▄" +ъюф срщЄр; 2 - ъюф "═╬┬█╔ ┴└╔╥" +ъюф срщЄр; 3 - ъюф "╙┬┼╦╚╫╚╥▄ ─╦╚═╙ ╩╬─└" +ўшёыю сшЄ єтхышўхэш  ъюфр +ъюф ЇЁруьхэЄр; 3 - ъюф ЇЁруьхэЄр +ъюф "╬╫╚╤╥╚╥▄ ╤╦╬┬└╨▄" +ъюф срщЄр; 5 - ъюф "╙┬┼╦╚╫╚╥▄ ─╦╚═╙ ╩╬─└" +ўшёыю сшЄ єтхышўхэш  ъюфр +ъюф ЇЁруьхэЄр +ъюф "╬╫╚╤╥╚╥▄ ╤╦╬┬└╨▄" +ъюф срщЄр; ёрьш ъюф√ ш шї фышэр яхЁхфр■Єё  т ьрёёштх ACodes; } var i:tCodesCount; { индекс кода в ACodes } c:tIndex; { вспомогательная переменная } lCodeSizeIncrement:word; { приращение длины кодированных данных в битах } begin {$IfOpt R+} if not (fEncodeRegime in prDicFlags) or (fDecodeRegime in prDicFlags) then begin RunError(201); end; {$EndIf} Inc(prInitialSizeInBytes); { поиск продолжения фрагмента}{ яюшёъ яЁюфюыцхэш  ЇЁруьхэЄр } c:=LZBase.FindNodeInBinaryTree(AByte, prDic.Successors^[prLastCode], prDic); if c<>cNilIndex then begin { продолжение фрагмента найдено - продолжаем поиск } { яЁюфюыцхэшх ЇЁруьхэЄр эрщфхэю - яЁюфюыцрхь яюшёъ } ByteToCodes:=0; prLastCode:=c; Inc(prFragmentLength); end else begin { продолжение фрагмента НЕнайдено - фрагмент закончился } { яЁюфюыцхэшх ЇЁруьхэЄр ═┼эрщфхэю - ЇЁруьхэЄ чръюэўшыё  } lCodeSizeIncrement:=0; i:=0; { записываем код текущего фрагмента } { чряшё√трхь ъюф Єхъє∙хую ЇЁруьхэЄр } c:=prLastCode; { проверка на добавление нового значения байта к корню } { яЁютхЁър эр фюсртыхэшх эютюую чэрўхэш  срщЄр ъ ъюЁэ■ } if c=cRootIndex then begin { добавление нового значения байта к корневому узлу - этот участок программы вызывается только 1 раз после SetEncodeRegime } { фюсртыхэшх эютюую чэрўхэш  срщЄр ъ ъюЁэхтюьє єчыє - ¤ЄюЄ єўрёЄюъ яЁюуЁрьь√ т√ч√трхЄё  Єюы№ъю 1 Ёрч яюёых SetEncodeRegime } prLastCode:=LZBase.AddNodeToBinaryTree(AByte, cRootIndex, prDic); { prLastCode:=Add(AByte, cRootIndex);} {$IfOpt R+} if prLastCode=cNilIndex then begin RunError(201); end; {$EndIf} { запись нового байта }{ чряшё№ эютюую срщЄр } ACodes.Code[i]:=cCode_ResetDictionary; ACodes.Length[i]:=prCodeLength; Inc(i); ACodes.Code[i]:=AByte; ACodes.Length[i]:=8; Inc(i); Inc(lCodeSizeIncrement,(prCodeLength+8)); Include(prDicFlags,fNewByte); {??? Inc(prFragmentLength);} end else begin { добавление нового байта к НЕкорневому узлу } { фюсртыхэшх эютюую срщЄр ъ ═┼ъюЁэхтюьє єчыє } { запись кода }{ чряшё№ ъюфр } if (fNewByte in prDicFlags) then begin { записывать не надо - предыдущий код "новый байт" } { чряшё√трЄ№ эх эрфю - яЁхф√фє∙шщ ъюф "эют√щ срщЄ" } Exclude(prDicFlags,fNewByte); end else begin { проверка длины кода }{ яЁютхЁър фышэ√ ъюфр } if c>prMaxCode then begin { код превышает текущий максимальный размер кода - увеличить длину кода} { ъюф яЁхт√°рхЄ Єхъє∙шщ ьръёшьры№э√щ ЁрчьхЁ ъюфр - єтхышўшЄ№ фышэє ъюфр} ACodes.Code[i]:=cCode_IncCodeLength; ACodes.Length[i]:=prCodeLength; Inc(i); Inc(lCodeSizeIncrement,(prCodeLength+cCodeLengthIncrementLength)); { приращение длины кода } { яЁшЁр∙хэшх фышэ√ ъюфр } ACodes.Code[i]:=IncrementCodeLength(c); ACodes.Length[i]:=cCodeLengthIncrementLength; Inc(i); end; {$IfOpt R+} if c>prMaxCode then begin RunError(201); end; {$EndIf} { запись собственно кода }{ чряшё№ ёюсёЄтхээю ъюфр } ACodes.Code[i]:=c; ACodes.Length[i]:=prCodeLength; Inc(i); Inc(lCodeSizeIncrement,(prCodeLength)); end; { если длина фрагмента не превосходит максимально допустимой, } { хёыш фышэр ЇЁруьхэЄр эх яЁхтюёїюфшЄ ьръёшьры№эю фюяєёЄшьющ, } if (prFragmentLengthcNilIndex then begin { фрагмент найден - продолжаем поиск }{ ЇЁруьхэЄ эрщфхэ - яЁюфюыцрхь яюшёъ } prLastCode:=c; Inc(prFragmentLength); end else begin { фрагмент не найден - добавляем новый байт в словарь } { ЇЁруьхэЄ эх эрщфхэ - фюсрты хь эют√щ срщЄ т ёыютрЁ№ } { добавление нового значения байта к корневому узлу } { фюсртыхэшх эютюую чэрўхэш  срщЄр ъ ъюЁэхтюьє єчыє } c:=LZBase.AddNodeToBinaryTree(AByte, cRootIndex, prDic); Inc(lCodeSizeIncrement,(prCodeLength+8)); { ! должно быть ПЕРЕД сбросом словаря } { ! фюыцэю с√Є№ ╧┼╨┼─ ёсЁюёюь ёыютрЁ  } ACodes.Length[i]:=prCodeLength; {!!! должно быть ПЕРЕД ResetDictionary } if c=cNilIndex then begin { свободное место в словаре закончилось }{ ётюсюфэюх ьхёЄю т ёыютрЁх чръюэўшыюё№ } ACodes.Code[i]:=cCode_ResetDictionary; ResetDictionary; c:=LZBase.AddNodeToBinaryTree(AByte, cRootIndex, prDic); end else begin ACodes.Code[i]:=cCode_NewByte; end; Inc(i); {$IfOpt R+} if c=cNilIndex then begin RunError(201); end; {$EndIf} prLastCode:=c; { запись нового байта }{ чряшё№ эютюую срщЄр } ACodes.Code[i]:=AByte; ACodes.Length[i]:=8; Inc(i); Include(prDicFlags,fNewByte); {??? Inc(prFragmentLength);} end; end; { запомнить приращение длины данных }{ чряюьэшЄ№ яЁшЁр∙хэшх фышэ√ фрээ√ї } xInc(prCompressedSize,lCodeSizeIncrement); ByteToCodes:=i; end; end; function tLZDictionary.ByteToCodesEx(AByte:tByte):tCodesCount; var i:tCodesCount; { индекс кода в ACodes } c:tIndex; { вспомогательная переменная } lCodeSizeIncrement:word; { приращение длины кодированных данных в битах } lCodes:^tCodeArray; lLength:^tCodeLengthArray; begin {$IfOpt R+} if not (fEncodeRegime in prDicFlags) or (fDecodeRegime in prDicFlags) then begin RunError(201); end; {$EndIf} Inc(prInitialSizeInBytes); { поиск продолжения фрагмента}{ яюшёъ яЁюфюыцхэш  ЇЁруьхэЄр } c:=LZBase.FindNodeInBinaryTree(AByte, prDic.Successors^[prLastCode], prDic); if c<>cNilIndex then begin { продолжение фрагмента найдено - продолжаем поиск } { яЁюфюыцхэшх ЇЁруьхэЄр эрщфхэю - яЁюфюыцрхь яюшёъ } ByteToCodesEx:=0; pbCodesCount:=0; prLastCode:=c; Inc(prFragmentLength); end else begin { продолжение фрагмента НЕнайдено - фрагмент закончился } { яЁюфюыцхэшх ЇЁруьхэЄр ═┼эрщфхэю - ЇЁруьхэЄ чръюэўшыё  } lCodeSizeIncrement:=0; i:=0; lCodes:=@pbCodes.Code; lLength:=@pbCodes.Length; { записываем код текущего фрагмента } { чряшё√трхь ъюф Єхъє∙хую ЇЁруьхэЄр } c:=prLastCode; { проверка на добавление нового значения байта к корню } { яЁютхЁър эр фюсртыхэшх эютюую чэрўхэш  срщЄр ъ ъюЁэ■ } if c=cRootIndex then begin { добавление нового значения байта к корневому узлу - этот участок программы вызывается только 1 раз после SetEncodeRegime } { фюсртыхэшх эютюую чэрўхэш  срщЄр ъ ъюЁэхтюьє єчыє - ¤ЄюЄ єўрёЄюъ яЁюуЁрьь√ т√ч√трхЄё  Єюы№ъю 1 Ёрч яюёых SetEncodeRegime } prLastCode:=LZBase.AddNodeToBinaryTree(AByte, cRootIndex, prDic); {$IfOpt R+} if prLastCode=cNilIndex then begin RunError(201); end; {$EndIf} { запись нового байта }{ чряшё№ эютюую срщЄр } lCodes^[i]:=cCode_ResetDictionary; lLength^[i]:=prCodeLength; Inc(i); lCodes^[i]:=AByte; lLength^[i]:=8; Inc(i); Inc(lCodeSizeIncrement,(prCodeLength+8)); Include(prDicFlags,fNewByte); Inc(prFragmentLength); end else begin { добавление нового байта к НЕкорневому узлу } { фюсртыхэшх эютюую срщЄр ъ ═┼ъюЁэхтюьє єчыє } { запись кода }{ чряшё№ ъюфр } if (fNewByte in prDicFlags) then begin { записывать не надо - предыдущий код "новый байт" } { чряшё√трЄ№ эх эрфю - яЁхф√фє∙шщ ъюф "эют√щ срщЄ" } Exclude(prDicFlags,fNewByte); end else begin { проверка длины кода }{ яЁютхЁър фышэ√ ъюфр } if c>prMaxCode then begin { код превышает текущий максимальный размер кода - увеличить длину кода} { ъюф яЁхт√°рхЄ Єхъє∙шщ ьръёшьры№э√щ ЁрчьхЁ ъюфр - єтхышўшЄ№ фышэє ъюфр} lCodes^[i]:=cCode_IncCodeLength; lLength^[i]:=prCodeLength; Inc(i); Inc(lCodeSizeIncrement,(prCodeLength+cCodeLengthIncrementLength)); { приращение длины кода } { яЁшЁр∙хэшх фышэ√ ъюфр } lCodes^[i]:=IncrementCodeLength(c); lLength^[i]:=cCodeLengthIncrementLength; Inc(i); end; {$IfOpt R+} if c>prMaxCode then begin RunError(201); end; {$EndIf} { запись собственно кода }{ чряшё№ ёюсёЄтхээю ъюфр } lCodes^[i]:=c; lLength^[i]:=prCodeLength; Inc(i); Inc(lCodeSizeIncrement,(prCodeLength)); end; { если длина фрагмента не превосходит максимально допустимой, } { хёыш фышэр ЇЁруьхэЄр эх яЁхтюёїюфшЄ ьръёшьры№эю фюяєёЄшьющ, } if (prFragmentLength<=prFragmentLengthLimit) then begin { то добавляем в словарь новое продолжение фрагмента } { Єю фюсрты хь т ёыютрЁ№ эютюх яЁюфюыцхэшх ЇЁруьхэЄр } if LZBase.AddNodeToBinaryTree(AByte, c, prDic)=cNilIndex then begin { свободное место в словаре закончилось - сбросить словарь } { ётюсюфэюх ьхёЄю т ёыютрЁх чръюэўшыюё№ - ёсЁюёшЄ№ ёыютрЁ№ } Inc(lCodeSizeIncrement,(prCodeLength+8)); { ! должно быть ПЕРЕД сбросом словаря } { ! фюыцэю с√Є№ ╧┼╨┼─ ёсЁюёюь ёыютрЁ  } {!!! должно быть ПЕРЕД ResetDictionary }{!!! фюыцэю с√Є№ ╧┼╨┼─ ResetDictionary } lCodes^[i]:=cCode_ResetDictionary; lLength^[i]:=prCodeLength; Inc(i); ResetDictionary; prLastCode:=LZBase.AddNodeToBinaryTree(AByte, cRootIndex, prDic); {$IfOpt R+} if prLastCode=cNilIndex then begin RunError(201); end; {$EndIf} { запись нового байта }{ чряшё№ эютюую срщЄр } lCodes^[i]:=AByte; lLength^[i]:=8; Inc(i); Include(prDicFlags,fNewByte); Inc(prFragmentLength); { запRм-ить приращ_-и_ д<и-ы да--ых } { чряюьэшЄ№ яЁшЁр∙хэшх фышэ√ фрээ√ї } xInc(prCompressedSize,lCodeSizeIncrement); pbCodesCount:=i; ByteToCodesEx:=i; { мRж-R выcти из прRц_дуры } { ьюцэю т√щЄш шч яЁюЎхфєЁ√ } Exit; end else begin if prCurrentMaxFragmentLengthcNilIndex then begin { фрагмент найден - продолжаем поиск }{ ЇЁруьхэЄ эрщфхэ - яЁюфюыцрхь яюшёъ } prLastCode:=c; Inc(prFragmentLength); end else begin { фрагмент не найден - добавляем новый байт в словарь } { ЇЁруьхэЄ эх эрщфхэ - фюсрты хь эют√щ срщЄ т ёыютрЁ№ } { добавление нового значения байта к корневому узлу } { фюсртыхэшх эютюую чэрўхэш  срщЄр ъ ъюЁэхтюьє єчыє } c:=LZBase.AddNodeToBinaryTree(AByte, cRootIndex, prDic); Inc(lCodeSizeIncrement,(prCodeLength+8)); { ! должно быть ПЕРЕД сбросом словаря } { ! фюыцэю с√Є№ ╧┼╨┼─ ёсЁюёюь ёыютрЁ  } lLength^[i]:=prCodeLength; {!!! должно быть ПЕРЕД ResetDictionary } if c=cNilIndex then begin { свободное место в словаре закончилось }{ ётюсюфэюх ьхёЄю т ёыютрЁх чръюэўшыюё№ } lCodes^[i]:=cCode_ResetDictionary; ResetDictionary; c:=LZBase.AddNodeToBinaryTree(AByte, cRootIndex, prDic); end else begin lCodes^[i]:=cCode_NewByte; end; Inc(i); {$IfOpt R+} if c=cNilIndex then begin RunError(201); end; {$EndIf} prLastCode:=c; { запись нового байта }{ чряшё№ эютюую срщЄр } lCodes^[i]:=AByte; lLength^[i]:=8; Inc(i); Include(prDicFlags,fNewByte); Inc(prFragmentLength); end; end; { запомнить приращение длины данных }{ чряюьэшЄ№ яЁшЁр∙хэшх фышэ√ фрээ√ї } xInc(prCompressedSize,lCodeSizeIncrement); pbCodesCount:=i; ByteToCodesEx:=i; end; end; { запись последнего фрагмента }{ чряшё№ яюёыхфэхую ЇЁруьхэЄр } function tLZDictionary.GetLastCodes(var ACodes:tLZCodesArray):tCodesCount; var i:tCodesCount; c:tIndex; begin {$IfOpt R+} if not (fEncodeRegime in prDicFlags) or (fDecodeRegime in prDicFlags) then begin RunError(201); end; {$EndIf} c:=prLastCode; { проверка на добавление нового значения байта к корню } { яЁютхЁър эр фюсртыхэшх эютюую чэрўхэш  срщЄр ъ ъюЁэ■ } if c=cRootIndex then begin { ничего не делать }{ эшўхую эх фхырЄ№ } GetLastCodes:=0; end else begin { запись кода } { чряшё№ ъюфр } if (fNewByte in prDicFlags) then begin { записывать не надо - предыдущий код "новый байт" } { чряшё√трЄ№ эх эрфю - яЁхф√фє∙шщ ъюф "эют√щ срщЄ" } Exclude(prDicFlags,fNewByte); GetLastCodes:=0; end else begin i:=0; { проверка длины кода и его изменение } { яЁютхЁър фышэ√ ъюфр ш хую шчьхэхэшх } if c>prMaxCode then begin { код превышает текущий максимальный размер кода - увеличить длину кода} { ъюф яЁхт√°рхЄ Єхъє∙шщ ьръёшьры№э√щ ЁрчьхЁ ъюфр - єтхышўшЄ№ фышэє ъюфр} ACodes.Code[i]:=cCode_IncCodeLength; ACodes.Length[i]:=prCodeLength; Inc(i); xInc(prCompressedSize,(prCodeLength+cCodeLengthIncrementLength)); ACodes.Code[i]:=IncrementCodeLength(c); ACodes.Length[i]:=cCodeLengthIncrementLength; Inc(i); end; {$IfOpt R+} if c>prMaxCode then begin RunError(201); end; {$EndIf} ACodes.Code[i]:=c; ACodes.Length[i]:=prCodeLength; Inc(i); xInc(prCompressedSize,prCodeLength); GetLastCodes:=i; end; prLastCode:=cRootIndex; end; end; { запись последнего фрагмента }{ чряшё№ яюёыхфэхую ЇЁруьхэЄр } function tLZDictionary.GetLastCodesEx:tCodesCount; var i:tCodesCount; c:tIndex; begin {$IfOpt R+} if not (fEncodeRegime in prDicFlags) or (fDecodeRegime in prDicFlags) then begin RunError(201); end; {$EndIf} c:=prLastCode; { проверка на добавление нового значения байта к корню } { яЁютхЁър эр фюсртыхэшх эютюую чэрўхэш  срщЄр ъ ъюЁэ■ } if c=cRootIndex then begin { ничего не делать }{ эшўхую эх фхырЄ№ } pbCodesCount:=0; GetLastCodesEx:=0; end else begin { запись кода } { чряшё№ ъюфр } if (fNewByte in prDicFlags) then begin { записывать не надо - предыдущий код "новый байт" } { чряшё√трЄ№ эх эрфю - яЁхф√фє∙шщ ъюф "эют√щ срщЄ" } Exclude(prDicFlags,fNewByte); pbCodesCount:=0; GetLastCodesEx:=0; end else begin i:=0; { проверка длины кода и его изменение } { яЁютхЁър фышэ√ ъюфр ш хую шчьхэхэшх } if c>prMaxCode then begin { код превышает текущий максимальный размер кода - увеличить длину кода} { ъюф яЁхт√°рхЄ Єхъє∙шщ ьръёшьры№э√щ ЁрчьхЁ ъюфр - єтхышўшЄ№ фышэє ъюфр} pbCodes.Code[i]:=cCode_IncCodeLength; pbCodes.Length[i]:=prCodeLength; Inc(i); xInc(prCompressedSize,(prCodeLength+cCodeLengthIncrementLength)); pbCodes.Code[i]:=IncrementCodeLength(c); pbCodes.Length[i]:=cCodeLengthIncrementLength; Inc(i); end; {$IfOpt R+} if c>prMaxCode then begin RunError(201); end; {$EndIf} pbCodes.Code[i]:=c; pbCodes.Length[i]:=prCodeLength; Inc(i); xInc(prCompressedSize,prCodeLength); pbCodesCount:=i; GetLastCodesEx:=i; end; prLastCode:=cRootIndex; end; end; { Декодирование фрагмента с обновлением словаря - возвращает значение >=0, если ACode декодирован, значение = числу байт помещенных в ABuffer; иначе возвращает значение <0, значение = размер недостающего пространства в буфере. Если возвращено значение <0, то ACode считается НЕДЕКОДИРОВАННЫМ и небходимо повторно вызвать CodeToBytes(ACode, ...) с новым буфером, остаточного размера. } { ─хъюфшЁютрэшх ЇЁруьхэЄр ё юсэютыхэшхь ёыютрЁ  - тючтЁр∙рхЄ чэрўхэшх >=0, хёыш ACode фхъюфшЁютрэ, чэрўхэшх = ўшёыє срщЄ яюьх∙хээ√ї т ABuffer; шэрўх тючтЁр∙рхЄ чэрўхэшх <0, чэрўхэшх = ЁрчьхЁ эхфюёЄр■∙хую яЁюёЄЁрэёЄтр т сєЇхЁх. ┼ёыш тючтЁр∙хэю чэрўхэшх <0, Єю ACode ёўшЄрхЄё  ═┼─┼╩╬─╚╨╬┬└══█╠ ш эхсїюфшью яютЄюЁэю т√чтрЄ№ CodeToBytes(ACode, ...) ё эют√ь сєЇхЁюь, юёЄрЄюўэюую ЁрчьхЁр. } function tLZDictionary.CodeToBytes(ACode:tIndex; var ABuffer; ABufferSize:tBufferIndex):tSignedBufferIndex; { Декодирует и восстанавливает словарь в процессе декодировки. } { ─хъюфшЁєхЄ ш тюёёЄрэртыштрхЄ ёыютрЁ№ т яЁюЎхёёх фхъюфшЁютъш. } var DataSize:tSignedBufferIndex; begin {$IfOpt R+} if (fEncodeRegime in prDicFlags) or not (fDecodeRegime in prDicFlags) then begin RunError(201); end; if (fNewByte in prDicFlags) and (fIncCodeLength in prDicFlags) then begin RunError(201); end; {$EndIf} CodeToBytes:=0; if (fNewByte in prDicFlags) then begin { предыдущий код - "НОВЫЙ БАЙТ" или "СБРОС СЛОВАРЯ"} { яЁхф√фє∙шщ ъюф - "═╬┬█╔ ┴└╔╥" шыш "╤┴╨╬╤ ╤╦╬┬└╨▀"} {$IfOpt R+} if ABufferSize<1 then begin RunError(201); end; if ACode>High(tByte) then begin RunError(201); end; {$EndIf} { вернуть код в буфере как байт } { тхЁэєЄ№ ъюф т сєЇхЁх ъръ срщЄ } tBuffer(ABuffer)[0]:=ACode; { данных возвращено 1 байт } { фрээ√ї тючтЁр∙хэю 1 срщЄ } CodeToBytes:=1; { сбросить флаг } { ёсЁюёшЄ№ Їыру } Exclude(prDicFlags,fNewByte); { пополнить словарь } { яюяюыэшЄ№ ёыютрЁ№ } if (prLastCode<>cRootIndex) then begin {$IfOpt R+} if cNilIndex={$EndIf} {$IfDef Fast1 - неполное восстановление словаря эхяюыэюх тюёёЄрэютыхэшх ёыютрЁ  } LZBase.AddNodeForDecode(ACode, prLastCode, prDic) {$ELSE} AddToLast(ACode) {$EndIf Fast1} {$IfOpt R+} then begin RunError(201); end {$EndIf}; end; {$IfDef Fast1 - неполное восстановление словаря эхяюыэюх тюёёЄрэютыхэшх ёыютрЁ  } prLastCode:=LZBase.AddNodeForDecode(ACode, cRootIndex, prDic); {$ELSE} prLastCode:=AddRoot(ACode); {$EndIf Fast1} {$IfOpt R+} if prLastCode=cNilIndex then RunError(201); {$EndIf} { запомнить первый байт (на всякий случай) } { чряюьэшЄ№ яхЁт√щ срщЄ (эр тё ъшщ ёыєўрщ) } prLastDecodedFragmentFirstByte:=ACode; {!!! это убирать нельзя - распаковка идет неправильно} end else if (fIncCodeLength in prDicFlags) then begin { предыдущий код - "УВЕЛИЧИТЬ ДЛИНУ КОДА"} { яЁхф√фє∙шщ ъюф - "╙┬┼╦╚╫╚╥▄ ─╦╚═╙ ╩╬─└"} {$IfOpt R+} if ACode>30 then begin RunError(201); end; {$EndIf} { увеличить текущую длину кода на величину ACode } { єтхышўшЄ№ Єхъє∙є■ фышэє ъюфр эр тхышўшэє ACode } DoIncrementCodeLength(ACode); { сбросить флаг } { ёсЁюёшЄ№ Їыру } Exclude(prDicFlags,fIncCodeLength); { данных не возвращено } { фрээ√ї эх тючтЁр∙хэю } end else begin {$IfOpt R+} if ACode>prMaxCode then begin RunError(201); end; {$EndIf} { ACode это } case ACode of cCode_ResetDictionary: begin { ACode="СБРОС СЛОВАРЯ"} { ACode="╤┴╨╬╤ ╤╦╬┬└╨▀"} ResetDictionary; Include(prDicFlags,fNewByte); end; cCode_NewByte: begin { ACode="НОВЫЙ БАЙТ"} { ACode="═╬┬█╔ ┴└╔╥"} Include(prDicFlags,fNewByte); end; cCode_IncCodeLength: begin { ACode="УВЕЛИЧИТЬ ДЛИНУ КОДА"} { ACode="╙┬┼╦╚╫╚╥▄ ─╦╚═╙ ╩╬─└"} Include(prDicFlags,fIncCodeLength); end; else begin { ACode=код фрагмента} { ACode=ъюф ЇЁруьхэЄр} { Особый случай: Допустим при кодировании встретилась последовательность ..."ababax"... причем, при начале ее кодирования фрагмент "ab" уже есть в словаре, а фрагмента "aba" еще нет в словаре. Тогда при кодировании после прохода "ab" и поступления на вход "a" будет обнаружен конец фрагмента, выдан код X, соответствующий "ab" и добавлен в словарь фрагмент "aba" с кодом Y, где Y старший код в словаре на текущий момент. Далее в словаре будет начат новый поиск и установлено начало фрагмента "a...". После прохода "ba", в словаре будет найден фрагмент "aba" и при поступлении на вход "x" будет выдан код Y и начат новый поиск в словаре. В результате в кодированном файле будет последовательность кодов "...,X,Y,...". При декодировке возникнет следующая проблема: В момент декодирования кода X фрагмент "ab" уже есть в словаре и будет декодирован, но кода Y в словаре еще нет и декодирование фрагмента "aba" невозможно! Причем, если бы во фрагменте ..."ab?bax"... вместо "?" стоял бы не "a", а любой другой символ, то описанной выше проблемы на наблюдалось бы. } { ╬ёюс√щ ёыєўрщ: ─юяєёЄшь яЁш ъюфшЁютрэшш тёЄЁхЄшырё№ яюёыхфютрЄхы№эюёЄ№ ..."ababax"... яЁшўхь, яЁш эрўрых хх ъюфшЁютрэш  ЇЁруьхэЄ "ab" єцх хёЄ№ т ёыютрЁх, р ЇЁруьхэЄр "aba" х∙х эхЄ т ёыютрЁх. ╥юуфр яЁш ъюфшЁютрэшш яюёых яЁюїюфр "ab" ш яюёЄєяыхэш  эр тїюф "a" сєфхЄ юсэрЁєцхэ ъюэхЎ ЇЁруьхэЄр, т√фрэ ъюф X, ёююЄтхЄёЄтє■∙шщ "ab" ш фюсртыхэ т ёыютрЁ№ ЇЁруьхэЄ "aba" ё ъюфюь Y, уфх Y ёЄрЁ°шщ ъюф т ёыютрЁх эр Єхъє∙шщ ьюьхэЄ. ─рыхх т ёыютрЁх сєфхЄ эрўрЄ эют√щ яюшёъ ш єёЄрэютыхэю эрўрыю ЇЁруьхэЄр "a...". ╧юёых яЁюїюфр "ba", т ёыютрЁх сєфхЄ эрщфхэ ЇЁруьхэЄ "aba" ш яЁш яюёЄєяыхэшш эр тїюф "x" сєфхЄ т√фрэ ъюф Y ш эрўрЄ эют√щ яюшёъ т ёыютрЁх. ┬ Ёхчєы№ЄрЄх т ъюфшЁютрээюь Їрщых сєфхЄ яюёыхфютрЄхы№эюёЄ№ ъюфют "...,X,Y,...". ╧Ёш фхъюфшЁютъх тючэшъэхЄ ёыхфє■∙р  яЁюсыхьр: ┬ ьюьхэЄ фхъюфшЁютрэш  ъюфр X ЇЁруьхэЄ "ab" єцх хёЄ№ т ёыютрЁх ш сєфхЄ фхъюфшЁютрэ, эю ъюфр Y т ёыютрЁх х∙х эхЄ ш фхъюфшЁютрэшх Y (ЇЁруьхэЄ "aba") эхтючьюцэю! ╧Ёшўхь, хёыш с√ тю ЇЁруьхэЄх ..."ab?bax"... тьхёЄю "?" ёЄю ы с√ эх "a", р ы■сющ фЁєующ ёшьтюы, Єю юяшёрээющ т√°х яЁюсыхь√ эр эрсы■фрыюё№ с√. } {$IfOpt R+} if (ACode>prDic.Descriptors.FirstFree) then RunError(201); {$EndIf} if (ACode=prDic.Descriptors.FirstFree) then begin { код отсутствует в словаре - отработка особого случая, см. выше } { проверим: хватит ли места для декодировки? !!! Это важно проверить, чтобы не получилось ситуации: словарь пополнен, но декодировать не удалось из-за недостатка места в буфере. В этом случае код считается недекодированным и при следующем обращении снова будет попытка добавить то же самое продолжение (уже существующее).} { ъюф юЄёєЄёЄтєхЄ т ёыютрЁх - юЄЁрсюЄър юёюсюую ёыєўр , ёь. т√°х } { яЁютхЁшь: їтрЄшЄ ыш ьхёЄр фы  фхъюфшЁютъш? !!! ▌Єю трцэю яЁютхЁшЄ№, ўЄюс√ эх яюыєўшыюё№ ёшЄєрЎшш: ёыютрЁ№ яюяюыэхэ, эю фхъюфшЁютрЄ№ эх єфрыюё№ шч-чр эхфюёЄрЄър ьхёЄр т сєЇхЁх. ┬ ¤Єюь ёыєўрх ъюф ёўшЄрхЄё  эхфхъюфшЁютрээ√ь ш яЁш ёыхфє■∙хь юсЁр∙хэшш ёэютр сєфхЄ яюя√Єър фюсртшЄ№ Єю цх ёрьюх яЁюфюыцхэшх (єцх фюсртыхээюх).} if prFragmentLengthprLastDecodedFragmentFirstByte then begin RunError(201); end; {$EndIf} { запомнить текущий фрагмент } { чряюьэшЄ№ Єхъє∙шщ ЇЁруьхэЄ } prLastCode:=ACode; { запомнить длину текущего фрагмента} { чряюьэшЄ№ фышэє Єхъє∙хую ЇЁруьхэЄр } Inc(prFragmentLength); { вернуть результат } { тхЁэєЄ№ Ёхчєы№ЄрЄ } CodeToBytes:=DataSize; end else begin { места мало - вернуть недостающий размер } { ьхёЄр ьрыю - тхЁэєЄ№ эхфюёЄр■∙шщ ЁрчьхЁ } CodeToBytes:=-Succ(prFragmentLength-ABufferSize); end; end else begin { код есть в словаре }{ ъюф хёЄ№ т ёыютрЁх } { декодировать } { фхъюфшЁютрЄ№ } DataSize:=LZBase.DecodeNode(ACode, ABuffer, ABufferSize, prDic); if DataSize>=0 then begin { декодировано }{ фхъюфшЁютрэю } { запомнить первый байт (на всякий случай) } { чряюьэшЄ№ яхЁт√щ срщЄ (эр тё ъшщ ёыєўрщ) } prLastDecodedFragmentFirstByte:=tBuffer(ABuffer)[0]; { проверить длину фрагмента } { яЁютхЁшЄ№ фышэє ЇЁруьхэЄр } if (prFragmentLengthHigh(tByte) then begin RunError(201); end; {$EndIf} { вернуть код в буфере как байт } { тхЁэєЄ№ ъюф т сєЇхЁх ъръ срщЄ } tBuffer(ABuffer)[0]:=ACode; { данных возвращено 1 байт } { фрээ√ї тючтЁр∙хэю 1 срщЄ } ADataSize:=1; { сбросить флаг } { ёсЁюёшЄ№ Їыру } Exclude(prDicFlags,fNewByte); { пополнить словарь } { яюяюыэшЄ№ ёыютрЁ№ } if (prLastCode<>cRootIndex) then begin {$IfOpt R+} if cNilIndex={$EndIf} {$IfDef Fast1 - неполное восстановление словаря эхяюыэюх тюёёЄрэютыхэшх ёыютрЁ  } LZBase.AddNodeForDecode(ACode, prLastCode, prDic) {$ELSE} AddToLast(ACode) {$EndIf Fast1} {$IfOpt R+} then begin RunError(201); end {$EndIf}; end; {$IfDef Fast1 - неполное восстановление словаря эхяюыэюх тюёёЄрэютыхэшх ёыютрЁ  } prLastCode:=LZBase.AddNodeForDecode(ACode, cRootIndex, prDic); {$ELSE} prLastCode:=AddRoot(ACode); {$EndIf Fast1} {$IfOpt R+} if prLastCode=cNilIndex then RunError(201); {$EndIf} { запомнить первый байт (на всякий случай) } { чряюьэшЄ№ яхЁт√щ срщЄ (эр тё ъшщ ёыєўрщ) } prLastDecodedFragmentFirstByte:=ACode; {!!! это убирать нельзя - распаковка идет неправильно} end else if (fIncCodeLength in prDicFlags) then begin { предыдущий код - "УВЕЛИЧИТЬ ДЛИНУ КОДА"} { яЁхф√фє∙шщ ъюф - "╙┬┼╦╚╫╚╥▄ ─╦╚═╙ ╩╬─└"} {$IfOpt R+} if ACode>30 then begin RunError(201); end; {$EndIf} { увеличить текущую длину кода на величину ACode } { єтхышўшЄ№ Єхъє∙є■ фышэє ъюфр эр тхышўшэє ACode } DoIncrementCodeLength(ACode); { сбросить флаг } { ёсЁюёшЄ№ Їыру } Exclude(prDicFlags,fIncCodeLength); { данных не возвращено } { фрээ√ї эх тючтЁр∙хэю } ADataSize:=0; end else begin ADataSize:=0; {$IfOpt R+} if ACode>prMaxCode then begin RunError(201); end; {$EndIf} { ACode это } case ACode of cCode_ResetDictionary: begin { ACode="СБРОС СЛОВАРЯ"} { ACode="╤┴╨╬╤ ╤╦╬┬└╨▀"} ResetDictionary; Include(prDicFlags,fNewByte); end; cCode_NewByte: begin { ACode="НОВЫЙ БАЙТ"} { ACode="═╬┬█╔ ┴└╔╥"} Include(prDicFlags,fNewByte); end; cCode_IncCodeLength: begin { ACode="УВЕЛИЧИТЬ ДЛИНУ КОДА"} { ACode="╙┬┼╦╚╫╚╥▄ ─╦╚═╙ ╩╬─└"} Include(prDicFlags,fIncCodeLength); end; else begin { ACode=код фрагмента} { ACode=ъюф ЇЁруьхэЄр} { Особый случай: Допустим при кодировании встретилась последовательность ..."ababax"... причем, при начале ее кодирования фрагмент "ab" уже есть в словаре, а фрагмента "aba" еще нет в словаре. Тогда при кодировании после прохода "ab" и поступления на вход "a" будет обнаружен конец фрагмента, выдан код X, соответствующий "ab" и добавлен в словарь фрагмент "aba" с кодом Y, где Y старший код в словаре на текущий момент. Далее в словаре будет начат новый поиск и установлено начало фрагмента "a...". После прохода "ba", в словаре будет найден фрагмент "aba" и при поступлении на вход "x" будет выдан код Y и начат новый поиск в словаре. В результате в кодированном файле будет последовательность кодов "...,X,Y,...". При декодировке возникнет следующая проблема: В момент декодирования кода X фрагмент "ab" уже есть в словаре и будет декодирован, но кода Y в словаре еще нет и декодирование фрагмента "aba" невозможно! Причем, если бы во фрагменте ..."ab?bax"... вместо "?" стоял бы не "a", а любой другой символ, то описанной выше проблемы на наблюдалось бы. } { ╬ёюс√щ ёыєўрщ: ─юяєёЄшь яЁш ъюфшЁютрэшш тёЄЁхЄшырё№ яюёыхфютрЄхы№эюёЄ№ ..."ababax"... яЁшўхь, яЁш эрўрых хх ъюфшЁютрэш  ЇЁруьхэЄ "ab" єцх хёЄ№ т ёыютрЁх, р ЇЁруьхэЄр "aba" х∙х эхЄ т ёыютрЁх. ╥юуфр яЁш ъюфшЁютрэшш яюёых яЁюїюфр "ab" ш яюёЄєяыхэш  эр тїюф "a" сєфхЄ юсэрЁєцхэ ъюэхЎ ЇЁруьхэЄр, т√фрэ ъюф X, ёююЄтхЄёЄтє■∙шщ "ab" ш фюсртыхэ т ёыютрЁ№ ЇЁруьхэЄ "aba" ё ъюфюь Y, уфх Y ёЄрЁ°шщ ъюф т ёыютрЁх эр Єхъє∙шщ ьюьхэЄ. ─рыхх т ёыютрЁх сєфхЄ эрўрЄ эют√щ яюшёъ ш єёЄрэютыхэю эрўрыю ЇЁруьхэЄр "a...". ╧юёых яЁюїюфр "ba", т ёыютрЁх сєфхЄ эрщфхэ ЇЁруьхэЄ "aba" ш яЁш яюёЄєяыхэшш эр тїюф "x" сєфхЄ т√фрэ ъюф Y ш эрўрЄ эют√щ яюшёъ т ёыютрЁх. ┬ Ёхчєы№ЄрЄх т ъюфшЁютрээюь Їрщых сєфхЄ яюёыхфютрЄхы№эюёЄ№ ъюфют "...,X,Y,...". ╧Ёш фхъюфшЁютъх тючэшъэхЄ ёыхфє■∙р  яЁюсыхьр: ┬ ьюьхэЄ фхъюфшЁютрэш  ъюфр X ЇЁруьхэЄ "ab" єцх хёЄ№ т ёыютрЁх ш сєфхЄ фхъюфшЁютрэ, эю ъюфр Y т ёыютрЁх х∙х эхЄ ш фхъюфшЁютрэшх Y (ЇЁруьхэЄ "aba") эхтючьюцэю! ╧Ёшўхь, хёыш с√ тю ЇЁруьхэЄх ..."ab?bax"... тьхёЄю "?" ёЄю ы с√ эх "a", р ы■сющ фЁєующ ёшьтюы, Єю юяшёрээющ т√°х яЁюсыхь√ эр эрсы■фрыюё№ с√. } {$IfOpt R+} if (ACode>prDic.Descriptors.FirstFree) then RunError(201); {$EndIf} if (ACode=prDic.Descriptors.FirstFree) then begin { код отсутствует в словаре - отработка особого случая, см. выше } { проверим: хватит ли места для декодировки? !!! Это важно проверить, чтобы не получилось ситуации: словарь пополнен, но декодировать не удалось из-за недостатка места в буфере. В этом случае код считается недекодированным и при следующем обращении снова будет попытка добавить то же самое продолжение (уже существующее).} { ъюф юЄёєЄёЄтєхЄ т ёыютрЁх - юЄЁрсюЄър юёюсюую ёыєўр , ёь. т√°х } { яЁютхЁшь: їтрЄшЄ ыш ьхёЄр фы  фхъюфшЁютъш? !!! ▌Єю трцэю яЁютхЁшЄ№, ўЄюс√ эх яюыєўшыюё№ ёшЄєрЎшш: ёыютрЁ№ яюяюыэхэ, эю фхъюфшЁютрЄ№ эх єфрыюё№ шч-чр эхфюёЄрЄър ьхёЄр т сєЇхЁх. ┬ ¤Єюь ёыєўрх ъюф ёўшЄрхЄё  эхфхъюфшЁютрээ√ь ш яЁш ёыхфє■∙хь юсЁр∙хэшш ёэютр сєфхЄ яюя√Єър фюсртшЄ№ Єю цх ёрьюх яЁюфюыцхэшх (єцх фюсртыхээюх).} if prFragmentLength{$EndIf} LZBase.DecodeNode(ACode, ABuffer, ABufferSize, ADataSize, prDic) {$IfOpt R+} then begin RunError(201); end {$EndIf};*) DataSize:=LZBase.DecodeNode(ACode, ABuffer, ABufferSize, prDic); {$IfOpt R+} if DataSize<0 then begin RunError(201); end {$EndIf}; ADataSize:=DataSize; {$IfOpt R+} if tBuffer(ABuffer)[0]<>prLastDecodedFragmentFirstByte then begin RunError(201); end; {$EndIf} { запомнить текущий фрагмент } { чряюьэшЄ№ Єхъє∙шщ ЇЁруьхэЄ } prLastCode:=ACode; { запомнить длину текущего фрагмента} { чряюьэшЄ№ фышэє Єхъє∙хую ЇЁруьхэЄр } Inc(prFragmentLength); { вернуть результат } { тхЁэєЄ№ Ёхчєы№ЄрЄ } CodeToBytesX:=0; end else begin { места мало - вернуть недостающий размер } { ьхёЄр ьрыю - тхЁэєЄ№ эхфюёЄр■∙шщ ЁрчьхЁ } CodeToBytesX:=Succ(prFragmentLength-ABufferSize); end; end else begin { код есть в словаре }{ ъюф хёЄ№ т ёыютрЁх } { декодировать } { фхъюфшЁютрЄ№ } { l:=LZBase.DecodeNode(ACode, ABuffer, ABufferSize, ADataSize, prDic); if l=0 then begin} { декодировано }{ фхъюфшЁютрэю } DataSize:=LZBase.DecodeNode(ACode, ABuffer, ABufferSize, prDic); if DataSize>=0 then begin { декодировано }{ фхъюфшЁютрэю } ADataSize:=DataSize; { запомнить первый байт (на всякий случай) } { чряюьэшЄ№ яхЁт√щ срщЄ (эр тё ъшщ ёыєўрщ) } prLastDecodedFragmentFirstByte:=tBuffer(ABuffer)[0]; { проверить длину фрагмента } { яЁютхЁшЄ№ фышэє ЇЁруьхэЄр } if (prFragmentLengthHigh(tByte) then begin RunError(201); end; {$EndIf} { вернуть код в буфере как байт } { тхЁэєЄ№ ъюф т сєЇхЁх ъръ срщЄ } tBuffer(ABuffer)[0]:=ACode; { данных возвращено 1 байт } { фрээ√ї тючтЁр∙хэю 1 срщЄ } ADataSize:=1; { сбросить флаг } { ёсЁюёшЄ№ Їыру } Exclude(prDicFlags,fNewByte); { пополнить словарь } { яюяюыэшЄ№ ёыютрЁ№ } if (prLastCode<>cRootIndex) then begin {$IfOpt R+} if cNilIndex={$EndIf} {$IfDef Fast1 - неполное восстановление словаря эхяюыэюх тюёёЄрэютыхэшх ёыютрЁ  } LZBase.AddNodeForDecode(ACode, prLastCode, prDic) {$ELSE} AddToLast(ACode) {$EndIf Fast1} {$IfOpt R+} then begin RunError(201); end {$EndIf}; end; {$IfDef Fast1 - неполное восстановление словаря эхяюыэюх тюёёЄрэютыхэшх ёыютрЁ  } {$IfOpt R+} if {$EndIf} LZBase.AddNodeForDecode(ACode, cRootIndex, prDic) {$IfOpt R+}=cNilIndex then RunError(201) {$EndIf}; prLastCode:=cRootIndex; {$ELSE} prLastCode:=AddRoot(ACode); prLastCode:=cRootIndex; {$EndIf Fast1} prFragmentLength:=0; { запомнить первый байт (на всякий случай) } { чряюьэшЄ№ яхЁт√щ срщЄ (эр тё ъшщ ёыєўрщ) } { prLastDecodedFragmentFirstByte:=ACode;} {!!! это убирать нельзя - распаковка идет неправильно} end else if (fIncCodeLength in prDicFlags) then begin { предыдущий код - "УВЕЛИЧИТЬ ДЛИНУ КОДА"} { яЁхф√фє∙шщ ъюф - "╙┬┼╦╚╫╚╥▄ ─╦╚═╙ ╩╬─└"} {$IfOpt R+} if ACode>30 then begin RunError(201); end; {$EndIf} { увеличить текущую длину кода на величину ACode } { єтхышўшЄ№ Єхъє∙є■ фышэє ъюфр эр тхышўшэє ACode } DoIncrementCodeLength(ACode); { сбросить флаг } { ёсЁюёшЄ№ Їыру } Exclude(prDicFlags,fIncCodeLength); { данных не возвращено } { фрээ√ї эх тючтЁр∙хэю } ADataSize:=0; end else begin ADataSize:=0; {$IfOpt R+} if ACode>prMaxCode then begin RunError(201); end; {$EndIf} { ACode это } case ACode of cCode_ResetDictionary: begin { ACode="СБРОС СЛОВАРЯ"} { ACode="╤┴╨╬╤ ╤╦╬┬└╨▀"} ResetDictionary; Include(prDicFlags,fNewByte); end; cCode_NewByte: begin { ACode="НОВЫЙ БАЙТ"} { ACode="═╬┬█╔ ┴└╔╥"} Include(prDicFlags,fNewByte); end; cCode_IncCodeLength: begin { ACode="УВЕЛИЧИТЬ ДЛИНУ КОДА"} { ACode="╙┬┼╦╚╫╚╥▄ ─╦╚═╙ ╩╬─└"} Include(prDicFlags,fIncCodeLength); end; else begin { ACode=код фрагмента} { ACode=ъюф ЇЁруьхэЄр} { Особый случай: Допустим при кодировании встретилась последовательность ..."ababax"... причем, при начале ее кодирования фрагмент "ab" уже есть в словаре, а фрагмента "aba" еще нет в словаре. Тогда при кодировании после прохода "ab" и поступления на вход "a" будет обнаружен конец фрагмента, выдан код X, соответствующий "ab" и добавлен в словарь фрагмент "aba" с кодом Y, где Y старший код в словаре на текущий момент. Далее в словаре будет начат новый поиск и установлено начало фрагмента "a...". После прохода "ba", в словаре будет найден фрагмент "aba" и при поступлении на вход "x" будет выдан код Y и начат новый поиск в словаре. В результате в кодированном файле будет последовательность кодов "...,X,Y,...". При декодировке возникнет следующая проблема: В момент декодирования кода X фрагмент "ab" уже есть в словаре и будет декодирован, но кода Y в словаре еще нет и декодирование фрагмента "aba" невозможно! Причем, если бы во фрагменте ..."ab?bax"... вместо "?" стоял бы не "a", а любой другой символ, то описанной выше проблемы на наблюдалось бы. } { ╬ёюс√щ ёыєўрщ: ─юяєёЄшь яЁш ъюфшЁютрэшш тёЄЁхЄшырё№ яюёыхфютрЄхы№эюёЄ№ ..."ababax"... яЁшўхь, яЁш эрўрых хх ъюфшЁютрэш  ЇЁруьхэЄ "ab" єцх хёЄ№ т ёыютрЁх, р ЇЁруьхэЄр "aba" х∙х эхЄ т ёыютрЁх. ╥юуфр яЁш ъюфшЁютрэшш яюёых яЁюїюфр "ab" ш яюёЄєяыхэш  эр тїюф "a" сєфхЄ юсэрЁєцхэ ъюэхЎ ЇЁруьхэЄр, т√фрэ ъюф X, ёююЄтхЄёЄтє■∙шщ "ab" ш фюсртыхэ т ёыютрЁ№ ЇЁруьхэЄ "aba" ё ъюфюь Y, уфх Y ёЄрЁ°шщ ъюф т ёыютрЁх эр Єхъє∙шщ ьюьхэЄ. ─рыхх т ёыютрЁх сєфхЄ эрўрЄ эют√щ яюшёъ ш єёЄрэютыхэю эрўрыю ЇЁруьхэЄр "a...". ╧юёых яЁюїюфр "ba", т ёыютрЁх сєфхЄ эрщфхэ ЇЁруьхэЄ "aba" ш яЁш яюёЄєяыхэшш эр тїюф "x" сєфхЄ т√фрэ ъюф Y ш эрўрЄ эют√щ яюшёъ т ёыютрЁх. ┬ Ёхчєы№ЄрЄх т ъюфшЁютрээюь Їрщых сєфхЄ яюёыхфютрЄхы№эюёЄ№ ъюфют "...,X,Y,...". ╧Ёш фхъюфшЁютъх тючэшъэхЄ ёыхфє■∙р  яЁюсыхьр: ┬ ьюьхэЄ фхъюфшЁютрэш  ъюфр X ЇЁруьхэЄ "ab" єцх хёЄ№ т ёыютрЁх ш сєфхЄ фхъюфшЁютрэ, эю ъюфр Y т ёыютрЁх х∙х эхЄ ш фхъюфшЁютрэшх Y (ЇЁруьхэЄ "aba") эхтючьюцэю! ╧Ёшўхь, хёыш с√ тю ЇЁруьхэЄх ..."ab?bax"... тьхёЄю "?" ёЄю ы с√ эх "a", р ы■сющ фЁєующ ёшьтюы, Єю юяшёрээющ т√°х яЁюсыхь√ эр эрсы■фрыюё№ с√. } {$IfOpt R+} if (ACode>prDic.Descriptors.FirstFree) then RunError(201); {$EndIf} if (ACode=prDic.Descriptors.FirstFree) then begin { код отсутствует в словаре - отработка особого случая, см. выше } { проверим: хватит ли места для декодировки? !!! Это важно проверить, чтобы не получилось ситуации: словарь пополнен, но декодировать не удалось из-за недостатка места в буфере. В этом случае код считается недекодированным и при следующем обращении снова будет попытка добавить то же самое продолжение (уже существующее).} { ъюф юЄёєЄёЄтєхЄ т ёыютрЁх - юЄЁрсюЄър юёюсюую ёыєўр , ёь. т√°х } { яЁютхЁшь: їтрЄшЄ ыш ьхёЄр фы  фхъюфшЁютъш? !!! ▌Єю трцэю яЁютхЁшЄ№, ўЄюс√ эх яюыєўшыюё№ ёшЄєрЎшш: ёыютрЁ№ яюяюыэхэ, эю фхъюфшЁютрЄ№ эх єфрыюё№ шч-чр эхфюёЄрЄър ьхёЄр т сєЇхЁх. ┬ ¤Єюь ёыєўрх ъюф ёўшЄрхЄё  эхфхъюфшЁютрээ√ь ш яЁш ёыхфє■∙хь юсЁр∙хэшш ёэютр сєфхЄ яюя√Єър фюсртшЄ№ Єю цх ёрьюх яЁюфюыцхэшх (єцх фюсртыхээюх).} if prFragmentLength{$EndIf} LZBase.DecodeNode(ACode, ABuffer, ABufferSize, ADataSize, prDic) {$IfOpt R+} then begin RunError(201); end {$EndIf}; {$IfOpt R+} if tBuffer(ABuffer)[0]<>prLastDecodedFragmentFirstByte then begin RunError(201); end; {$EndIf} { запомнить текущий фрагмент } { чряюьэшЄ№ Єхъє∙шщ ЇЁруьхэЄ } prLastCode:=ACode; { запомнить длину текущего фрагмента} { чряюьэшЄ№ фышэє Єхъє∙хую ЇЁруьхэЄр } Inc(prFragmentLength); { вернуть результат } { тхЁэєЄ№ Ёхчєы№ЄрЄ } CodeToBytes:=0; end else begin { места мало - вернуть недостающий размер } { ьхёЄр ьрыю - тхЁэєЄ№ эхфюёЄр■∙шщ ЁрчьхЁ } CodeToBytes:=Succ(prFragmentLength-ABufferSize); end; end else begin { код есть в словаре }{ ъюф хёЄ№ т ёыютрЁх } { декодировать } { фхъюфшЁютрЄ№ } l:=LZBase.DecodeNode(ACode, ABuffer, ABufferSize, ADataSize, prDic); if l=0 then begin { декодировано }{ фхъюфшЁютрэю } { запомнить первый байт (на всякий случай) } { чряюьэшЄ№ яхЁт√щ срщЄ (эр тё ъшщ ёыєўрщ) } prLastDecodedFragmentFirstByte:=tBuffer(ABuffer)[0]; { проверить длину фрагмента } { яЁютхЁшЄ№ фышэє ЇЁруьхэЄр } if (prFragmentLength