3 #ifndef __LZMA_ENCODER_H
\r
4 #define __LZMA_ENCODER_H
\r
6 #include "../../../Common/MyCom.h"
\r
7 #include "../../../Common/Alloc.h"
\r
8 #include "../../ICoder.h"
\r
9 #include "../LZ/IMatchFinder.h"
\r
10 #include "../RangeCoder/RangeCoderBitTree.h"
\r
14 namespace NCompress {
\r
17 typedef NRangeCoder::CBitEncoder<kNumMoveBits> CMyBitEncoder;
\r
24 UInt32 _repDistances[kNumRepDistances];
\r
29 for(UInt32 i = 0 ; i < kNumRepDistances; i++)
\r
30 _repDistances[i] = 0;
\r
45 UInt32 PosPrev; // posNext;
\r
47 UInt32 Backs[kNumRepDistances];
\r
48 void MakeAsChar() { BackPrev = UInt32(-1); Prev1IsChar = false; }
\r
49 void MakeAsShortRep() { BackPrev = 0; ; Prev1IsChar = false; }
\r
50 bool IsShortRep() { return (BackPrev == 0); }
\r
54 extern Byte g_FastPos[1 << 11];
\r
55 inline UInt32 GetPosSlot(UInt32 pos)
\r
57 if (pos < (1 << 11))
\r
58 return g_FastPos[pos];
\r
59 if (pos < (1 << 21))
\r
60 return g_FastPos[pos >> 10] + 20;
\r
61 return g_FastPos[pos >> 20] + 40;
\r
64 inline UInt32 GetPosSlot2(UInt32 pos)
\r
66 if (pos < (1 << 17))
\r
67 return g_FastPos[pos >> 6] + 12;
\r
68 if (pos < (1 << 27))
\r
69 return g_FastPos[pos >> 16] + 32;
\r
70 return g_FastPos[pos >> 26] + 52;
\r
73 const UInt32 kIfinityPrice = 0xFFFFFFF;
\r
75 const UInt32 kNumOpts = 1 << 12;
\r
78 class CLiteralEncoder2
\r
80 CMyBitEncoder _encoders[0x300];
\r
84 for (int i = 0; i < 0x300; i++)
\r
85 _encoders[i].Init();
\r
87 void Encode(NRangeCoder::CEncoder *rangeEncoder, Byte symbol);
\r
88 void EncodeMatched(NRangeCoder::CEncoder *rangeEncoder, Byte matchByte, Byte symbol);
\r
89 UInt32 GetPrice(bool matchMode, Byte matchByte, Byte symbol) const;
\r
92 class CLiteralEncoder
\r
94 CLiteralEncoder2 *_coders;
\r
99 CLiteralEncoder(): _coders(0) {}
\r
100 ~CLiteralEncoder() { Free(); }
\r
106 bool Create(int numPosBits, int numPrevBits)
\r
108 if (_coders == 0 || (numPosBits + numPrevBits) != (_numPrevBits + _numPosBits))
\r
111 UInt32 numStates = 1 << (numPosBits + numPrevBits);
\r
112 _coders = (CLiteralEncoder2 *)MyAlloc(numStates * sizeof(CLiteralEncoder2));
\r
114 _numPosBits = numPosBits;
\r
115 _posMask = (1 << numPosBits) - 1;
\r
116 _numPrevBits = numPrevBits;
\r
117 return (_coders != 0);
\r
121 UInt32 numStates = 1 << (_numPrevBits + _numPosBits);
\r
122 for (UInt32 i = 0; i < numStates; i++)
\r
125 CLiteralEncoder2 *GetSubCoder(UInt32 pos, Byte prevByte)
\r
126 { return &_coders[((pos & _posMask) << _numPrevBits) + (prevByte >> (8 - _numPrevBits))]; }
\r
129 namespace NLength {
\r
133 CMyBitEncoder _choice;
\r
134 CMyBitEncoder _choice2;
\r
135 NRangeCoder::CBitTreeEncoder<kNumMoveBits, kNumLowBits> _lowCoder[kNumPosStatesEncodingMax];
\r
136 NRangeCoder::CBitTreeEncoder<kNumMoveBits, kNumMidBits> _midCoder[kNumPosStatesEncodingMax];
\r
137 NRangeCoder::CBitTreeEncoder<kNumMoveBits, kNumHighBits> _highCoder;
\r
139 void Init(UInt32 numPosStates);
\r
140 void Encode(NRangeCoder::CEncoder *rangeEncoder, UInt32 symbol, UInt32 posState);
\r
141 void SetPrices(UInt32 posState, UInt32 numSymbols, UInt32 *prices) const;
\r
144 const UInt32 kNumSpecSymbols = kNumLowSymbols + kNumMidSymbols;
\r
146 class CPriceTableEncoder: public CEncoder
\r
148 UInt32 _prices[kNumPosStatesEncodingMax][kNumSymbolsTotal];
\r
150 UInt32 _counters[kNumPosStatesEncodingMax];
\r
152 void SetTableSize(UInt32 tableSize) { _tableSize = tableSize; }
\r
153 UInt32 GetPrice(UInt32 symbol, UInt32 posState) const { return _prices[posState][symbol]; }
\r
154 void UpdateTable(UInt32 posState)
\r
156 SetPrices(posState, _tableSize, _prices[posState]);
\r
157 _counters[posState] = _tableSize;
\r
159 void UpdateTables(UInt32 numPosStates)
\r
161 for (UInt32 posState = 0; posState < numPosStates; posState++)
\r
162 UpdateTable(posState);
\r
164 void Encode(NRangeCoder::CEncoder *rangeEncoder, UInt32 symbol, UInt32 posState, bool updatePrice)
\r
166 CEncoder::Encode(rangeEncoder, symbol, posState);
\r
168 if (--_counters[posState] == 0)
\r
169 UpdateTable(posState);
\r
176 public ICompressCoder,
\r
177 public ICompressSetOutStream,
\r
178 public ICompressSetCoderProperties,
\r
179 public ICompressWriteCoderProperties,
\r
181 public CMyUnknownImp
\r
183 COptimal _optimum[kNumOpts];
\r
184 CMyComPtr<IMatchFinder> _matchFinder; // test it
\r
185 NRangeCoder::CEncoder _rangeEncoder;
\r
187 CMyBitEncoder _isMatch[kNumStates][NLength::kNumPosStatesEncodingMax];
\r
188 CMyBitEncoder _isRep[kNumStates];
\r
189 CMyBitEncoder _isRepG0[kNumStates];
\r
190 CMyBitEncoder _isRepG1[kNumStates];
\r
191 CMyBitEncoder _isRepG2[kNumStates];
\r
192 CMyBitEncoder _isRep0Long[kNumStates][NLength::kNumPosStatesEncodingMax];
\r
194 NRangeCoder::CBitTreeEncoder<kNumMoveBits, kNumPosSlotBits> _posSlotEncoder[kNumLenToPosStates];
\r
196 CMyBitEncoder _posEncoders[kNumFullDistances - kEndPosModelIndex];
\r
197 NRangeCoder::CBitTreeEncoder<kNumMoveBits, kNumAlignBits> _posAlignEncoder;
\r
199 NLength::CPriceTableEncoder _lenEncoder;
\r
200 NLength::CPriceTableEncoder _repMatchLenEncoder;
\r
202 CLiteralEncoder _literalEncoder;
\r
204 UInt32 _matchDistances[kMatchMaxLen * 2 + 2 + 1];
\r
208 UInt32 _numFastBytes;
\r
209 UInt32 _longestMatchLength;
\r
210 UInt32 _numDistancePairs;
\r
212 UInt32 _additionalOffset;
\r
214 UInt32 _optimumEndIndex;
\r
215 UInt32 _optimumCurrentIndex;
\r
217 bool _longestMatchWasFound;
\r
219 UInt32 _posSlotPrices[kNumLenToPosStates][kDistTableSizeMax];
\r
221 UInt32 _distancesPrices[kNumLenToPosStates][kNumFullDistances];
\r
223 UInt32 _alignPrices[kAlignTableSize];
\r
224 UInt32 _alignPriceCount;
\r
226 UInt32 _distTableSize;
\r
228 UInt32 _posStateBits;
\r
229 UInt32 _posStateMask;
\r
230 UInt32 _numLiteralPosStateBits;
\r
231 UInt32 _numLiteralContextBits;
\r
233 UInt32 _dictionarySize;
\r
235 UInt32 _dictionarySizePrev;
\r
236 UInt32 _numFastBytesPrev;
\r
238 UInt32 _matchPriceCount;
\r
241 ISequentialInStream *_inStream;
\r
243 UInt32 _matchFinderCycles;
\r
244 int _matchFinderIndex;
\r
245 #ifdef COMPRESS_MF_MT
\r
249 bool _writeEndMark;
\r
251 bool _needReleaseMFStream;
\r
253 IMatchFinderSetNumPasses *setMfPasses;
\r
255 void ReleaseMatchFinder()
\r
258 _matchFinder.Release();
\r
261 HRESULT ReadMatchDistances(UInt32 &len, UInt32 &numDistancePairs);
\r
263 HRESULT MovePos(UInt32 num);
\r
264 UInt32 GetRepLen1Price(CState state, UInt32 posState) const
\r
266 return _isRepG0[state.Index].GetPrice0() +
\r
267 _isRep0Long[state.Index][posState].GetPrice0();
\r
270 UInt32 GetPureRepPrice(UInt32 repIndex, CState state, UInt32 posState) const
\r
275 price = _isRepG0[state.Index].GetPrice0();
\r
276 price += _isRep0Long[state.Index][posState].GetPrice1();
\r
280 price = _isRepG0[state.Index].GetPrice1();
\r
282 price += _isRepG1[state.Index].GetPrice0();
\r
285 price += _isRepG1[state.Index].GetPrice1();
\r
286 price += _isRepG2[state.Index].GetPrice(repIndex - 2);
\r
291 UInt32 GetRepPrice(UInt32 repIndex, UInt32 len, CState state, UInt32 posState) const
\r
293 return _repMatchLenEncoder.GetPrice(len - kMatchMinLen, posState) +
\r
294 GetPureRepPrice(repIndex, state, posState);
\r
297 UInt32 GetPosLen2Price(UInt32 pos, UInt32 posState) const
\r
299 if (pos >= kNumFullDistances)
\r
300 return kIfinityPrice;
\r
301 return _distancesPrices[0][pos] + _lenEncoder.GetPrice(0, posState);
\r
303 UInt32 GetPosLen3Price(UInt32 pos, UInt32 len, UInt32 posState) const
\r
306 UInt32 lenToPosState = GetLenToPosState(len);
\r
307 if (pos < kNumFullDistances)
\r
308 price = _distancesPrices[lenToPosState][pos];
\r
310 price = _posSlotPrices[lenToPosState][GetPosSlot2(pos)] +
\r
311 _alignPrices[pos & kAlignMask];
\r
312 return price + _lenEncoder.GetPrice(len - kMatchMinLen, posState);
\r
315 UInt32 GetPosLenPrice(UInt32 pos, UInt32 len, UInt32 posState) const
\r
318 UInt32 lenToPosState = GetLenToPosState(len);
\r
319 if (pos < kNumFullDistances)
\r
320 price = _distancesPrices[lenToPosState][pos];
\r
322 price = _posSlotPrices[lenToPosState][GetPosSlot2(pos)] +
\r
323 _alignPrices[pos & kAlignMask];
\r
324 return price + _lenEncoder.GetPrice(len - kMatchMinLen, posState);
\r
327 UInt32 Backward(UInt32 &backRes, UInt32 cur);
\r
328 HRESULT GetOptimum(UInt32 position, UInt32 &backRes, UInt32 &lenRes);
\r
329 HRESULT GetOptimumFast(UInt32 position, UInt32 &backRes, UInt32 &lenRes);
\r
331 void FillDistancesPrices();
\r
332 void FillAlignPrices();
\r
334 void ReleaseMFStream()
\r
336 if (_matchFinder && _needReleaseMFStream)
\r
338 _matchFinder->ReleaseStream();
\r
339 _needReleaseMFStream = false;
\r
343 void ReleaseStreams()
\r
346 ReleaseOutStream();
\r
349 HRESULT Flush(UInt32 nowPos);
\r
350 class CCoderReleaser
\r
354 CCoderReleaser(CEncoder *coder): _coder(coder) {}
\r
357 _coder->ReleaseStreams();
\r
360 friend class CCoderReleaser;
\r
362 void WriteEndMarker(UInt32 posState);
\r
366 void SetWriteEndMarkerMode(bool writeEndMarker)
\r
367 { _writeEndMark= writeEndMarker; }
\r
372 ICompressSetOutStream,
\r
373 ICompressSetCoderProperties,
\r
374 ICompressWriteCoderProperties
\r
379 // ICompressCoder interface
\r
380 HRESULT SetStreams(ISequentialInStream *inStream,
\r
381 ISequentialOutStream *outStream,
\r
382 const UInt64 *inSize, const UInt64 *outSize);
\r
383 HRESULT CodeOneBlock(UInt64 *inSize, UInt64 *outSize, Int32 *finished);
\r
385 HRESULT CodeReal(ISequentialInStream *inStream,
\r
386 ISequentialOutStream *outStream,
\r
387 const UInt64 *inSize, const UInt64 *outSize,
\r
388 ICompressProgressInfo *progress);
\r
390 // ICompressCoder interface
\r
391 STDMETHOD(Code)(ISequentialInStream *inStream,
\r
392 ISequentialOutStream *outStream,
\r
393 const UInt64 *inSize, const UInt64 *outSize,
\r
394 ICompressProgressInfo *progress);
\r
396 // ICompressSetCoderProperties2
\r
397 STDMETHOD(SetCoderProperties)(const PROPID *propIDs,
\r
398 const PROPVARIANT *properties, UInt32 numProperties);
\r
400 // ICompressWriteCoderProperties
\r
401 STDMETHOD(WriteCoderProperties)(ISequentialOutStream *outStream);
\r
403 STDMETHOD(SetOutStream)(ISequentialOutStream *outStream);
\r
404 STDMETHOD(ReleaseOutStream)();
\r
406 virtual ~CEncoder() {}
\r