3 #ifndef __LZMA_ENCODER_H
4 #define __LZMA_ENCODER_H
6 #include "../../../Common/MyCom.h"
7 #include "../../../Common/Alloc.h"
8 #include "../../ICoder.h"
9 #include "../LZ/IMatchFinder.h"
10 #include "../RangeCoder/RangeCoderBitTree.h"
17 typedef NRangeCoder::CBitEncoder
<kNumMoveBits
> CMyBitEncoder
;
24 UInt32 _repDistances
[kNumRepDistances
];
29 for(UInt32 i
= 0 ; i
< kNumRepDistances
; i
++)
45 UInt32 PosPrev
; // posNext;
47 UInt32 Backs
[kNumRepDistances
];
48 void MakeAsChar() { BackPrev
= UInt32(-1); Prev1IsChar
= false; }
49 void MakeAsShortRep() { BackPrev
= 0; ; Prev1IsChar
= false; }
50 bool IsShortRep() { return (BackPrev
== 0); }
54 extern Byte g_FastPos
[1024];
55 inline UInt32
GetPosSlot(UInt32 pos
)
58 return g_FastPos
[pos
];
60 return g_FastPos
[pos
>> 9] + 18;
61 return g_FastPos
[pos
>> 18] + 36;
64 inline UInt32
GetPosSlot2(UInt32 pos
)
67 return g_FastPos
[pos
>> 6] + 12;
69 return g_FastPos
[pos
>> 15] + 30;
70 return g_FastPos
[pos
>> 24] + 48;
73 const UInt32 kIfinityPrice
= 0xFFFFFFF;
75 const UInt32 kNumOpts
= 1 << 12;
78 class CLiteralEncoder2
80 CMyBitEncoder _encoders
[0x300];
84 for (int i
= 0; i
< 0x300; i
++)
87 void Encode(NRangeCoder::CEncoder
*rangeEncoder
, Byte symbol
);
88 void EncodeMatched(NRangeCoder::CEncoder
*rangeEncoder
, Byte matchByte
, Byte symbol
);
89 UInt32
GetPrice(bool matchMode
, Byte matchByte
, Byte symbol
) const;
94 CLiteralEncoder2
*_coders
;
99 CLiteralEncoder(): _coders(0) {}
100 ~CLiteralEncoder() { Free(); }
106 bool Create(int numPosBits
, int numPrevBits
)
108 if (_coders
== 0 || (numPosBits
+ numPrevBits
) !=
109 (_numPrevBits
+ _numPosBits
) )
112 UInt32 numStates
= 1 << (numPosBits
+ numPrevBits
);
113 _coders
= (CLiteralEncoder2
*)MyAlloc(numStates
* sizeof(CLiteralEncoder2
));
115 _numPosBits
= numPosBits
;
116 _posMask
= (1 << numPosBits
) - 1;
117 _numPrevBits
= numPrevBits
;
118 return (_coders
!= 0);
122 UInt32 numStates
= 1 << (_numPrevBits
+ _numPosBits
);
123 for (UInt32 i
= 0; i
< numStates
; i
++)
126 UInt32
GetState(UInt32 pos
, Byte prevByte
) const
127 { return ((pos
& _posMask
) << _numPrevBits
) + (prevByte
>> (8 - _numPrevBits
)); }
128 CLiteralEncoder2
*GetSubCoder(UInt32 pos
, Byte prevByte
)
129 { return &_coders
[GetState(pos
, prevByte
)]; }
131 void Encode(NRangeCoder::CEncoder *rangeEncoder, UInt32 pos, Byte prevByte,
133 { _coders[GetState(pos, prevByte)].Encode(rangeEncoder, symbol); }
134 void EncodeMatched(NRangeCoder::CEncoder *rangeEncoder, UInt32 pos, Byte prevByte,
135 Byte matchByte, Byte symbol)
136 { _coders[GetState(pos, prevByte)].Encode(rangeEncoder,
137 matchByte, symbol); }
139 UInt32
GetPrice(UInt32 pos
, Byte prevByte
, bool matchMode
, Byte matchByte
, Byte symbol
) const
140 { return _coders
[GetState(pos
, prevByte
)].GetPrice(matchMode
, matchByte
, symbol
); }
147 CMyBitEncoder _choice
;
148 CMyBitEncoder _choice2
;
149 NRangeCoder::CBitTreeEncoder
<kNumMoveBits
, kNumLowBits
> _lowCoder
[kNumPosStatesEncodingMax
];
150 NRangeCoder::CBitTreeEncoder
<kNumMoveBits
, kNumMidBits
> _midCoder
[kNumPosStatesEncodingMax
];
151 NRangeCoder::CBitTreeEncoder
<kNumMoveBits
, kNumHighBits
> _highCoder
;
153 void Init(UInt32 numPosStates
);
154 void Encode(NRangeCoder::CEncoder
*rangeEncoder
, UInt32 symbol
, UInt32 posState
);
155 UInt32
GetPrice(UInt32 symbol
, UInt32 posState
) const;
158 const UInt32 kNumSpecSymbols
= kNumLowSymbols
+ kNumMidSymbols
;
160 class CPriceTableEncoder
: public CEncoder
162 UInt32 _prices
[kNumSymbolsTotal
][kNumPosStatesEncodingMax
];
164 UInt32 _counters
[kNumPosStatesEncodingMax
];
166 void SetTableSize(UInt32 tableSize
) { _tableSize
= tableSize
; }
167 UInt32
GetPrice(UInt32 symbol
, UInt32 posState
) const
168 { return _prices
[symbol
][posState
]; }
169 void UpdateTable(UInt32 posState
)
171 for (UInt32 len
= 0; len
< _tableSize
; len
++)
172 _prices
[len
][posState
] = CEncoder::GetPrice(len
, posState
);
173 _counters
[posState
] = _tableSize
;
175 void UpdateTables(UInt32 numPosStates
)
177 for (UInt32 posState
= 0; posState
< numPosStates
; posState
++)
178 UpdateTable(posState
);
180 void Encode(NRangeCoder::CEncoder
*rangeEncoder
, UInt32 symbol
, UInt32 posState
)
182 CEncoder::Encode(rangeEncoder
, symbol
, posState
);
183 if (--_counters
[posState
] == 0)
184 UpdateTable(posState
);
191 public ICompressCoder
,
192 public ICompressSetOutStream
,
193 public ICompressSetCoderProperties
,
194 public ICompressWriteCoderProperties
,
198 COptimal _optimum
[kNumOpts
];
199 CMyComPtr
<IMatchFinder
> _matchFinder
; // test it
200 NRangeCoder::CEncoder _rangeEncoder
;
202 CMyBitEncoder _isMatch
[kNumStates
][NLength::kNumPosStatesEncodingMax
];
203 CMyBitEncoder _isRep
[kNumStates
];
204 CMyBitEncoder _isRepG0
[kNumStates
];
205 CMyBitEncoder _isRepG1
[kNumStates
];
206 CMyBitEncoder _isRepG2
[kNumStates
];
207 CMyBitEncoder _isRep0Long
[kNumStates
][NLength::kNumPosStatesEncodingMax
];
209 NRangeCoder::CBitTreeEncoder
<kNumMoveBits
, kNumPosSlotBits
> _posSlotEncoder
[kNumLenToPosStates
];
211 CMyBitEncoder _posEncoders
[kNumFullDistances
- kEndPosModelIndex
];
212 NRangeCoder::CBitTreeEncoder
<kNumMoveBits
, kNumAlignBits
> _posAlignEncoder
;
214 NLength::CPriceTableEncoder _lenEncoder
;
215 NLength::CPriceTableEncoder _repMatchLenEncoder
;
217 CLiteralEncoder _literalEncoder
;
219 UInt32 _matchDistances
[kMatchMaxLen
+ 1];
223 UInt32 _numFastBytes
;
224 UInt32 _longestMatchLength
;
226 UInt32 _additionalOffset
;
228 UInt32 _optimumEndIndex
;
229 UInt32 _optimumCurrentIndex
;
231 bool _longestMatchWasFound
;
233 UInt32 _posSlotPrices
[kNumLenToPosStates
][kDistTableSizeMax
];
235 UInt32 _distancesPrices
[kNumLenToPosStates
][kNumFullDistances
];
237 UInt32 _alignPrices
[kAlignTableSize
];
238 UInt32 _alignPriceCount
;
240 UInt32 _distTableSize
;
242 UInt32 _posStateBits
;
243 UInt32 _posStateMask
;
244 UInt32 _numLiteralPosStateBits
;
245 UInt32 _numLiteralContextBits
;
247 UInt32 _dictionarySize
;
249 UInt32 _dictionarySizePrev
;
250 UInt32 _numFastBytesPrev
;
252 UInt64 lastPosSlotFillingPos
;
255 ISequentialInStream
*_inStream
;
257 int _matchFinderIndex
;
258 #ifdef COMPRESS_MF_MT
264 bool _needReleaseMFStream
;
266 HRESULT
ReadMatchDistances(UInt32
&len
);
268 HRESULT
MovePos(UInt32 num
);
269 UInt32
GetRepLen1Price(CState state
, UInt32 posState
) const
271 return _isRepG0
[state
.Index
].GetPrice0() +
272 _isRep0Long
[state
.Index
][posState
].GetPrice0();
274 UInt32
GetRepPrice(UInt32 repIndex
, UInt32 len
, CState state
, UInt32 posState
) const
276 UInt32 price
= _repMatchLenEncoder
.GetPrice(len
- kMatchMinLen
, posState
);
279 price
+= _isRepG0
[state
.Index
].GetPrice0();
280 price
+= _isRep0Long
[state
.Index
][posState
].GetPrice1();
284 price
+= _isRepG0
[state
.Index
].GetPrice1();
286 price
+= _isRepG1
[state
.Index
].GetPrice0();
289 price
+= _isRepG1
[state
.Index
].GetPrice1();
290 price
+= _isRepG2
[state
.Index
].GetPrice(repIndex
- 2);
296 UInt32 GetPosLen2Price(UInt32 pos, UInt32 posState) const
298 if (pos >= kNumFullDistances)
299 return kIfinityPrice;
300 return _distancesPrices[0][pos] + _lenEncoder.GetPrice(0, posState);
302 UInt32 GetPosLen3Price(UInt32 pos, UInt32 len, UInt32 posState) const
305 UInt32 lenToPosState = GetLenToPosState(len);
306 if (pos < kNumFullDistances)
307 price = _distancesPrices[lenToPosState][pos];
309 price = _posSlotPrices[lenToPosState][GetPosSlot2(pos)] +
310 _alignPrices[pos & kAlignMask];
311 return price + _lenEncoder.GetPrice(len - kMatchMinLen, posState);
314 UInt32
GetPosLenPrice(UInt32 pos
, UInt32 len
, UInt32 posState
) const
316 if (len
== 2 && pos
>= 0x80)
317 return kIfinityPrice
;
319 UInt32 lenToPosState
= GetLenToPosState(len
);
320 if (pos
< kNumFullDistances
)
321 price
= _distancesPrices
[lenToPosState
][pos
];
323 price
= _posSlotPrices
[lenToPosState
][GetPosSlot2(pos
)] +
324 _alignPrices
[pos
& kAlignMask
];
325 return price
+ _lenEncoder
.GetPrice(len
- kMatchMinLen
, posState
);
328 UInt32
Backward(UInt32
&backRes
, UInt32 cur
);
329 HRESULT
GetOptimum(UInt32 position
, UInt32
&backRes
, UInt32
&lenRes
);
330 HRESULT
GetOptimumFast(UInt32 position
, UInt32
&backRes
, UInt32
&lenRes
);
332 void FillPosSlotPrices();
333 void FillDistancesPrices();
334 void FillAlignPrices();
336 void ReleaseMFStream()
338 if (_matchFinder
&& _needReleaseMFStream
)
340 _matchFinder
->ReleaseStream();
341 _needReleaseMFStream
= false;
345 void ReleaseStreams()
351 HRESULT
Flush(UInt32 nowPos
);
356 CCoderReleaser(CEncoder
*coder
): _coder(coder
) {}
359 _coder
->ReleaseStreams();
362 friend class CCoderReleaser
;
364 void WriteEndMarker(UInt32 posState
);
368 void SetWriteEndMarkerMode(bool writeEndMarker
)
369 { _writeEndMark
= writeEndMarker
; }
374 ICompressSetOutStream
,
375 ICompressSetCoderProperties
,
376 ICompressWriteCoderProperties
381 // ICompressCoder interface
382 HRESULT
SetStreams(ISequentialInStream
*inStream
,
383 ISequentialOutStream
*outStream
,
384 const UInt64
*inSize
, const UInt64
*outSize
);
385 HRESULT
CodeOneBlock(UInt64
*inSize
, UInt64
*outSize
, Int32
*finished
);
387 HRESULT
CodeReal(ISequentialInStream
*inStream
,
388 ISequentialOutStream
*outStream
,
389 const UInt64
*inSize
, const UInt64
*outSize
,
390 ICompressProgressInfo
*progress
);
392 // ICompressCoder interface
393 STDMETHOD(Code
)(ISequentialInStream
*inStream
,
394 ISequentialOutStream
*outStream
,
395 const UInt64
*inSize
, const UInt64
*outSize
,
396 ICompressProgressInfo
*progress
);
398 // IInitMatchFinder interface
399 STDMETHOD(InitMatchFinder
)(IMatchFinder
*matchFinder
);
401 // ICompressSetCoderProperties2
402 STDMETHOD(SetCoderProperties
)(const PROPID
*propIDs
,
403 const PROPVARIANT
*properties
, UInt32 numProperties
);
405 // ICompressWriteCoderProperties
406 STDMETHOD(WriteCoderProperties
)(ISequentialOutStream
*outStream
);
408 STDMETHOD(SetOutStream
)(ISequentialOutStream
*outStream
);
409 STDMETHOD(ReleaseOutStream
)();
411 virtual ~CEncoder() {}