unit ULZMAEncoder; {$IFDEF FPC} {$MODE Delphi} {$ENDIF} interface uses UBitTreeEncoder,ULZMABase,ULZBinTree,URangeEncoder,KOL,ULZMACommon; const EMatchFinderTypeBT2 = 0; EMatchFinderTypeBT4 = 1; kIfinityPrice:integer = $FFFFFFF; kDefaultDictionaryLogSize = 22; kNumFastBytesDefault = $20; kNumLenSpecSymbols = ULZMABase.kNumLowLenSymbols + ULZMABase.kNumMidLenSymbols; kNumOpts = 1 shl 12; kPropSize = 5; type PLZMAEncoder2=^TLZMAEncoder2; PLZMALiteralEncoder=^TLZMALiteralEncoder; PLZMAOptimal=^TLZMAOptimal; PLZMALenPriceTableEncoder=^TLZMALenPriceTableEncoder; PLZMAEncoder=^TLZMAEncoder; TLZMAEncoder=object(TObj) private FOnProgress:TLZMAProgress; procedure DoProgress(const Action:TLZMAProgressAction;const Value:integer); public g_FastPos:array [0..1 shl 11-1] of byte; _state:integer; _previousByte:byte; _repDistances:array [0..ULZMABase.kNumRepDistances-1] of integer; _optimum: array [0..kNumOpts-1] of PLZMAOptimal; _matchFinder:PLZBinTree; _rangeEncoder:PRangeEncoder; _isMatch:array [0..ULZMABase.kNumStates shl ULZMABase.kNumPosStatesBitsMax-1]of smallint; _isRep:array [0..ULZMABase.kNumStates-1] of smallint; _isRepG0:array [0..ULZMABase.kNumStates-1] of smallint; _isRepG1:array [0..ULZMABase.kNumStates-1] of smallint; _isRepG2:array [0..ULZMABase.kNumStates-1] of smallint; _isRep0Long:array [0..ULZMABase.kNumStates shl ULZMABase.kNumPosStatesBitsMax-1]of smallint; _posSlotEncoder:array [0..ULZMABase.kNumLenToPosStates-1] of PBitTreeEncoder; // kNumPosSlotBits _posEncoders:array [0..ULZMABase.kNumFullDistances-ULZMABase.kEndPosModelIndex-1]of smallint; _posAlignEncoder:PBitTreeEncoder; _lenEncoder:PLZMALenPriceTableEncoder; _repMatchLenEncoder:PLZMALenPriceTableEncoder; _literalEncoder:PLZMALiteralEncoder; _matchDistances:array [0..ULZMABase.kMatchMaxLen*2+1] of integer; _numFastBytes:integer; _longestMatchLength:integer; _numDistancePairs:integer; _additionalOffset:integer; _optimumEndIndex:integer; _optimumCurrentIndex:integer; _longestMatchWasFound:boolean; _posSlotPrices:array [0..1 shl (ULZMABase.kNumPosSlotBits+ULZMABase.kNumLenToPosStatesBits)-1] of integer; _distancesPrices:array [0..ULZMABase.kNumFullDistances shl ULZMABase.kNumLenToPosStatesBits-1] of integer; _alignPrices:array [0..ULZMABase.kAlignTableSize-1] of integer; _alignPriceCount:integer; _distTableSize:integer; _posStateBits:integer; _posStateMask:integer; _numLiteralPosStateBits:integer; _numLiteralContextBits:integer; _dictionarySize:integer; _dictionarySizePrev:integer; _numFastBytesPrev:integer; nowPos64:int64; _finished:boolean; _inStream:PStream; _matchFinderType:integer; _writeEndMark:boolean; _needReleaseMFStream:boolean; reps:array [0..ULZMABase.kNumRepDistances-1]of integer; repLens:array [0..ULZMABase.kNumRepDistances-1] of integer; backRes:integer; processedInSize:int64; processedOutSize:int64; finished:boolean; properties:array [0..kPropSize] of byte; tempPrices:array [0..ULZMABase.kNumFullDistances-1]of integer; _matchPriceCount:integer; constructor Create; destructor Destroy;virtual; function GetPosSlot(const pos:integer):integer; function GetPosSlot2(const pos:integer):integer; procedure BaseInit; procedure _Create; procedure SetWriteEndMarkerMode(const AwriteEndMarker:boolean); procedure _Init; function ReadMatchDistances:integer; procedure MovePos(const num:integer); function GetRepLen1Price(const state,posState:integer):integer; function GetPureRepPrice(const repIndex, state, posState:integer):integer; function GetRepPrice(const repIndex, len, state, posState:integer):integer; function GetPosLenPrice(const pos, len, posState:integer):integer; function Backward(cur:integer):integer; function GetOptimum(position:integer):integer; function ChangePair(const smallDist, bigDist:integer):boolean; procedure WriteEndMarker(const posState:integer); procedure Flush(const nowPos:integer); procedure ReleaseMFStream; procedure CodeOneBlock(var inSize,outSize:int64;var Afinished:boolean); procedure FillDistancesPrices; procedure FillAlignPrices; procedure SetOutStream(const outStream:PStream); procedure ReleaseOutStream; procedure ReleaseStreams; procedure SetStreams(const inStream, outStream:PStream;const inSize, outSize:int64); procedure Code(const inStream, outStream:PStream;const inSize, outSize:int64); procedure WriteCoderProperties(const outStream:PStream); function SetAlgorithm(const algorithm:integer):boolean; function SetDictionarySize(dictionarySize:Cardinal):boolean; function SeNumFastBytes(const numFastBytes:integer):boolean; function SetMatchFinder(const matchFinderIndex:integer):boolean; function SetLcLpPb(const lc,lp,pb:integer):boolean; procedure SetEndMarkerMode(const endMarkerMode:boolean); property OnProgress:TLZMAProgress read FOnProgress write FOnProgress; end; TLZMALiteralEncoder=object(TObj) public m_Coders: array of PLZMAEncoder2; m_NumPrevBits:integer; m_NumPosBits:integer; m_PosMask:integer; procedure _Create(const numPosBits,numPrevBits:integer); destructor Destroy;virtual; procedure _Init; function GetSubCoder(const pos:integer;const prevByte:byte):PLZMAEncoder2; end; TLZMAEncoder2=object(TObj) public m_Encoders: array[0..$300-1] of smallint; procedure _Init; procedure Encode(const rangeEncoder:PRangeEncoder;const symbol:byte); procedure EncodeMatched(const rangeEncoder:PRangeEncoder;const matchByte,symbol:byte); function GetPrice(const matchMode:boolean;const matchByte,symbol:byte):integer; end; TLZMALenEncoder=object(TObj) public _choice:array[0..1] of smallint; _lowCoder: array [0..ULZMABase.kNumPosStatesEncodingMax-1] of PBitTreeEncoder; _midCoder: array [0..ULZMABase.kNumPosStatesEncodingMax-1] of PBitTreeEncoder; _highCoder:PBitTreeEncoder; constructor Create; destructor Destroy;virtual; procedure _Init(const numPosStates:integer); procedure Encode(const rangeEncoder:PRangeEncoder;symbol:integer;const posState:integer);virtual; procedure SetPrices(const posState,numSymbols:integer;var prices:array of integer;const st:integer); end; TLZMALenPriceTableEncoder=object(TLZMALenEncoder) public _prices: array [0..ULZMABase.kNumLenSymbols shl ULZMABase.kNumPosStatesBitsEncodingMax-1] of integer; _tableSize:integer; _counters: array [0..ULZMABase.kNumPosStatesEncodingMax-1] of integer; procedure SetTableSize(const tableSize:integer); function GetPrice(const symbol,posState:integer):integer; procedure UpdateTable(const posState:integer); procedure UpdateTables(const numPosStates:integer); procedure Encode(const rangeEncoder:PRangeEncoder;symbol:integer;const posState:integer);virtual; end; TLZMAOptimal=object(TObj) public State:integer; Prev1IsChar:boolean; Prev2:boolean; PosPrev2:integer; BackPrev2:integer; Price:integer; PosPrev:integer; BackPrev:integer; Backs0:integer; Backs1:integer; Backs2:integer; Backs3:integer; procedure MakeAsChar; procedure MakeAsShortRep; function IsShortRep:boolean; end; implementation constructor TLZMAEncoder.Create; var kFastSlots,c,slotFast,j,k:integer; begin kFastSlots := 22; c := 2; g_FastPos[0] := 0; g_FastPos[1] := 1; for slotFast := 2 to kFastSlots -1 do begin k := (1 shl ((slotFast shr 1) - 1)); for j := 0 to k -1 do begin g_FastPos[c] := slotFast; inc(c); end; end; _state := ULZMABase.StateInit(); _matchFinder:=nil; New(_rangeEncoder, Create); New(_posAlignEncoder, Create(ULZMABase.kNumAlignBits)); New(_lenEncoder, Create); New(_repMatchLenEncoder, Create); New(_literalEncoder, Create); _numFastBytes:= kNumFastBytesDefault; _distTableSize:= (kDefaultDictionaryLogSize * 2); _posStateBits:= 2; _posStateMask:= (4 - 1); _numLiteralPosStateBits:= 0; _numLiteralContextBits:= 3; _dictionarySize:= (1 shl kDefaultDictionaryLogSize); _dictionarySizePrev:= -1; _numFastBytesPrev:= -1; _matchFinderType:= EMatchFinderTypeBT4; _writeEndMark:= false; _needReleaseMFStream:= false; end; destructor TLZMAEncoder.Destroy; var i:integer; begin _rangeEncoder.Free; _posAlignEncoder.Free; _lenEncoder.Free; _repMatchLenEncoder.Free; _literalEncoder.Free; if _matchFinder<>nil then _matchFinder.Free; for i := 0 to kNumOpts -1 do _optimum[i].Free; for i := 0 to ULZMABase.kNumLenToPosStates -1 do _posSlotEncoder[i].Free; end; procedure TLZMAEncoder._Create; var bt:PLZBinTree; numHashBytes,i:integer; begin if _matchFinder = nil then begin New(bt, Create); numHashBytes:= 4; if _matchFinderType = EMatchFinderTypeBT2 then numHashBytes := 2; bt.SetType(numHashBytes); _matchFinder := bt; end; _literalEncoder._Create(_numLiteralPosStateBits, _numLiteralContextBits); if (_dictionarySize = _dictionarySizePrev) and (_numFastBytesPrev = _numFastBytes) then exit; _matchFinder._Create(_dictionarySize, kNumOpts, _numFastBytes, ULZMABase.kMatchMaxLen + 1); _dictionarySizePrev := _dictionarySize; _numFastBytesPrev := _numFastBytes; for i := 0 to kNumOpts -1 do New(_optimum[i], Create); for i := 0 to ULZMABase.kNumLenToPosStates -1 do New(_posSlotEncoder[i], Create(ULZMABase.kNumPosSlotBits)); end; function TLZMAEncoder.GetPosSlot(const pos:integer):integer; begin if (pos < (1 shl 11)) then result:=g_FastPos[pos] else if (pos < (1 shl 21)) then result:=(g_FastPos[pos shr 10] + 20) else result:=(g_FastPos[pos shr 20] + 40); end; function TLZMAEncoder.GetPosSlot2(const pos:integer):integer; begin if (pos < (1 shl 17)) then result:=(g_FastPos[pos shr 6] + 12) else if (pos < (1 shl 27)) then result:=(g_FastPos[pos shr 16] + 32) else result:=(g_FastPos[pos shr 26] + 52); end; procedure TLZMAEncoder.BaseInit; var i:integer; begin _state := ulzmaBase.StateInit; _previousByte := 0; for i := 0 to ULZMABase.kNumRepDistances -1 do _repDistances[i] := 0; end; procedure TLZMAEncoder.SetWriteEndMarkerMode(const AwriteEndMarker:boolean); begin _writeEndMark := AwriteEndMarker; end; procedure TLZMAEncoder._Init; var i:integer; begin BaseInit; _rangeEncoder._Init; URangeEncoder.InitBitModels(_isMatch); URangeEncoder.InitBitModels(_isRep0Long); URangeEncoder.InitBitModels(_isRep); URangeEncoder.InitBitModels(_isRepG0); URangeEncoder.InitBitModels(_isRepG1); URangeEncoder.InitBitModels(_isRepG2); URangeEncoder.InitBitModels(_posEncoders); _literalEncoder._Init(); for i := 0 to ULZMABase.kNumLenToPosStates -1 do _posSlotEncoder[i]._Init; _lenEncoder._Init(1 shl _posStateBits); _repMatchLenEncoder._Init(1 shl _posStateBits); _posAlignEncoder._Init; _longestMatchWasFound := false; _optimumEndIndex := 0; _optimumCurrentIndex := 0; _additionalOffset := 0; end; function TLZMAEncoder.ReadMatchDistances:integer; var lenRes:integer; begin lenRes := 0; _numDistancePairs := _matchFinder.GetMatches(_matchDistances); if _numDistancePairs > 0 then begin lenRes := _matchDistances[_numDistancePairs - 2]; if lenRes = _numFastBytes then lenRes := lenRes + _matchFinder.GetMatchLen(lenRes - 1, _matchDistances[_numDistancePairs - 1], ULZMABase.kMatchMaxLen - lenRes); end; inc(_additionalOffset); result:=lenRes; end; procedure TLZMAEncoder.MovePos(const num:integer); begin if num > 0 then begin _matchFinder.Skip(num); _additionalOffset := _additionalOffset + num; end; end; function TLZMAEncoder.GetRepLen1Price(const state,posState:integer):integer; begin result:=RangeEncoder.GetPrice0(_isRepG0[state]) + RangeEncoder.GetPrice0(_isRep0Long[(state shl ULZMABase.kNumPosStatesBitsMax) + posState]); end; function TLZMAEncoder.GetPureRepPrice(const repIndex, state, posState:integer):integer; var price:integer; begin if repIndex = 0 then begin price := RangeEncoder.GetPrice0(_isRepG0[state]); price := price + RangeEncoder.GetPrice1(_isRep0Long[(state shl ULZMABase.kNumPosStatesBitsMax) + posState]); end else begin price := RangeEncoder.GetPrice1(_isRepG0[state]); if repIndex = 1 then price := price + RangeEncoder.GetPrice0(_isRepG1[state]) else begin price := price + RangeEncoder.GetPrice1(_isRepG1[state]); price := price + RangeEncoder.GetPrice(_isRepG2[state], repIndex - 2); end; end; result:=price; end; function TLZMAEncoder.GetRepPrice(const repIndex, len, state, posState:integer):integer; var price:integer; begin price := _repMatchLenEncoder.GetPrice(len - ULZMABase.kMatchMinLen, posState); result := price + GetPureRepPrice(repIndex, state, posState); end; function TLZMAEncoder.GetPosLenPrice(const pos, len, posState:integer):integer; var price,lenToPosState:integer; begin lenToPosState := ULZMABase.GetLenToPosState(len); if pos < ULZMABase.kNumFullDistances then price := _distancesPrices[(lenToPosState * ULZMABase.kNumFullDistances) + pos] else price := _posSlotPrices[(lenToPosState shl ULZMABase.kNumPosSlotBits) + GetPosSlot2(pos)] + _alignPrices[pos and ULZMABase.kAlignMask]; result := price + _lenEncoder.GetPrice(len - ULZMABase.kMatchMinLen, posState); end; function TLZMAEncoder.Backward(cur:integer):integer; var posMem,backMem,posPrev,backCur:integer; begin _optimumEndIndex := cur; posMem := _optimum[cur].PosPrev; backMem := _optimum[cur].BackPrev; repeat if _optimum[cur].Prev1IsChar then begin _optimum[posMem].MakeAsChar; _optimum[posMem].PosPrev := posMem - 1; if _optimum[cur].Prev2 then begin _optimum[posMem - 1].Prev1IsChar := false; _optimum[posMem - 1].PosPrev := _optimum[cur].PosPrev2; _optimum[posMem - 1].BackPrev := _optimum[cur].BackPrev2; end; end; posPrev := posMem; backCur := backMem; backMem := _optimum[posPrev].BackPrev; posMem := _optimum[posPrev].PosPrev; _optimum[posPrev].BackPrev := backCur; _optimum[posPrev].PosPrev := cur; cur := posPrev; until not (cur > 0); backRes := _optimum[0].BackPrev; _optimumCurrentIndex := _optimum[0].PosPrev; result:=_optimumCurrentIndex; end; function TLZMAEncoder.GetOptimum(position:integer):integer; var lenRes,lenMain,numDistancePairs,numAvailableBytes,repMaxIndex,i:integer; matchPrice,repMatchPrice,shortRepPrice,lenEnd,len,repLen,price:integer; curAndLenPrice,normalMatchPrice,Offs,distance,cur,newLen:integer; posPrev,state,pos,curPrice,curAnd1Price,numAvailableBytesFull:integer; lenTest2,t,state2,posStateNext,nextRepMatchPrice,offset:integer; startLen,repIndex,lenTest,lenTestTemp,curAndLenCharPrice:integer; nextMatchPrice,curBack:integer; optimum,opt,nextOptimum:PLZMAOptimal; currentByte,matchByte,posState:byte; nextIsChar:boolean; begin if (_optimumEndIndex <> _optimumCurrentIndex) then begin lenRes := _optimum[_optimumCurrentIndex].PosPrev - _optimumCurrentIndex; backRes := _optimum[_optimumCurrentIndex].BackPrev; _optimumCurrentIndex := _optimum[_optimumCurrentIndex].PosPrev; result:=lenRes; exit; end;//if optimumendindex _optimumCurrentIndex := 0; _optimumEndIndex := 0; if not _longestMatchWasFound then begin lenMain := ReadMatchDistances(); end else begin //if not longest lenMain := _longestMatchLength; _longestMatchWasFound := false; end;//if not longest else numDistancePairs := _numDistancePairs; numAvailableBytes := _matchFinder.GetNumAvailableBytes + 1; if numAvailableBytes < 2 then begin backRes := -1; result:=1; exit; end;//if numavailable {if numAvailableBytes > ULZMABase.kMatchMaxLen then numAvailableBytes := ULZMABase.kMatchMaxLen;} repMaxIndex := 0; for i := 0 to ULZMABase.kNumRepDistances-1 do begin reps[i] := _repDistances[i]; repLens[i] := _matchFinder.GetMatchLen(0 - 1, reps[i], ULZMABase.kMatchMaxLen); if repLens[i] > repLens[repMaxIndex] then repMaxIndex := i; end;//for i if repLens[repMaxIndex] >= _numFastBytes then begin backRes := repMaxIndex; lenRes := repLens[repMaxIndex]; MovePos(lenRes - 1); result:=lenRes; exit; end;//if replens[] if lenMain >= _numFastBytes then begin backRes := _matchDistances[numDistancePairs - 1] + ULZMABase.kNumRepDistances; MovePos(lenMain - 1); result:=lenMain; exit; end;//if lenMain currentByte := _matchFinder.GetIndexByte(0 - 1); matchByte := _matchFinder.GetIndexByte(0 - _repDistances[0] - 1 - 1); if (lenMain < 2) and (currentByte <> matchByte) and (repLens[repMaxIndex] < 2) then begin backRes := -1; result:=1; exit; end;//if lenmain<2 _optimum[0].State := _state; posState := (position and _posStateMask); _optimum[1].Price := RangeEncoder.GetPrice0(_isMatch[(_state shl ULZMABase.kNumPosStatesBitsMax) + posState]) + _literalEncoder.GetSubCoder(position, _previousByte).GetPrice(not ULZMABase.StateIsCharState(_state), matchByte, currentByte); _optimum[1].MakeAsChar(); matchPrice := RangeEncoder.GetPrice1(_isMatch[(_state shl ULZMABase.kNumPosStatesBitsMax) + posState]); repMatchPrice := matchPrice + RangeEncoder.GetPrice1(_isRep[_state]); if matchByte = currentByte then begin shortRepPrice := repMatchPrice + GetRepLen1Price(_state, posState); if shortRepPrice < _optimum[1].Price then begin _optimum[1].Price := shortRepPrice; _optimum[1].MakeAsShortRep; end;//if shortrepprice end;//if matchbyte if lenMain >= repLens[repMaxIndex] then lenEnd:=lenMain else lenEnd:=repLens[repMaxIndex]; if lenEnd < 2 then begin backRes := _optimum[1].BackPrev; result:=1; exit; end;//if lenend<2 _optimum[1].PosPrev := 0; _optimum[0].Backs0 := reps[0]; _optimum[0].Backs1 := reps[1]; _optimum[0].Backs2 := reps[2]; _optimum[0].Backs3 := reps[3]; len := lenEnd; repeat _optimum[len].Price := kIfinityPrice; dec(len); until not (len >= 2); for i := 0 to ULZMABase.kNumRepDistances -1 do begin repLen := repLens[i]; if repLen < 2 then continue; price := repMatchPrice + GetPureRepPrice(i, _state, posState); repeat curAndLenPrice := price + _repMatchLenEncoder.GetPrice(repLen - 2, posState); optimum := _optimum[repLen]; if curAndLenPrice < optimum.Price then begin optimum.Price := curAndLenPrice; optimum.PosPrev := 0; optimum.BackPrev := i; optimum.Prev1IsChar := false; end;//if curandlenprice dec(replen); until not (repLen >= 2); end;//for i normalMatchPrice := matchPrice + RangeEncoder.GetPrice0(_isRep[_state]); if repLens[0] >= 2 then len:=repLens[0] + 1 else len:=2; if len <= lenMain then begin offs := 0; while len > _matchDistances[offs] do offs := offs + 2; while (true) do begin distance := _matchDistances[offs + 1]; curAndLenPrice := normalMatchPrice + GetPosLenPrice(distance, len, posState); optimum := _optimum[len]; if curAndLenPrice < optimum.Price then begin optimum.Price := curAndLenPrice; optimum.PosPrev := 0; optimum.BackPrev := distance + ULZMABase.kNumRepDistances; optimum.Prev1IsChar := false; end;//if curlenandprice if len = _matchDistances[offs] then begin offs := offs + 2; if offs = numDistancePairs then break; end;//if len=_match inc(len); end;//while (true) end;//if len<=lenmain cur := 0; while (true) do begin inc(cur); if cur = lenEnd then begin result:=Backward(cur); exit; end;//if cur=lenEnd newLen := ReadMatchDistances; numDistancePairs := _numDistancePairs; if newLen >= _numFastBytes then begin _longestMatchLength := newLen; _longestMatchWasFound := true; result:=Backward(cur); exit; end;//if newlen=_numfast inc(position); posPrev := _optimum[cur].PosPrev; if _optimum[cur].Prev1IsChar then begin dec(posPrev); if _optimum[cur].Prev2 then begin state := _optimum[_optimum[cur].PosPrev2].State; if _optimum[cur].BackPrev2 < ULZMABase.kNumRepDistances then state := ULZMABase.StateUpdateRep(state) else state := ULZMABase.StateUpdateMatch(state); end//if _optimum[cur].Prev2 else state := _optimum[posPrev].State; state := ULZMABase.StateUpdateChar(state); end//if _optimum[cur].Prev1IsChar else state := _optimum[posPrev].State; if posPrev = cur - 1 then begin if _optimum[cur].IsShortRep then state := ULZMABase.StateUpdateShortRep(state) else state := ULZMABase.StateUpdateChar(state); end //if posPrev = cur - 1 else begin if _optimum[cur].Prev1IsChar and _optimum[cur].Prev2 then begin posPrev := _optimum[cur].PosPrev2; pos := _optimum[cur].BackPrev2; state := ULZMABase.StateUpdateRep(state); end//if _optimum[cur].Prev1IsChar else begin pos := _optimum[cur].BackPrev; if pos < ULZMABase.kNumRepDistances then state := ULZMABase.StateUpdateRep(state) else state := ULZMABase.StateUpdateMatch(state); end;//if else _optimum[cur].Prev1IsChar opt := _optimum[posPrev]; if pos < ULZMABase.kNumRepDistances then begin if pos = 0 then begin reps[0] := opt.Backs0; reps[1] := opt.Backs1; reps[2] := opt.Backs2; reps[3] := opt.Backs3; end//if pos=0 else if pos = 1 then begin reps[0] := opt.Backs1; reps[1] := opt.Backs0; reps[2] := opt.Backs2; reps[3] := opt.Backs3; end //if pos=1 else if pos = 2 then begin reps[0] := opt.Backs2; reps[1] := opt.Backs0; reps[2] := opt.Backs1; reps[3] := opt.Backs3; end//if pos=2 else begin reps[0] := opt.Backs3; reps[1] := opt.Backs0; reps[2] := opt.Backs1; reps[3] := opt.Backs2; end;//else if pos= end// if pos < ULZMABase.kNumRepDistances else begin reps[0] := (pos - ULZMABase.kNumRepDistances); reps[1] := opt.Backs0; reps[2] := opt.Backs1; reps[3] := opt.Backs2; end;//if else pos < ULZMABase.kNumRepDistances end;//if else posPrev = cur - 1 _optimum[cur].State := state; _optimum[cur].Backs0 := reps[0]; _optimum[cur].Backs1 := reps[1]; _optimum[cur].Backs2 := reps[2]; _optimum[cur].Backs3 := reps[3]; curPrice := _optimum[cur].Price; currentByte := _matchFinder.GetIndexByte(0 - 1); matchByte := _matchFinder.GetIndexByte(0 - reps[0] - 1 - 1); posState := (position and _posStateMask); curAnd1Price := curPrice + RangeEncoder.GetPrice0(_isMatch[(state shl ULZMABase.kNumPosStatesBitsMax) + posState]) + _literalEncoder.GetSubCoder(position, _matchFinder.GetIndexByte(0 - 2)). GetPrice(not ULZMABase.StateIsCharState(state), matchByte, currentByte); nextOptimum := _optimum[cur + 1]; nextIsChar := false; if curAnd1Price < nextOptimum.Price then begin nextOptimum.Price := curAnd1Price; nextOptimum.PosPrev := cur; nextOptimum.MakeAsChar; nextIsChar := true; end;//if curand1price matchPrice := curPrice + RangeEncoder.GetPrice1(_isMatch[(state shl ULZMABase.kNumPosStatesBitsMax) + posState]); repMatchPrice := matchPrice + RangeEncoder.GetPrice1(_isRep[state]); if (matchByte = currentByte) and (not ((nextOptimum.PosPrev < cur) and (nextOptimum.BackPrev = 0))) then begin shortRepPrice := repMatchPrice + GetRepLen1Price(state, posState); if shortRepPrice <= nextOptimum.Price then begin nextOptimum.Price := shortRepPrice; nextOptimum.PosPrev := cur; nextOptimum.MakeAsShortRep; nextIsChar := true; end;//if shortRepPrice <= nextOptimum.Price end;//if (matchByte = currentByte) and numAvailableBytesFull := _matchFinder.GetNumAvailableBytes + 1; numAvailableBytesFull := min(kNumOpts - 1 - cur, numAvailableBytesFull); numAvailableBytes := numAvailableBytesFull; if numAvailableBytes < 2 then continue; if numAvailableBytes > _numFastBytes then numAvailableBytes := _numFastBytes; if (not nextIsChar) and (matchByte <> currentByte) then begin // try Literal + rep0 t := min(numAvailableBytesFull - 1, _numFastBytes); lenTest2 := _matchFinder.GetMatchLen(0, reps[0], t); if lenTest2 >= 2 then begin state2 := ULZMABase.StateUpdateChar(state); posStateNext := (position + 1) and _posStateMask; nextRepMatchPrice := curAnd1Price + RangeEncoder.GetPrice1(_isMatch[(state2 shl ULZMABase.kNumPosStatesBitsMax) + posStateNext]) + RangeEncoder.GetPrice1(_isRep[state2]); begin offset := cur + 1 + lenTest2; while lenEnd < offset do begin inc(lenEnd); _optimum[lenEnd].Price := kIfinityPrice; end;//while lenend curAndLenPrice := nextRepMatchPrice + GetRepPrice( 0, lenTest2, state2, posStateNext); optimum := _optimum[offset]; if curAndLenPrice < optimum.Price then begin optimum.Price := curAndLenPrice; optimum.PosPrev := cur + 1; optimum.BackPrev := 0; optimum.Prev1IsChar := true; optimum.Prev2 := false; end;//if curandlenprice end;//none end;//if lentest end;//if not nextischar and ... startLen := 2; // speed optimization for repIndex := 0 to ULZMABase.kNumRepDistances -1 do begin lenTest := _matchFinder.GetMatchLen(0 - 1, reps[repIndex], numAvailableBytes); if lenTest < 2 then continue; lenTestTemp := lenTest; repeat while lenEnd < cur + lenTest do begin inc(lenEnd); _optimum[lenEnd].Price := kIfinityPrice; end;//while lenEnd curAndLenPrice := repMatchPrice + GetRepPrice(repIndex, lenTest, state, posState); optimum := _optimum[cur + lenTest]; if curAndLenPrice < optimum.Price then begin optimum.Price := curAndLenPrice; optimum.PosPrev := cur; optimum.BackPrev := repIndex; optimum.Prev1IsChar := false; end;//if curandlen dec(lenTest); until not (lenTest >= 2); lenTest := lenTestTemp; if repIndex = 0 then startLen := lenTest + 1; // if (_maxMode) if lenTest < numAvailableBytesFull then begin t := min(numAvailableBytesFull - 1 - lenTest, _numFastBytes); lenTest2 := _matchFinder.GetMatchLen(lenTest, reps[repIndex], t); if lenTest2 >= 2 then begin state2 := ULZMABase.StateUpdateRep(state); posStateNext := (position + lenTest) and _posStateMask; curAndLenCharPrice := repMatchPrice + GetRepPrice(repIndex, lenTest, state, posState) + RangeEncoder.GetPrice0(_isMatch[(state2 shl ULZMABase.kNumPosStatesBitsMax) + posStateNext]) + _literalEncoder.GetSubCoder(position + lenTest, _matchFinder.GetIndexByte(lenTest - 1 - 1)).GetPrice(true, _matchFinder.GetIndexByte(lenTest - 1 - (reps[repIndex] + 1)), _matchFinder.GetIndexByte(lenTest - 1)); state2 := ULZMABase.StateUpdateChar(state2); posStateNext := (position + lenTest + 1) and _posStateMask; nextMatchPrice := curAndLenCharPrice + RangeEncoder.GetPrice1(_isMatch[(state2 shl ULZMABase.kNumPosStatesBitsMax) + posStateNext]); nextRepMatchPrice := nextMatchPrice + RangeEncoder.GetPrice1(_isRep[state2]); // for(; lenTest2 >= 2; lenTest2--) begin offset := lenTest + 1 + lenTest2; while lenEnd < cur + offset do begin inc(lenEnd); _optimum[lenEnd].Price := kIfinityPrice; end;//while lenEnd curAndLenPrice := nextRepMatchPrice + GetRepPrice(0, lenTest2, state2, posStateNext); optimum := _optimum[cur + offset]; if curAndLenPrice < optimum.Price then begin optimum.Price := curAndLenPrice; optimum.PosPrev := cur + lenTest + 1; optimum.BackPrev := 0; optimum.Prev1IsChar := true; optimum.Prev2 := true; optimum.PosPrev2 := cur; optimum.BackPrev2 := repIndex; end;//if curAndLenPrice < optimum.Price end;//none end;//if lenTest2 >= 2 end;//if lenTest < numAvailableBytesFull end;//for repIndex if newLen > numAvailableBytes then begin newLen := numAvailableBytes; numDistancePairs := 0; while newLen > _matchDistances[numDistancePairs] do numDistancePairs := numDistancePairs + 2; _matchDistances[numDistancePairs] := newLen; numDistancePairs := numDistancePairs + 2; end;//if newLen > numAvailableBytes if newLen >= startLen then begin normalMatchPrice := matchPrice + RangeEncoder.GetPrice0(_isRep[state]); while lenEnd < cur + newLen do begin inc(lenEnd); _optimum[lenEnd].Price := kIfinityPrice; end;//while lenEnd offs := 0; while startLen > _matchDistances[offs] do offs := offs + 2; lenTest := startLen; while (true) do begin curBack := _matchDistances[offs + 1]; curAndLenPrice := normalMatchPrice + GetPosLenPrice(curBack, lenTest, posState); optimum := _optimum[cur + lenTest]; if curAndLenPrice < optimum.Price then begin optimum.Price := curAndLenPrice; optimum.PosPrev := cur; optimum.BackPrev := curBack + ULZMABase.kNumRepDistances; optimum.Prev1IsChar := false; end;//if curAndLenPrice < optimum.Price if lenTest = _matchDistances[offs] then begin if lenTest < numAvailableBytesFull then begin t := min(numAvailableBytesFull - 1 - lenTest, _numFastBytes); lenTest2 := _matchFinder.GetMatchLen(lenTest, curBack, t); if lenTest2 >= 2 then begin state2 := ULZMABase.StateUpdateMatch(state); posStateNext := (position + lenTest) and _posStateMask; curAndLenCharPrice := curAndLenPrice + RangeEncoder.GetPrice0(_isMatch[(state2 shl ULZMABase.kNumPosStatesBitsMax) + posStateNext]) + _literalEncoder.GetSubCoder(position + lenTest, _matchFinder.GetIndexByte(lenTest - 1 - 1)). GetPrice(true, _matchFinder.GetIndexByte(lenTest - (curBack + 1) - 1), _matchFinder.GetIndexByte(lenTest - 1)); state2 := ULZMABase.StateUpdateChar(state2); posStateNext := (position + lenTest + 1) and _posStateMask; nextMatchPrice := curAndLenCharPrice + RangeEncoder.GetPrice1(_isMatch[(state2 shl ULZMABase.kNumPosStatesBitsMax) + posStateNext]); nextRepMatchPrice := nextMatchPrice + RangeEncoder.GetPrice1(_isRep[state2]); offset := lenTest + 1 + lenTest2; while lenEnd < cur + offset do begin inc(lenEnd); _optimum[lenEnd].Price := kIfinityPrice; end;//while lenEnd curAndLenPrice := nextRepMatchPrice + GetRepPrice(0, lenTest2, state2, posStateNext); optimum := _optimum[cur + offset]; if curAndLenPrice < optimum.Price then begin optimum.Price := curAndLenPrice; optimum.PosPrev := cur + lenTest + 1; optimum.BackPrev := 0; optimum.Prev1IsChar := true; optimum.Prev2 := true; optimum.PosPrev2 := cur; optimum.BackPrev2 := curBack + ULZMABase.kNumRepDistances; end;//if curAndLenPrice < optimum.Price end;//if lenTest2 >= 2 end;//lenTest < numAvailableBytesFull offs :=offs + 2; if offs = numDistancePairs then break; end;//if lenTest = _matchDistances[offs] inc(lenTest); end;//while(true) end;//if newLen >= startLen end;//while (true) end; function TLZMAEncoder.ChangePair(const smallDist, bigDist:integer):boolean; var kDif:integer; begin kDif := 7; result:= (smallDist < (1 shl (32 - kDif))) and (bigDist >= (smallDist shl kDif)); end; procedure TLZMAEncoder.WriteEndMarker(const posState:integer); var len,posSlot,lenToPosState,footerBits,posReduced:integer; begin if not _writeEndMark then exit; _rangeEncoder.Encode(_isMatch, (_state shl ULZMABase.kNumPosStatesBitsMax) + posState, 1); _rangeEncoder.Encode(_isRep, _state, 0); _state := ULZMABase.StateUpdateMatch(_state); len := ULZMABase.kMatchMinLen; _lenEncoder.Encode(_rangeEncoder, len - ULZMABase.kMatchMinLen, posState); posSlot := (1 shl ULZMABase.kNumPosSlotBits) - 1; lenToPosState := ULZMABase.GetLenToPosState(len); _posSlotEncoder[lenToPosState].Encode(_rangeEncoder, posSlot); footerBits := 30; posReduced := (1 shl footerBits) - 1; _rangeEncoder.EncodeDirectBits(posReduced shr ULZMABase.kNumAlignBits, footerBits - ULZMABase.kNumAlignBits); _posAlignEncoder.ReverseEncode(_rangeEncoder, posReduced and ULZMABase.kAlignMask); end; procedure TLZMAEncoder.Flush(const nowPos:integer); begin ReleaseMFStream; WriteEndMarker(nowPos and _posStateMask); _rangeEncoder.FlushData(); _rangeEncoder.FlushStream(); end; procedure TLZMAEncoder.CodeOneBlock(var inSize,outSize:int64;var Afinished:boolean); var progressPosValuePrev:int64; posState,len,pos,complexState,distance,i,posSlot,lenToPosState:integer; footerBits,baseVal,posReduced:integer; curByte,matchByte:byte; subcoder:PLZMAEncoder2; begin inSize := 0; outSize := 0; Afinished := true; if _inStream <>nil then begin _matchFinder.SetStream(_inStream); _matchFinder._Init; _needReleaseMFStream := true; _inStream := nil; end; if _finished then exit; _finished := true; progressPosValuePrev := nowPos64; if nowPos64 = 0 then begin if _matchFinder.GetNumAvailableBytes = 0 then begin Flush(nowPos64); exit; end; ReadMatchDistances; posState := integer(nowPos64) and _posStateMask; _rangeEncoder.Encode(_isMatch, (_state shl ULZMABase.kNumPosStatesBitsMax) + posState, 0); _state := ULZMABase.StateUpdateChar(_state); curByte := _matchFinder.GetIndexByte(0 - _additionalOffset); _literalEncoder.GetSubCoder(integer(nowPos64), _previousByte).Encode(_rangeEncoder, curByte); _previousByte := curByte; dec(_additionalOffset); inc(nowPos64); end; if _matchFinder.GetNumAvailableBytes = 0 then begin Flush(integer(nowPos64)); exit; end; while true do begin len := GetOptimum(integer(nowPos64)); pos := backRes; posState := integer(nowPos64) and _posStateMask; complexState := (_state shl ULZMABase.kNumPosStatesBitsMax) + posState; if (len = 1) and (pos = -1) then begin _rangeEncoder.Encode(_isMatch, complexState, 0); curByte := _matchFinder.GetIndexByte(0 - _additionalOffset); subCoder := _literalEncoder.GetSubCoder(integer(nowPos64), _previousByte); if not ULZMABase.StateIsCharState(_state) then begin matchByte := _matchFinder.GetIndexByte(0 - _repDistances[0] - 1 - _additionalOffset); subCoder.EncodeMatched(_rangeEncoder, matchByte, curByte); end else subCoder.Encode(_rangeEncoder, curByte); _previousByte := curByte; _state := ULZMABase.StateUpdateChar(_state); end else begin _rangeEncoder.Encode(_isMatch, complexState, 1); if pos < ULZMABase.kNumRepDistances then begin _rangeEncoder.Encode(_isRep, _state, 1); if pos = 0 then begin _rangeEncoder.Encode(_isRepG0, _state, 0); if len = 1 then _rangeEncoder.Encode(_isRep0Long, complexState, 0) else _rangeEncoder.Encode(_isRep0Long, complexState, 1); end else begin _rangeEncoder.Encode(_isRepG0, _state, 1); if pos = 1 then _rangeEncoder.Encode(_isRepG1, _state, 0) else begin _rangeEncoder.Encode(_isRepG1, _state, 1); _rangeEncoder.Encode(_isRepG2, _state, pos - 2); end; end; if len = 1 then _state := ULZMABase.StateUpdateShortRep(_state) else begin _repMatchLenEncoder.Encode(_rangeEncoder, len - ULZMABase.kMatchMinLen, posState); _state := ULZMABase.StateUpdateRep(_state); end; distance := _repDistances[pos]; if pos <> 0 then begin for i := pos downto 1 do _repDistances[i] := _repDistances[i - 1]; _repDistances[0] := distance; end; end else begin _rangeEncoder.Encode(_isRep, _state, 0); _state := ULZMABase.StateUpdateMatch(_state); _lenEncoder.Encode(_rangeEncoder, len - ULZMABase.kMatchMinLen, posState); pos := pos - ULZMABase.kNumRepDistances; posSlot := GetPosSlot(pos); lenToPosState := ULZMABase.GetLenToPosState(len); _posSlotEncoder[lenToPosState].Encode(_rangeEncoder, posSlot); if posSlot >= ULZMABase.kStartPosModelIndex then begin footerBits := integer((posSlot shr 1) - 1); baseVal := ((2 or (posSlot and 1)) shl footerBits); posReduced := pos - baseVal; if posSlot < ULZMABase.kEndPosModelIndex then UBitTreeEncoder.ReverseEncode(_posEncoders, baseVal - posSlot - 1, _rangeEncoder, footerBits, posReduced) else begin _rangeEncoder.EncodeDirectBits(posReduced shr ULZMABase.kNumAlignBits, footerBits - ULZMABase.kNumAlignBits); _posAlignEncoder.ReverseEncode(_rangeEncoder, posReduced and ULZMABase.kAlignMask); inc(_alignPriceCount); end; end; distance := pos; for i := ULZMABase.kNumRepDistances - 1 downto 1 do _repDistances[i] := _repDistances[i - 1]; _repDistances[0] := distance; inc(_matchPriceCount); end; _previousByte := _matchFinder.GetIndexByte(len - 1 - _additionalOffset); end; _additionalOffset := _additionalOffset - len; nowPos64 := nowPos64 + len; if _additionalOffset = 0 then begin // if (!_fastMode) if _matchPriceCount >= (1 shl 7) then FillDistancesPrices; if _alignPriceCount >= ULZMABase.kAlignTableSize then FillAlignPrices; inSize := nowPos64; outSize := _rangeEncoder.GetProcessedSizeAdd; if _matchFinder.GetNumAvailableBytes = 0 then begin Flush(integer(nowPos64)); exit; end; if (nowPos64 - progressPosValuePrev >= (1 shl 12)) then begin _finished := false; Afinished := false; exit; end; end; end; end; procedure TLZMAEncoder.ReleaseMFStream; begin if (_matchFinder <>nil) and _needReleaseMFStream then begin _matchFinder.ReleaseStream; _needReleaseMFStream := false; end; end; procedure TLZMAEncoder.SetOutStream(const outStream:PStream); begin _rangeEncoder.SetStream(outStream); end; procedure TLZMAEncoder.ReleaseOutStream; begin _rangeEncoder.ReleaseStream; end; procedure TLZMAEncoder.ReleaseStreams; begin ReleaseMFStream; ReleaseOutStream; end; procedure TLZMAEncoder.SetStreams(const inStream, outStream:PStream;const inSize, outSize:int64); begin _inStream := inStream; _finished := false; _Create(); SetOutStream(outStream); _Init(); // if (!_fastMode) FillDistancesPrices; FillAlignPrices; _lenEncoder.SetTableSize(_numFastBytes + 1 - ULZMABase.kMatchMinLen); _lenEncoder.UpdateTables(1 shl _posStateBits); _repMatchLenEncoder.SetTableSize(_numFastBytes + 1 - ULZMABase.kMatchMinLen); _repMatchLenEncoder.UpdateTables(1 shl _posStateBits); nowPos64 := 0; end; procedure TLZMAEncoder.Code(const inStream, outStream:PStream;const inSize, outSize:int64); var lpos:int64; progint:int64; inputsize:int64; begin if insize=-1 then inputsize:=instream.Size-instream.Position else inputsize:=insize; progint:=inputsize div CodeProgressInterval; lpos:=progint; _needReleaseMFStream := false; DoProgress(LPAMax,inputsize); try SetStreams(inStream, outStream, inSize, outSize); while true do begin CodeOneBlock(processedInSize, processedOutSize, finished); if finished then begin DoProgress(LPAPos,inputsize); exit; end; if (processedInSize>=lpos) then begin DoProgress(LPAPos,processedInSize); lpos:=lpos+progint; end; end; finally ReleaseStreams(); end; end; procedure TLZMAEncoder.WriteCoderProperties(const outStream:PStream); var i:integer; begin properties[0] := (_posStateBits * 5 + _numLiteralPosStateBits) * 9 + _numLiteralContextBits; for i := 0 to 3 do properties[1 + i] := (_dictionarySize shr (8 * i)); outStream.write(properties, kPropSize); end; procedure TLZMAEncoder.FillDistancesPrices; var i,posSlot,footerBits,baseVal,lenToPosState,st,st2:integer; encoder:PBitTreeEncoder; begin for i := ULZMABase.kStartPosModelIndex to ULZMABase.kNumFullDistances -1 do begin posSlot := GetPosSlot(i); footerBits := integer((posSlot shr 1) - 1); baseVal := (2 or (posSlot and 1)) shl footerBits; tempPrices[i] := ReverseGetPrice(_posEncoders, baseVal - posSlot - 1, footerBits, i - baseVal); end; for lenToPosState := 0 to ULZMABase.kNumLenToPosStates -1 do begin encoder := _posSlotEncoder[lenToPosState]; st := (lenToPosState shl ULZMABase.kNumPosSlotBits); for posSlot := 0 to _distTableSize -1 do _posSlotPrices[st + posSlot] := encoder.GetPrice(posSlot); for posSlot := ULZMABase.kEndPosModelIndex to _distTableSize -1 do _posSlotPrices[st + posSlot] := _posSlotPrices[st + posSlot] + ((((posSlot shr 1) - 1) - ULZMABase.kNumAlignBits) shl kNumBitPriceShiftBits); st2 := lenToPosState * ULZMABase.kNumFullDistances; for i := 0 to ULZMABase.kStartPosModelIndex -1 do _distancesPrices[st2 + i] := _posSlotPrices[st + i]; for i := ULZMABase.kStartPosModelIndex to ULZMABase.kNumFullDistances-1 do _distancesPrices[st2 + i] := _posSlotPrices[st + GetPosSlot(i)] + tempPrices[i]; end; _matchPriceCount := 0; end; procedure TLZMAEncoder.FillAlignPrices; var i:integer; begin for i := 0 to ULZMABase.kAlignTableSize -1 do _alignPrices[i] := _posAlignEncoder.ReverseGetPrice(i); _alignPriceCount := 0; end; function TLZMAEncoder.SetAlgorithm(const algorithm:integer):boolean; begin { _fastMode = (algorithm == 0); _maxMode = (algorithm >= 2); } result:=true; end; function TLZMAEncoder.SetDictionarySize(dictionarySize:Cardinal):boolean; var kDicLogSizeMaxCompress,dicLogSize:integer; begin kDicLogSizeMaxCompress := 29; if (dictionarySize < (1 shl ULZMABase.kDicLogSizeMin)) or (dictionarySize > (1 shl kDicLogSizeMaxCompress)) then begin result:=false; exit; end; _dictionarySize := dictionarySize; dicLogSize := 0; while dictionarySize > (1 shl dicLogSize) do inc(dicLogSize); _distTableSize := dicLogSize * 2; result:=true; end; function TLZMAEncoder.SeNumFastBytes(const numFastBytes:integer):boolean; begin if (numFastBytes < 5) or (numFastBytes > ULZMABase.kMatchMaxLen) then begin result:=false; exit; end; _numFastBytes := numFastBytes; result:=true; end; function TLZMAEncoder.SetMatchFinder(const matchFinderIndex:integer):boolean; var matchFinderIndexPrev:integer; begin if (matchFinderIndex < 0) or (matchFinderIndex > 2) then begin result:=false; exit; end; matchFinderIndexPrev := _matchFinderType; _matchFinderType := matchFinderIndex; if (_matchFinder <> nil) and (matchFinderIndexPrev <> _matchFinderType) then begin _dictionarySizePrev := -1; _matchFinder := nil; end; result:=true; end; function TLZMAEncoder.SetLcLpPb(const lc,lp,pb:integer):boolean; begin if (lp < 0) or (lp > ULZMABase.kNumLitPosStatesBitsEncodingMax) or (lc < 0) or (lc > ULZMABase.kNumLitContextBitsMax) or (pb < 0) or (pb > ULZMABase.kNumPosStatesBitsEncodingMax) then begin result:=false; exit; end; _numLiteralPosStateBits := lp; _numLiteralContextBits := lc; _posStateBits := pb; _posStateMask := ((1) shl _posStateBits) - 1; result:=true; end; procedure TLZMAEncoder.SetEndMarkerMode(const endMarkerMode:boolean); begin _writeEndMark := endMarkerMode; end; procedure TLZMAEncoder2._Init; begin URangeEncoder.InitBitModels(m_Encoders); end; procedure TLZMAEncoder2.Encode(const rangeEncoder:PRangeEncoder;const symbol:byte); var context:integer; bit,i:integer; begin context := 1; for i := 7 downto 0 do begin bit := ((symbol shr i) and 1); rangeEncoder.Encode(m_Encoders, context, bit); context := (context shl 1) or bit; end; end; procedure TLZMAEncoder2.EncodeMatched(const rangeEncoder:PRangeEncoder;const matchByte,symbol:byte); var context,i,bit,state,matchbit:integer; same:boolean; begin context := 1; same := true; for i := 7 downto 0 do begin bit := ((symbol shr i) and 1); state := context; if same then begin matchBit := ((matchByte shr i) and 1); state :=state + ((1 + matchBit) shl 8); same := (matchBit = bit); end; rangeEncoder.Encode(m_Encoders, state, bit); context := (context shl 1) or bit; end; end; function TLZMAEncoder2.GetPrice(const matchMode:boolean;const matchByte,symbol:byte):integer; var price,context,i,matchbit,bit:integer; begin price := 0; context := 1; i := 7; if matchMode then while i>=0 do begin matchBit := (matchByte shr i) and 1; bit := (symbol shr i) and 1; price := price + RangeEncoder.GetPrice(m_Encoders[((1 + matchBit) shl 8) + context], bit); context := (context shl 1) or bit; if (matchBit <> bit) then begin dec(i); break; end; dec(i); end; while i>=0 do begin bit := (symbol shr i) and 1; price := price + RangeEncoder.GetPrice(m_Encoders[context], bit); context := (context shl 1) or bit; dec(i); end; result:=price; end; procedure TLZMALiteralEncoder._Create(const numPosBits,numPrevBits:integer); var numstates:integer; i:integer; begin if (length(m_Coders)<>0) and (m_NumPrevBits = numPrevBits) and (m_NumPosBits = numPosBits) then exit; m_NumPosBits := numPosBits; m_PosMask := (1 shl numPosBits) - 1; m_NumPrevBits := numPrevBits; numStates := 1 shl (m_NumPrevBits + m_NumPosBits); setlength(m_coders,numStates); for i := 0 to numStates-1 do New(m_Coders[i],Create); end; destructor TLZMALiteralEncoder.Destroy; var i:integer; begin for i:=low(m_Coders) to high(m_Coders) do if m_Coders[i]<>nil then m_Coders[i].Free; inherited; end; procedure TLZMALiteralEncoder._Init; var numstates,i:integer; begin numStates := 1 shl (m_NumPrevBits + m_NumPosBits); for i := 0 to numStates-1 do m_Coders[i]._Init; end; function TLZMALiteralEncoder.GetSubCoder(const pos:integer;const prevByte:byte):PLZMAEncoder2; begin result:=m_Coders[((pos and m_PosMask) shl m_NumPrevBits) + ((prevByte and $FF) shr (8 - m_NumPrevBits))]; end; constructor TLZMALenEncoder.Create; var posState:integer; begin New(_highCoder, Create(ULZMABase.kNumHighLenBits)); for posState := 0 to ULZMABase.kNumPosStatesEncodingMax-1 do begin New(_lowCoder[posState], Create(ULZMABase.kNumLowLenBits)); New(_midCoder[posState], Create(ULZMABase.kNumMidLenBits)); end; end; destructor TLZMALenEncoder.Destroy; var posState:integer; begin _highCoder.Free; for posState := 0 to ULZMABase.kNumPosStatesEncodingMax-1 do begin _lowCoder[posState].Free; _midCoder[posState].Free; end; inherited; end; procedure TLZMALenEncoder._Init(const numPosStates:integer); var posState:integer; begin URangeEncoder.InitBitModels(_choice); for posState := 0 to numPosStates -1 do begin _lowCoder[posState]._Init; _midCoder[posState]._Init; end; _highCoder._Init; end; procedure TLZMALenEncoder.Encode(const rangeEncoder:PRangeEncoder;symbol:integer;const posState:integer); begin if (symbol < ULZMABase.kNumLowLenSymbols) then begin rangeEncoder.Encode(_choice, 0, 0); _lowCoder[posState].Encode(rangeEncoder, symbol); end else begin symbol := symbol - ULZMABase.kNumLowLenSymbols; rangeEncoder.Encode(_choice, 0, 1); if symbol < ULZMABase.kNumMidLenSymbols then begin rangeEncoder.Encode(_choice, 1, 0); _midCoder[posState].Encode(rangeEncoder, symbol); end else begin rangeEncoder.Encode(_choice, 1, 1); _highCoder.Encode(rangeEncoder, symbol - ULZMABase.kNumMidLenSymbols); end; end; end; procedure TLZMALenEncoder.SetPrices(const posState,numSymbols:integer;var prices:array of integer;const st:integer); var a0,a1,b0,b1,i:integer; begin a0 := RangeEncoder.GetPrice0(_choice[0]); a1 := RangeEncoder.GetPrice1(_choice[0]); b0 := a1 + RangeEncoder.GetPrice0(_choice[1]); b1 := a1 + RangeEncoder.GetPrice1(_choice[1]); i:=0; while i= numSymbols then exit; prices[st + i] := a0 + _lowCoder[posState].GetPrice(i); inc(i); end; while i < ULZMABase.kNumLowLenSymbols + ULZMABase.kNumMidLenSymbols do begin if i >= numSymbols then exit; prices[st + i] := b0 + _midCoder[posState].GetPrice(i - ULZMABase.kNumLowLenSymbols); inc(i); end; while i < numSymbols do begin prices[st + i] := b1 + _highCoder.GetPrice(i - ULZMABase.kNumLowLenSymbols - ULZMABase.kNumMidLenSymbols); inc(i); end; end; procedure TLZMALenPriceTableEncoder.SetTableSize(const tableSize:integer); begin _tableSize := tableSize; end; function TLZMALenPriceTableEncoder.GetPrice(const symbol,posState:integer):integer; begin result:=_prices[posState * ULZMABase.kNumLenSymbols + symbol] end; procedure TLZMALenPriceTableEncoder.UpdateTable(const posState:integer); begin SetPrices(posState, _tableSize, _prices, posState * ULZMABase.kNumLenSymbols); _counters[posState] := _tableSize; end; procedure TLZMALenPriceTableEncoder.UpdateTables(const numPosStates:integer); var posState:integer; begin for posState := 0 to numPosStates -1 do UpdateTable(posState); end; procedure TLZMALenPriceTableEncoder.Encode(const rangeEncoder:PRangeEncoder;symbol:integer;const posState:integer); begin inherited Encode(rangeEncoder, symbol, posState); dec(_counters[posState]); if (_counters[posState] = 0) then UpdateTable(posState); end; procedure TLZMAOptimal.MakeAsChar; begin BackPrev := -1; Prev1IsChar := false; end; procedure TLZMAOptimal.MakeAsShortRep; begin BackPrev := 0; Prev1IsChar := false; end; function TLZMAOptimal.IsShortRep:boolean; begin result:=BackPrev = 0; end; procedure TLZMAEncoder.DoProgress(const Action:TLZMAProgressAction;const Value:integer); begin if assigned(fonprogress) then fonprogress(action,value); end; end.