• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* LzmaEnc.c -- LZMA Encoder
2 2014-12-29 : Igor Pavlov : Public domain */
3 
4 #include "Precomp.h"
5 
6 #include <string.h>
7 
8 /* #define SHOW_STAT */
9 /* #define SHOW_STAT2 */
10 
11 #if defined(SHOW_STAT) || defined(SHOW_STAT2)
12 #include <stdio.h>
13 #endif
14 
15 #include "LzmaEnc.h"
16 
17 #include "LzFind.h"
18 #ifndef _7ZIP_ST
19 #include "LzFindMt.h"
20 #endif
21 
22 #ifdef SHOW_STAT
23 static unsigned g_STAT_OFFSET = 0;
24 #endif
25 
26 #define kBlockSizeMax ((1 << LZMA_NUM_BLOCK_SIZE_BITS) - 1)
27 
28 #define kBlockSize (9 << 10)
29 #define kUnpackBlockSize (1 << 18)
30 #define kMatchArraySize (1 << 21)
31 #define kMatchRecordMaxSize ((LZMA_MATCH_LEN_MAX * 2 + 3) * LZMA_MATCH_LEN_MAX)
32 
33 #define kNumMaxDirectBits (31)
34 
35 #define kNumTopBits 24
36 #define kTopValue ((UInt32)1 << kNumTopBits)
37 
38 #define kNumBitModelTotalBits 11
39 #define kBitModelTotal (1 << kNumBitModelTotalBits)
40 #define kNumMoveBits 5
41 #define kProbInitValue (kBitModelTotal >> 1)
42 
43 #define kNumMoveReducingBits 4
44 #define kNumBitPriceShiftBits 4
45 #define kBitPrice (1 << kNumBitPriceShiftBits)
46 
LzmaEncProps_Init(CLzmaEncProps * p)47 void LzmaEncProps_Init(CLzmaEncProps *p)
48 {
49   p->level = 5;
50   p->dictSize = p->mc = 0;
51   p->reduceSize = (UInt64)(Int64)-1;
52   p->lc = p->lp = p->pb = p->algo = p->fb = p->btMode = p->numHashBytes = p->numThreads = -1;
53   p->writeEndMark = 0;
54 }
55 
LzmaEncProps_Normalize(CLzmaEncProps * p)56 void LzmaEncProps_Normalize(CLzmaEncProps *p)
57 {
58   int level = p->level;
59   if (level < 0) level = 5;
60   p->level = level;
61   if (p->dictSize == 0) p->dictSize = (level <= 5 ? (1 << (level * 2 + 14)) : (level == 6 ? (1 << 25) : (1 << 26)));
62   if (p->dictSize > p->reduceSize)
63   {
64     unsigned i;
65     for (i = 11; i <= 30; i++)
66     {
67       if ((UInt32)p->reduceSize <= ((UInt32)2 << i)) { p->dictSize = ((UInt32)2 << i); break; }
68       if ((UInt32)p->reduceSize <= ((UInt32)3 << i)) { p->dictSize = ((UInt32)3 << i); break; }
69     }
70   }
71   if (p->lc < 0) p->lc = 3;
72   if (p->lp < 0) p->lp = 0;
73   if (p->pb < 0) p->pb = 2;
74   if (p->algo < 0) p->algo = (level < 5 ? 0 : 1);
75   if (p->fb < 0) p->fb = (level < 7 ? 32 : 64);
76   if (p->btMode < 0) p->btMode = (p->algo == 0 ? 0 : 1);
77   if (p->numHashBytes < 0) p->numHashBytes = 4;
78   if (p->mc == 0)  p->mc = (16 + (p->fb >> 1)) >> (p->btMode ? 0 : 1);
79   if (p->numThreads < 0)
80     p->numThreads =
81       #ifndef _7ZIP_ST
82       ((p->btMode && p->algo) ? 2 : 1);
83       #else
84       1;
85       #endif
86 }
87 
LzmaEncProps_GetDictSize(const CLzmaEncProps * props2)88 UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2)
89 {
90   CLzmaEncProps props = *props2;
91   LzmaEncProps_Normalize(&props);
92   return props.dictSize;
93 }
94 
95 /* #define LZMA_LOG_BSR */
96 /* Define it for Intel's CPU */
97 
98 
99 #ifdef LZMA_LOG_BSR
100 
101 #define kDicLogSizeMaxCompress 30
102 
103 #define BSR2_RET(pos, res) { unsigned long i; _BitScanReverse(&i, (pos)); res = (i + i) + ((pos >> (i - 1)) & 1); }
104 
GetPosSlot1(UInt32 pos)105 UInt32 GetPosSlot1(UInt32 pos)
106 {
107   UInt32 res;
108   BSR2_RET(pos, res);
109   return res;
110 }
111 #define GetPosSlot2(pos, res) { BSR2_RET(pos, res); }
112 #define GetPosSlot(pos, res) { if (pos < 2) res = pos; else BSR2_RET(pos, res); }
113 
114 #else
115 
116 #define kNumLogBits (9 + (int)sizeof(size_t) / 2)
117 #define kDicLogSizeMaxCompress ((kNumLogBits - 1) * 2 + 7)
118 
LzmaEnc_FastPosInit(Byte * g_FastPos)119 void LzmaEnc_FastPosInit(Byte *g_FastPos)
120 {
121   int c = 2, slotFast;
122   g_FastPos[0] = 0;
123   g_FastPos[1] = 1;
124 
125   for (slotFast = 2; slotFast < kNumLogBits * 2; slotFast++)
126   {
127     UInt32 k = (1 << ((slotFast >> 1) - 1));
128     UInt32 j;
129     for (j = 0; j < k; j++, c++)
130       g_FastPos[c] = (Byte)slotFast;
131   }
132 }
133 
134 #define BSR2_RET(pos, res) { UInt32 i = 6 + ((kNumLogBits - 1) & \
135   (0 - (((((UInt32)1 << (kNumLogBits + 6)) - 1) - pos) >> 31))); \
136   res = p->g_FastPos[pos >> i] + (i * 2); }
137 /*
138 #define BSR2_RET(pos, res) { res = (pos < (1 << (kNumLogBits + 6))) ? \
139   p->g_FastPos[pos >> 6] + 12 : \
140   p->g_FastPos[pos >> (6 + kNumLogBits - 1)] + (6 + (kNumLogBits - 1)) * 2; }
141 */
142 
143 #define GetPosSlot1(pos) p->g_FastPos[pos]
144 #define GetPosSlot2(pos, res) { BSR2_RET(pos, res); }
145 #define GetPosSlot(pos, res) { if (pos < kNumFullDistances) res = p->g_FastPos[pos]; else BSR2_RET(pos, res); }
146 
147 #endif
148 
149 
150 #define LZMA_NUM_REPS 4
151 
152 typedef unsigned CState;
153 
154 typedef struct
155 {
156   UInt32 price;
157 
158   CState state;
159   int prev1IsChar;
160   int prev2;
161 
162   UInt32 posPrev2;
163   UInt32 backPrev2;
164 
165   UInt32 posPrev;
166   UInt32 backPrev;
167   UInt32 backs[LZMA_NUM_REPS];
168 } COptimal;
169 
170 #define kNumOpts (1 << 12)
171 
172 #define kNumLenToPosStates 4
173 #define kNumPosSlotBits 6
174 #define kDicLogSizeMin 0
175 #define kDicLogSizeMax 32
176 #define kDistTableSizeMax (kDicLogSizeMax * 2)
177 
178 
179 #define kNumAlignBits 4
180 #define kAlignTableSize (1 << kNumAlignBits)
181 #define kAlignMask (kAlignTableSize - 1)
182 
183 #define kStartPosModelIndex 4
184 #define kEndPosModelIndex 14
185 #define kNumPosModels (kEndPosModelIndex - kStartPosModelIndex)
186 
187 #define kNumFullDistances (1 << (kEndPosModelIndex >> 1))
188 
189 #ifdef _LZMA_PROB32
190 #define CLzmaProb UInt32
191 #else
192 #define CLzmaProb UInt16
193 #endif
194 
195 #define LZMA_PB_MAX 4
196 #define LZMA_LC_MAX 8
197 #define LZMA_LP_MAX 4
198 
199 #define LZMA_NUM_PB_STATES_MAX (1 << LZMA_PB_MAX)
200 
201 
202 #define kLenNumLowBits 3
203 #define kLenNumLowSymbols (1 << kLenNumLowBits)
204 #define kLenNumMidBits 3
205 #define kLenNumMidSymbols (1 << kLenNumMidBits)
206 #define kLenNumHighBits 8
207 #define kLenNumHighSymbols (1 << kLenNumHighBits)
208 
209 #define kLenNumSymbolsTotal (kLenNumLowSymbols + kLenNumMidSymbols + kLenNumHighSymbols)
210 
211 #define LZMA_MATCH_LEN_MIN 2
212 #define LZMA_MATCH_LEN_MAX (LZMA_MATCH_LEN_MIN + kLenNumSymbolsTotal - 1)
213 
214 #define kNumStates 12
215 
216 typedef struct
217 {
218   CLzmaProb choice;
219   CLzmaProb choice2;
220   CLzmaProb low[LZMA_NUM_PB_STATES_MAX << kLenNumLowBits];
221   CLzmaProb mid[LZMA_NUM_PB_STATES_MAX << kLenNumMidBits];
222   CLzmaProb high[kLenNumHighSymbols];
223 } CLenEnc;
224 
225 typedef struct
226 {
227   CLenEnc p;
228   UInt32 prices[LZMA_NUM_PB_STATES_MAX][kLenNumSymbolsTotal];
229   UInt32 tableSize;
230   UInt32 counters[LZMA_NUM_PB_STATES_MAX];
231 } CLenPriceEnc;
232 
233 typedef struct
234 {
235   UInt32 range;
236   Byte cache;
237   UInt64 low;
238   UInt64 cacheSize;
239   Byte *buf;
240   Byte *bufLim;
241   Byte *bufBase;
242   ISeqOutStream *outStream;
243   UInt64 processed;
244   SRes res;
245 } CRangeEnc;
246 
247 typedef struct
248 {
249   CLzmaProb *litProbs;
250 
251   CLzmaProb isMatch[kNumStates][LZMA_NUM_PB_STATES_MAX];
252   CLzmaProb isRep[kNumStates];
253   CLzmaProb isRepG0[kNumStates];
254   CLzmaProb isRepG1[kNumStates];
255   CLzmaProb isRepG2[kNumStates];
256   CLzmaProb isRep0Long[kNumStates][LZMA_NUM_PB_STATES_MAX];
257 
258   CLzmaProb posSlotEncoder[kNumLenToPosStates][1 << kNumPosSlotBits];
259   CLzmaProb posEncoders[kNumFullDistances - kEndPosModelIndex];
260   CLzmaProb posAlignEncoder[1 << kNumAlignBits];
261 
262   CLenPriceEnc lenEnc;
263   CLenPriceEnc repLenEnc;
264 
265   UInt32 reps[LZMA_NUM_REPS];
266   UInt32 state;
267 } CSaveState;
268 
269 typedef struct
270 {
271   IMatchFinder matchFinder;
272   void *matchFinderObj;
273 
274   #ifndef _7ZIP_ST
275   Bool mtMode;
276   CMatchFinderMt matchFinderMt;
277   #endif
278 
279   CMatchFinder matchFinderBase;
280 
281   #ifndef _7ZIP_ST
282   Byte pad[128];
283   #endif
284 
285   UInt32 optimumEndIndex;
286   UInt32 optimumCurrentIndex;
287 
288   UInt32 longestMatchLength;
289   UInt32 numPairs;
290   UInt32 numAvail;
291   COptimal opt[kNumOpts];
292 
293   #ifndef LZMA_LOG_BSR
294   Byte g_FastPos[1 << kNumLogBits];
295   #endif
296 
297   UInt32 ProbPrices[kBitModelTotal >> kNumMoveReducingBits];
298   UInt32 matches[LZMA_MATCH_LEN_MAX * 2 + 2 + 1];
299   UInt32 numFastBytes;
300   UInt32 additionalOffset;
301   UInt32 reps[LZMA_NUM_REPS];
302   UInt32 state;
303 
304   UInt32 posSlotPrices[kNumLenToPosStates][kDistTableSizeMax];
305   UInt32 distancesPrices[kNumLenToPosStates][kNumFullDistances];
306   UInt32 alignPrices[kAlignTableSize];
307   UInt32 alignPriceCount;
308 
309   UInt32 distTableSize;
310 
311   unsigned lc, lp, pb;
312   unsigned lpMask, pbMask;
313 
314   CLzmaProb *litProbs;
315 
316   CLzmaProb isMatch[kNumStates][LZMA_NUM_PB_STATES_MAX];
317   CLzmaProb isRep[kNumStates];
318   CLzmaProb isRepG0[kNumStates];
319   CLzmaProb isRepG1[kNumStates];
320   CLzmaProb isRepG2[kNumStates];
321   CLzmaProb isRep0Long[kNumStates][LZMA_NUM_PB_STATES_MAX];
322 
323   CLzmaProb posSlotEncoder[kNumLenToPosStates][1 << kNumPosSlotBits];
324   CLzmaProb posEncoders[kNumFullDistances - kEndPosModelIndex];
325   CLzmaProb posAlignEncoder[1 << kNumAlignBits];
326 
327   CLenPriceEnc lenEnc;
328   CLenPriceEnc repLenEnc;
329 
330   unsigned lclp;
331 
332   Bool fastMode;
333 
334   CRangeEnc rc;
335 
336   Bool writeEndMark;
337   UInt64 nowPos64;
338   UInt32 matchPriceCount;
339   Bool finished;
340   Bool multiThread;
341 
342   SRes result;
343   UInt32 dictSize;
344 
345   int needInit;
346 
347   CSaveState saveState;
348 } CLzmaEnc;
349 
LzmaEnc_SaveState(CLzmaEncHandle pp)350 void LzmaEnc_SaveState(CLzmaEncHandle pp)
351 {
352   CLzmaEnc *p = (CLzmaEnc *)pp;
353   CSaveState *dest = &p->saveState;
354   int i;
355   dest->lenEnc = p->lenEnc;
356   dest->repLenEnc = p->repLenEnc;
357   dest->state = p->state;
358 
359   for (i = 0; i < kNumStates; i++)
360   {
361     memcpy(dest->isMatch[i], p->isMatch[i], sizeof(p->isMatch[i]));
362     memcpy(dest->isRep0Long[i], p->isRep0Long[i], sizeof(p->isRep0Long[i]));
363   }
364   for (i = 0; i < kNumLenToPosStates; i++)
365     memcpy(dest->posSlotEncoder[i], p->posSlotEncoder[i], sizeof(p->posSlotEncoder[i]));
366   memcpy(dest->isRep, p->isRep, sizeof(p->isRep));
367   memcpy(dest->isRepG0, p->isRepG0, sizeof(p->isRepG0));
368   memcpy(dest->isRepG1, p->isRepG1, sizeof(p->isRepG1));
369   memcpy(dest->isRepG2, p->isRepG2, sizeof(p->isRepG2));
370   memcpy(dest->posEncoders, p->posEncoders, sizeof(p->posEncoders));
371   memcpy(dest->posAlignEncoder, p->posAlignEncoder, sizeof(p->posAlignEncoder));
372   memcpy(dest->reps, p->reps, sizeof(p->reps));
373   memcpy(dest->litProbs, p->litProbs, (0x300 << p->lclp) * sizeof(CLzmaProb));
374 }
375 
LzmaEnc_RestoreState(CLzmaEncHandle pp)376 void LzmaEnc_RestoreState(CLzmaEncHandle pp)
377 {
378   CLzmaEnc *dest = (CLzmaEnc *)pp;
379   const CSaveState *p = &dest->saveState;
380   int i;
381   dest->lenEnc = p->lenEnc;
382   dest->repLenEnc = p->repLenEnc;
383   dest->state = p->state;
384 
385   for (i = 0; i < kNumStates; i++)
386   {
387     memcpy(dest->isMatch[i], p->isMatch[i], sizeof(p->isMatch[i]));
388     memcpy(dest->isRep0Long[i], p->isRep0Long[i], sizeof(p->isRep0Long[i]));
389   }
390   for (i = 0; i < kNumLenToPosStates; i++)
391     memcpy(dest->posSlotEncoder[i], p->posSlotEncoder[i], sizeof(p->posSlotEncoder[i]));
392   memcpy(dest->isRep, p->isRep, sizeof(p->isRep));
393   memcpy(dest->isRepG0, p->isRepG0, sizeof(p->isRepG0));
394   memcpy(dest->isRepG1, p->isRepG1, sizeof(p->isRepG1));
395   memcpy(dest->isRepG2, p->isRepG2, sizeof(p->isRepG2));
396   memcpy(dest->posEncoders, p->posEncoders, sizeof(p->posEncoders));
397   memcpy(dest->posAlignEncoder, p->posAlignEncoder, sizeof(p->posAlignEncoder));
398   memcpy(dest->reps, p->reps, sizeof(p->reps));
399   memcpy(dest->litProbs, p->litProbs, (0x300 << dest->lclp) * sizeof(CLzmaProb));
400 }
401 
LzmaEnc_SetProps(CLzmaEncHandle pp,const CLzmaEncProps * props2)402 SRes LzmaEnc_SetProps(CLzmaEncHandle pp, const CLzmaEncProps *props2)
403 {
404   CLzmaEnc *p = (CLzmaEnc *)pp;
405   CLzmaEncProps props = *props2;
406   LzmaEncProps_Normalize(&props);
407 
408   if (props.lc > LZMA_LC_MAX || props.lp > LZMA_LP_MAX || props.pb > LZMA_PB_MAX ||
409       props.dictSize > ((UInt32)1 << kDicLogSizeMaxCompress) || props.dictSize > ((UInt32)1 << 30))
410     return SZ_ERROR_PARAM;
411   p->dictSize = props.dictSize;
412   {
413     unsigned fb = props.fb;
414     if (fb < 5)
415       fb = 5;
416     if (fb > LZMA_MATCH_LEN_MAX)
417       fb = LZMA_MATCH_LEN_MAX;
418     p->numFastBytes = fb;
419   }
420   p->lc = props.lc;
421   p->lp = props.lp;
422   p->pb = props.pb;
423   p->fastMode = (props.algo == 0);
424   p->matchFinderBase.btMode = props.btMode;
425   {
426     UInt32 numHashBytes = 4;
427     if (props.btMode)
428     {
429       if (props.numHashBytes < 2)
430         numHashBytes = 2;
431       else if (props.numHashBytes < 4)
432         numHashBytes = props.numHashBytes;
433     }
434     p->matchFinderBase.numHashBytes = numHashBytes;
435   }
436 
437   p->matchFinderBase.cutValue = props.mc;
438 
439   p->writeEndMark = props.writeEndMark;
440 
441   #ifndef _7ZIP_ST
442   /*
443   if (newMultiThread != _multiThread)
444   {
445     ReleaseMatchFinder();
446     _multiThread = newMultiThread;
447   }
448   */
449   p->multiThread = (props.numThreads > 1);
450   #endif
451 
452   return SZ_OK;
453 }
454 
455 static const int kLiteralNextStates[kNumStates] = {0, 0, 0, 0, 1, 2, 3, 4,  5,  6,   4, 5};
456 static const int kMatchNextStates[kNumStates]   = {7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10};
457 static const int kRepNextStates[kNumStates]     = {8, 8, 8, 8, 8, 8, 8, 11, 11, 11, 11, 11};
458 static const int kShortRepNextStates[kNumStates]= {9, 9, 9, 9, 9, 9, 9, 11, 11, 11, 11, 11};
459 
460 #define IsCharState(s) ((s) < 7)
461 
462 #define GetLenToPosState(len) (((len) < kNumLenToPosStates + 1) ? (len) - 2 : kNumLenToPosStates - 1)
463 
464 #define kInfinityPrice (1 << 30)
465 
RangeEnc_Construct(CRangeEnc * p)466 static void RangeEnc_Construct(CRangeEnc *p)
467 {
468   p->outStream = 0;
469   p->bufBase = 0;
470 }
471 
472 #define RangeEnc_GetProcessed(p) ((p)->processed + ((p)->buf - (p)->bufBase) + (p)->cacheSize)
473 
474 #define RC_BUF_SIZE (1 << 16)
RangeEnc_Alloc(CRangeEnc * p,ISzAlloc * alloc)475 static int RangeEnc_Alloc(CRangeEnc *p, ISzAlloc *alloc)
476 {
477   if (p->bufBase == 0)
478   {
479     p->bufBase = (Byte *)alloc->Alloc(alloc, RC_BUF_SIZE);
480     if (p->bufBase == 0)
481       return 0;
482     p->bufLim = p->bufBase + RC_BUF_SIZE;
483   }
484   return 1;
485 }
486 
RangeEnc_Free(CRangeEnc * p,ISzAlloc * alloc)487 static void RangeEnc_Free(CRangeEnc *p, ISzAlloc *alloc)
488 {
489   alloc->Free(alloc, p->bufBase);
490   p->bufBase = 0;
491 }
492 
RangeEnc_Init(CRangeEnc * p)493 static void RangeEnc_Init(CRangeEnc *p)
494 {
495   /* Stream.Init(); */
496   p->low = 0;
497   p->range = 0xFFFFFFFF;
498   p->cacheSize = 1;
499   p->cache = 0;
500 
501   p->buf = p->bufBase;
502 
503   p->processed = 0;
504   p->res = SZ_OK;
505 }
506 
RangeEnc_FlushStream(CRangeEnc * p)507 static void RangeEnc_FlushStream(CRangeEnc *p)
508 {
509   size_t num;
510   if (p->res != SZ_OK)
511     return;
512   num = p->buf - p->bufBase;
513   if (num != p->outStream->Write(p->outStream, p->bufBase, num))
514     p->res = SZ_ERROR_WRITE;
515   p->processed += num;
516   p->buf = p->bufBase;
517 }
518 
RangeEnc_ShiftLow(CRangeEnc * p)519 static void MY_FAST_CALL RangeEnc_ShiftLow(CRangeEnc *p)
520 {
521   if ((UInt32)p->low < (UInt32)0xFF000000 || (unsigned)(p->low >> 32) != 0)
522   {
523     Byte temp = p->cache;
524     do
525     {
526       Byte *buf = p->buf;
527       *buf++ = (Byte)(temp + (Byte)(p->low >> 32));
528       p->buf = buf;
529       if (buf == p->bufLim)
530         RangeEnc_FlushStream(p);
531       temp = 0xFF;
532     }
533     while (--p->cacheSize != 0);
534     p->cache = (Byte)((UInt32)p->low >> 24);
535   }
536   p->cacheSize++;
537   p->low = (UInt32)p->low << 8;
538 }
539 
RangeEnc_FlushData(CRangeEnc * p)540 static void RangeEnc_FlushData(CRangeEnc *p)
541 {
542   int i;
543   for (i = 0; i < 5; i++)
544     RangeEnc_ShiftLow(p);
545 }
546 
RangeEnc_EncodeDirectBits(CRangeEnc * p,UInt32 value,unsigned numBits)547 static void RangeEnc_EncodeDirectBits(CRangeEnc *p, UInt32 value, unsigned numBits)
548 {
549   do
550   {
551     p->range >>= 1;
552     p->low += p->range & (0 - ((value >> --numBits) & 1));
553     if (p->range < kTopValue)
554     {
555       p->range <<= 8;
556       RangeEnc_ShiftLow(p);
557     }
558   }
559   while (numBits != 0);
560 }
561 
RangeEnc_EncodeBit(CRangeEnc * p,CLzmaProb * prob,UInt32 symbol)562 static void RangeEnc_EncodeBit(CRangeEnc *p, CLzmaProb *prob, UInt32 symbol)
563 {
564   UInt32 ttt = *prob;
565   UInt32 newBound = (p->range >> kNumBitModelTotalBits) * ttt;
566   if (symbol == 0)
567   {
568     p->range = newBound;
569     ttt += (kBitModelTotal - ttt) >> kNumMoveBits;
570   }
571   else
572   {
573     p->low += newBound;
574     p->range -= newBound;
575     ttt -= ttt >> kNumMoveBits;
576   }
577   *prob = (CLzmaProb)ttt;
578   if (p->range < kTopValue)
579   {
580     p->range <<= 8;
581     RangeEnc_ShiftLow(p);
582   }
583 }
584 
LitEnc_Encode(CRangeEnc * p,CLzmaProb * probs,UInt32 symbol)585 static void LitEnc_Encode(CRangeEnc *p, CLzmaProb *probs, UInt32 symbol)
586 {
587   symbol |= 0x100;
588   do
589   {
590     RangeEnc_EncodeBit(p, probs + (symbol >> 8), (symbol >> 7) & 1);
591     symbol <<= 1;
592   }
593   while (symbol < 0x10000);
594 }
595 
LitEnc_EncodeMatched(CRangeEnc * p,CLzmaProb * probs,UInt32 symbol,UInt32 matchByte)596 static void LitEnc_EncodeMatched(CRangeEnc *p, CLzmaProb *probs, UInt32 symbol, UInt32 matchByte)
597 {
598   UInt32 offs = 0x100;
599   symbol |= 0x100;
600   do
601   {
602     matchByte <<= 1;
603     RangeEnc_EncodeBit(p, probs + (offs + (matchByte & offs) + (symbol >> 8)), (symbol >> 7) & 1);
604     symbol <<= 1;
605     offs &= ~(matchByte ^ symbol);
606   }
607   while (symbol < 0x10000);
608 }
609 
LzmaEnc_InitPriceTables(UInt32 * ProbPrices)610 void LzmaEnc_InitPriceTables(UInt32 *ProbPrices)
611 {
612   UInt32 i;
613   for (i = (1 << kNumMoveReducingBits) / 2; i < kBitModelTotal; i += (1 << kNumMoveReducingBits))
614   {
615     const int kCyclesBits = kNumBitPriceShiftBits;
616     UInt32 w = i;
617     UInt32 bitCount = 0;
618     int j;
619     for (j = 0; j < kCyclesBits; j++)
620     {
621       w = w * w;
622       bitCount <<= 1;
623       while (w >= ((UInt32)1 << 16))
624       {
625         w >>= 1;
626         bitCount++;
627       }
628     }
629     ProbPrices[i >> kNumMoveReducingBits] = ((kNumBitModelTotalBits << kCyclesBits) - 15 - bitCount);
630   }
631 }
632 
633 
634 #define GET_PRICE(prob, symbol) \
635   p->ProbPrices[((prob) ^ (((-(int)(symbol))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits];
636 
637 #define GET_PRICEa(prob, symbol) \
638   ProbPrices[((prob) ^ ((-((int)(symbol))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits];
639 
640 #define GET_PRICE_0(prob) p->ProbPrices[(prob) >> kNumMoveReducingBits]
641 #define GET_PRICE_1(prob) p->ProbPrices[((prob) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits]
642 
643 #define GET_PRICE_0a(prob) ProbPrices[(prob) >> kNumMoveReducingBits]
644 #define GET_PRICE_1a(prob) ProbPrices[((prob) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits]
645 
LitEnc_GetPrice(const CLzmaProb * probs,UInt32 symbol,UInt32 * ProbPrices)646 static UInt32 LitEnc_GetPrice(const CLzmaProb *probs, UInt32 symbol, UInt32 *ProbPrices)
647 {
648   UInt32 price = 0;
649   symbol |= 0x100;
650   do
651   {
652     price += GET_PRICEa(probs[symbol >> 8], (symbol >> 7) & 1);
653     symbol <<= 1;
654   }
655   while (symbol < 0x10000);
656   return price;
657 }
658 
LitEnc_GetPriceMatched(const CLzmaProb * probs,UInt32 symbol,UInt32 matchByte,UInt32 * ProbPrices)659 static UInt32 LitEnc_GetPriceMatched(const CLzmaProb *probs, UInt32 symbol, UInt32 matchByte, UInt32 *ProbPrices)
660 {
661   UInt32 price = 0;
662   UInt32 offs = 0x100;
663   symbol |= 0x100;
664   do
665   {
666     matchByte <<= 1;
667     price += GET_PRICEa(probs[offs + (matchByte & offs) + (symbol >> 8)], (symbol >> 7) & 1);
668     symbol <<= 1;
669     offs &= ~(matchByte ^ symbol);
670   }
671   while (symbol < 0x10000);
672   return price;
673 }
674 
675 
RcTree_Encode(CRangeEnc * rc,CLzmaProb * probs,int numBitLevels,UInt32 symbol)676 static void RcTree_Encode(CRangeEnc *rc, CLzmaProb *probs, int numBitLevels, UInt32 symbol)
677 {
678   UInt32 m = 1;
679   int i;
680   for (i = numBitLevels; i != 0;)
681   {
682     UInt32 bit;
683     i--;
684     bit = (symbol >> i) & 1;
685     RangeEnc_EncodeBit(rc, probs + m, bit);
686     m = (m << 1) | bit;
687   }
688 }
689 
RcTree_ReverseEncode(CRangeEnc * rc,CLzmaProb * probs,int numBitLevels,UInt32 symbol)690 static void RcTree_ReverseEncode(CRangeEnc *rc, CLzmaProb *probs, int numBitLevels, UInt32 symbol)
691 {
692   UInt32 m = 1;
693   int i;
694   for (i = 0; i < numBitLevels; i++)
695   {
696     UInt32 bit = symbol & 1;
697     RangeEnc_EncodeBit(rc, probs + m, bit);
698     m = (m << 1) | bit;
699     symbol >>= 1;
700   }
701 }
702 
RcTree_GetPrice(const CLzmaProb * probs,int numBitLevels,UInt32 symbol,UInt32 * ProbPrices)703 static UInt32 RcTree_GetPrice(const CLzmaProb *probs, int numBitLevels, UInt32 symbol, UInt32 *ProbPrices)
704 {
705   UInt32 price = 0;
706   symbol |= (1 << numBitLevels);
707   while (symbol != 1)
708   {
709     price += GET_PRICEa(probs[symbol >> 1], symbol & 1);
710     symbol >>= 1;
711   }
712   return price;
713 }
714 
RcTree_ReverseGetPrice(const CLzmaProb * probs,int numBitLevels,UInt32 symbol,UInt32 * ProbPrices)715 static UInt32 RcTree_ReverseGetPrice(const CLzmaProb *probs, int numBitLevels, UInt32 symbol, UInt32 *ProbPrices)
716 {
717   UInt32 price = 0;
718   UInt32 m = 1;
719   int i;
720   for (i = numBitLevels; i != 0; i--)
721   {
722     UInt32 bit = symbol & 1;
723     symbol >>= 1;
724     price += GET_PRICEa(probs[m], bit);
725     m = (m << 1) | bit;
726   }
727   return price;
728 }
729 
730 
LenEnc_Init(CLenEnc * p)731 static void LenEnc_Init(CLenEnc *p)
732 {
733   unsigned i;
734   p->choice = p->choice2 = kProbInitValue;
735   for (i = 0; i < (LZMA_NUM_PB_STATES_MAX << kLenNumLowBits); i++)
736     p->low[i] = kProbInitValue;
737   for (i = 0; i < (LZMA_NUM_PB_STATES_MAX << kLenNumMidBits); i++)
738     p->mid[i] = kProbInitValue;
739   for (i = 0; i < kLenNumHighSymbols; i++)
740     p->high[i] = kProbInitValue;
741 }
742 
LenEnc_Encode(CLenEnc * p,CRangeEnc * rc,UInt32 symbol,UInt32 posState)743 static void LenEnc_Encode(CLenEnc *p, CRangeEnc *rc, UInt32 symbol, UInt32 posState)
744 {
745   if (symbol < kLenNumLowSymbols)
746   {
747     RangeEnc_EncodeBit(rc, &p->choice, 0);
748     RcTree_Encode(rc, p->low + (posState << kLenNumLowBits), kLenNumLowBits, symbol);
749   }
750   else
751   {
752     RangeEnc_EncodeBit(rc, &p->choice, 1);
753     if (symbol < kLenNumLowSymbols + kLenNumMidSymbols)
754     {
755       RangeEnc_EncodeBit(rc, &p->choice2, 0);
756       RcTree_Encode(rc, p->mid + (posState << kLenNumMidBits), kLenNumMidBits, symbol - kLenNumLowSymbols);
757     }
758     else
759     {
760       RangeEnc_EncodeBit(rc, &p->choice2, 1);
761       RcTree_Encode(rc, p->high, kLenNumHighBits, symbol - kLenNumLowSymbols - kLenNumMidSymbols);
762     }
763   }
764 }
765 
LenEnc_SetPrices(CLenEnc * p,UInt32 posState,UInt32 numSymbols,UInt32 * prices,UInt32 * ProbPrices)766 static void LenEnc_SetPrices(CLenEnc *p, UInt32 posState, UInt32 numSymbols, UInt32 *prices, UInt32 *ProbPrices)
767 {
768   UInt32 a0 = GET_PRICE_0a(p->choice);
769   UInt32 a1 = GET_PRICE_1a(p->choice);
770   UInt32 b0 = a1 + GET_PRICE_0a(p->choice2);
771   UInt32 b1 = a1 + GET_PRICE_1a(p->choice2);
772   UInt32 i = 0;
773   for (i = 0; i < kLenNumLowSymbols; i++)
774   {
775     if (i >= numSymbols)
776       return;
777     prices[i] = a0 + RcTree_GetPrice(p->low + (posState << kLenNumLowBits), kLenNumLowBits, i, ProbPrices);
778   }
779   for (; i < kLenNumLowSymbols + kLenNumMidSymbols; i++)
780   {
781     if (i >= numSymbols)
782       return;
783     prices[i] = b0 + RcTree_GetPrice(p->mid + (posState << kLenNumMidBits), kLenNumMidBits, i - kLenNumLowSymbols, ProbPrices);
784   }
785   for (; i < numSymbols; i++)
786     prices[i] = b1 + RcTree_GetPrice(p->high, kLenNumHighBits, i - kLenNumLowSymbols - kLenNumMidSymbols, ProbPrices);
787 }
788 
LenPriceEnc_UpdateTable(CLenPriceEnc * p,UInt32 posState,UInt32 * ProbPrices)789 static void MY_FAST_CALL LenPriceEnc_UpdateTable(CLenPriceEnc *p, UInt32 posState, UInt32 *ProbPrices)
790 {
791   LenEnc_SetPrices(&p->p, posState, p->tableSize, p->prices[posState], ProbPrices);
792   p->counters[posState] = p->tableSize;
793 }
794 
LenPriceEnc_UpdateTables(CLenPriceEnc * p,UInt32 numPosStates,UInt32 * ProbPrices)795 static void LenPriceEnc_UpdateTables(CLenPriceEnc *p, UInt32 numPosStates, UInt32 *ProbPrices)
796 {
797   UInt32 posState;
798   for (posState = 0; posState < numPosStates; posState++)
799     LenPriceEnc_UpdateTable(p, posState, ProbPrices);
800 }
801 
LenEnc_Encode2(CLenPriceEnc * p,CRangeEnc * rc,UInt32 symbol,UInt32 posState,Bool updatePrice,UInt32 * ProbPrices)802 static void LenEnc_Encode2(CLenPriceEnc *p, CRangeEnc *rc, UInt32 symbol, UInt32 posState, Bool updatePrice, UInt32 *ProbPrices)
803 {
804   LenEnc_Encode(&p->p, rc, symbol, posState);
805   if (updatePrice)
806     if (--p->counters[posState] == 0)
807       LenPriceEnc_UpdateTable(p, posState, ProbPrices);
808 }
809 
810 
811 
812 
MovePos(CLzmaEnc * p,UInt32 num)813 static void MovePos(CLzmaEnc *p, UInt32 num)
814 {
815   #ifdef SHOW_STAT
816   g_STAT_OFFSET += num;
817   printf("\n MovePos %d", num);
818   #endif
819 
820   if (num != 0)
821   {
822     p->additionalOffset += num;
823     p->matchFinder.Skip(p->matchFinderObj, num);
824   }
825 }
826 
ReadMatchDistances(CLzmaEnc * p,UInt32 * numDistancePairsRes)827 static UInt32 ReadMatchDistances(CLzmaEnc *p, UInt32 *numDistancePairsRes)
828 {
829   UInt32 lenRes = 0, numPairs;
830   p->numAvail = p->matchFinder.GetNumAvailableBytes(p->matchFinderObj);
831   numPairs = p->matchFinder.GetMatches(p->matchFinderObj, p->matches);
832 
833   #ifdef SHOW_STAT
834   printf("\n i = %d numPairs = %d    ", g_STAT_OFFSET, numPairs / 2);
835   g_STAT_OFFSET++;
836   {
837     UInt32 i;
838     for (i = 0; i < numPairs; i += 2)
839       printf("%2d %6d   | ", p->matches[i], p->matches[i + 1]);
840   }
841   #endif
842 
843   if (numPairs > 0)
844   {
845     lenRes = p->matches[numPairs - 2];
846     if (lenRes == p->numFastBytes)
847     {
848       const Byte *pby = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1;
849       UInt32 distance = p->matches[numPairs - 1] + 1;
850       UInt32 numAvail = p->numAvail;
851       if (numAvail > LZMA_MATCH_LEN_MAX)
852         numAvail = LZMA_MATCH_LEN_MAX;
853       {
854         const Byte *pby2 = pby - distance;
855         for (; lenRes < numAvail && pby[lenRes] == pby2[lenRes]; lenRes++);
856       }
857     }
858   }
859   p->additionalOffset++;
860   *numDistancePairsRes = numPairs;
861   return lenRes;
862 }
863 
864 
865 #define MakeAsChar(p) (p)->backPrev = (UInt32)(-1); (p)->prev1IsChar = False;
866 #define MakeAsShortRep(p) (p)->backPrev = 0; (p)->prev1IsChar = False;
867 #define IsShortRep(p) ((p)->backPrev == 0)
868 
GetRepLen1Price(CLzmaEnc * p,UInt32 state,UInt32 posState)869 static UInt32 GetRepLen1Price(CLzmaEnc *p, UInt32 state, UInt32 posState)
870 {
871   return
872     GET_PRICE_0(p->isRepG0[state]) +
873     GET_PRICE_0(p->isRep0Long[state][posState]);
874 }
875 
GetPureRepPrice(CLzmaEnc * p,UInt32 repIndex,UInt32 state,UInt32 posState)876 static UInt32 GetPureRepPrice(CLzmaEnc *p, UInt32 repIndex, UInt32 state, UInt32 posState)
877 {
878   UInt32 price;
879   if (repIndex == 0)
880   {
881     price = GET_PRICE_0(p->isRepG0[state]);
882     price += GET_PRICE_1(p->isRep0Long[state][posState]);
883   }
884   else
885   {
886     price = GET_PRICE_1(p->isRepG0[state]);
887     if (repIndex == 1)
888       price += GET_PRICE_0(p->isRepG1[state]);
889     else
890     {
891       price += GET_PRICE_1(p->isRepG1[state]);
892       price += GET_PRICE(p->isRepG2[state], repIndex - 2);
893     }
894   }
895   return price;
896 }
897 
GetRepPrice(CLzmaEnc * p,UInt32 repIndex,UInt32 len,UInt32 state,UInt32 posState)898 static UInt32 GetRepPrice(CLzmaEnc *p, UInt32 repIndex, UInt32 len, UInt32 state, UInt32 posState)
899 {
900   return p->repLenEnc.prices[posState][len - LZMA_MATCH_LEN_MIN] +
901     GetPureRepPrice(p, repIndex, state, posState);
902 }
903 
Backward(CLzmaEnc * p,UInt32 * backRes,UInt32 cur)904 static UInt32 Backward(CLzmaEnc *p, UInt32 *backRes, UInt32 cur)
905 {
906   UInt32 posMem = p->opt[cur].posPrev;
907   UInt32 backMem = p->opt[cur].backPrev;
908   p->optimumEndIndex = cur;
909   do
910   {
911     if (p->opt[cur].prev1IsChar)
912     {
913       MakeAsChar(&p->opt[posMem])
914       p->opt[posMem].posPrev = posMem - 1;
915       if (p->opt[cur].prev2)
916       {
917         p->opt[posMem - 1].prev1IsChar = False;
918         p->opt[posMem - 1].posPrev = p->opt[cur].posPrev2;
919         p->opt[posMem - 1].backPrev = p->opt[cur].backPrev2;
920       }
921     }
922     {
923       UInt32 posPrev = posMem;
924       UInt32 backCur = backMem;
925 
926       backMem = p->opt[posPrev].backPrev;
927       posMem = p->opt[posPrev].posPrev;
928 
929       p->opt[posPrev].backPrev = backCur;
930       p->opt[posPrev].posPrev = cur;
931       cur = posPrev;
932     }
933   }
934   while (cur != 0);
935   *backRes = p->opt[0].backPrev;
936   p->optimumCurrentIndex  = p->opt[0].posPrev;
937   return p->optimumCurrentIndex;
938 }
939 
940 #define LIT_PROBS(pos, prevByte) (p->litProbs + ((((pos) & p->lpMask) << p->lc) + ((prevByte) >> (8 - p->lc))) * 0x300)
941 
GetOptimum(CLzmaEnc * p,UInt32 position,UInt32 * backRes)942 static UInt32 GetOptimum(CLzmaEnc *p, UInt32 position, UInt32 *backRes)
943 {
944   UInt32 numAvail, mainLen, numPairs, repMaxIndex, i, posState, lenEnd, len, cur;
945   UInt32 matchPrice, repMatchPrice, normalMatchPrice;
946   UInt32 reps[LZMA_NUM_REPS], repLens[LZMA_NUM_REPS];
947   UInt32 *matches;
948   const Byte *data;
949   Byte curByte, matchByte;
950   if (p->optimumEndIndex != p->optimumCurrentIndex)
951   {
952     const COptimal *opt = &p->opt[p->optimumCurrentIndex];
953     UInt32 lenRes = opt->posPrev - p->optimumCurrentIndex;
954     *backRes = opt->backPrev;
955     p->optimumCurrentIndex = opt->posPrev;
956     return lenRes;
957   }
958   p->optimumCurrentIndex = p->optimumEndIndex = 0;
959 
960   if (p->additionalOffset == 0)
961     mainLen = ReadMatchDistances(p, &numPairs);
962   else
963   {
964     mainLen = p->longestMatchLength;
965     numPairs = p->numPairs;
966   }
967 
968   numAvail = p->numAvail;
969   if (numAvail < 2)
970   {
971     *backRes = (UInt32)(-1);
972     return 1;
973   }
974   if (numAvail > LZMA_MATCH_LEN_MAX)
975     numAvail = LZMA_MATCH_LEN_MAX;
976 
977   data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1;
978   repMaxIndex = 0;
979   for (i = 0; i < LZMA_NUM_REPS; i++)
980   {
981     UInt32 lenTest;
982     const Byte *data2;
983     reps[i] = p->reps[i];
984     data2 = data - (reps[i] + 1);
985     if (data[0] != data2[0] || data[1] != data2[1])
986     {
987       repLens[i] = 0;
988       continue;
989     }
990     for (lenTest = 2; lenTest < numAvail && data[lenTest] == data2[lenTest]; lenTest++);
991     repLens[i] = lenTest;
992     if (lenTest > repLens[repMaxIndex])
993       repMaxIndex = i;
994   }
995   if (repLens[repMaxIndex] >= p->numFastBytes)
996   {
997     UInt32 lenRes;
998     *backRes = repMaxIndex;
999     lenRes = repLens[repMaxIndex];
1000     MovePos(p, lenRes - 1);
1001     return lenRes;
1002   }
1003 
1004   matches = p->matches;
1005   if (mainLen >= p->numFastBytes)
1006   {
1007     *backRes = matches[numPairs - 1] + LZMA_NUM_REPS;
1008     MovePos(p, mainLen - 1);
1009     return mainLen;
1010   }
1011   curByte = *data;
1012   matchByte = *(data - (reps[0] + 1));
1013 
1014   if (mainLen < 2 && curByte != matchByte && repLens[repMaxIndex] < 2)
1015   {
1016     *backRes = (UInt32)-1;
1017     return 1;
1018   }
1019 
1020   p->opt[0].state = (CState)p->state;
1021 
1022   posState = (position & p->pbMask);
1023 
1024   {
1025     const CLzmaProb *probs = LIT_PROBS(position, *(data - 1));
1026     p->opt[1].price = GET_PRICE_0(p->isMatch[p->state][posState]) +
1027         (!IsCharState(p->state) ?
1028           LitEnc_GetPriceMatched(probs, curByte, matchByte, p->ProbPrices) :
1029           LitEnc_GetPrice(probs, curByte, p->ProbPrices));
1030   }
1031 
1032   MakeAsChar(&p->opt[1]);
1033 
1034   matchPrice = GET_PRICE_1(p->isMatch[p->state][posState]);
1035   repMatchPrice = matchPrice + GET_PRICE_1(p->isRep[p->state]);
1036 
1037   if (matchByte == curByte)
1038   {
1039     UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(p, p->state, posState);
1040     if (shortRepPrice < p->opt[1].price)
1041     {
1042       p->opt[1].price = shortRepPrice;
1043       MakeAsShortRep(&p->opt[1]);
1044     }
1045   }
1046   lenEnd = ((mainLen >= repLens[repMaxIndex]) ? mainLen : repLens[repMaxIndex]);
1047 
1048   if (lenEnd < 2)
1049   {
1050     *backRes = p->opt[1].backPrev;
1051     return 1;
1052   }
1053 
1054   p->opt[1].posPrev = 0;
1055   for (i = 0; i < LZMA_NUM_REPS; i++)
1056     p->opt[0].backs[i] = reps[i];
1057 
1058   len = lenEnd;
1059   do
1060     p->opt[len--].price = kInfinityPrice;
1061   while (len >= 2);
1062 
1063   for (i = 0; i < LZMA_NUM_REPS; i++)
1064   {
1065     UInt32 repLen = repLens[i];
1066     UInt32 price;
1067     if (repLen < 2)
1068       continue;
1069     price = repMatchPrice + GetPureRepPrice(p, i, p->state, posState);
1070     do
1071     {
1072       UInt32 curAndLenPrice = price + p->repLenEnc.prices[posState][repLen - 2];
1073       COptimal *opt = &p->opt[repLen];
1074       if (curAndLenPrice < opt->price)
1075       {
1076         opt->price = curAndLenPrice;
1077         opt->posPrev = 0;
1078         opt->backPrev = i;
1079         opt->prev1IsChar = False;
1080       }
1081     }
1082     while (--repLen >= 2);
1083   }
1084 
1085   normalMatchPrice = matchPrice + GET_PRICE_0(p->isRep[p->state]);
1086 
1087   len = ((repLens[0] >= 2) ? repLens[0] + 1 : 2);
1088   if (len <= mainLen)
1089   {
1090     UInt32 offs = 0;
1091     while (len > matches[offs])
1092       offs += 2;
1093     for (; ; len++)
1094     {
1095       COptimal *opt;
1096       UInt32 distance = matches[offs + 1];
1097 
1098       UInt32 curAndLenPrice = normalMatchPrice + p->lenEnc.prices[posState][len - LZMA_MATCH_LEN_MIN];
1099       UInt32 lenToPosState = GetLenToPosState(len);
1100       if (distance < kNumFullDistances)
1101         curAndLenPrice += p->distancesPrices[lenToPosState][distance];
1102       else
1103       {
1104         UInt32 slot;
1105         GetPosSlot2(distance, slot);
1106         curAndLenPrice += p->alignPrices[distance & kAlignMask] + p->posSlotPrices[lenToPosState][slot];
1107       }
1108       opt = &p->opt[len];
1109       if (curAndLenPrice < opt->price)
1110       {
1111         opt->price = curAndLenPrice;
1112         opt->posPrev = 0;
1113         opt->backPrev = distance + LZMA_NUM_REPS;
1114         opt->prev1IsChar = False;
1115       }
1116       if (len == matches[offs])
1117       {
1118         offs += 2;
1119         if (offs == numPairs)
1120           break;
1121       }
1122     }
1123   }
1124 
1125   cur = 0;
1126 
1127     #ifdef SHOW_STAT2
1128     if (position >= 0)
1129     {
1130       unsigned i;
1131       printf("\n pos = %4X", position);
1132       for (i = cur; i <= lenEnd; i++)
1133       printf("\nprice[%4X] = %d", position - cur + i, p->opt[i].price);
1134     }
1135     #endif
1136 
1137   for (;;)
1138   {
1139     UInt32 numAvailFull, newLen, numPairs, posPrev, state, posState, startLen;
1140     UInt32 curPrice, curAnd1Price, matchPrice, repMatchPrice;
1141     Bool nextIsChar;
1142     Byte curByte, matchByte;
1143     const Byte *data;
1144     COptimal *curOpt;
1145     COptimal *nextOpt;
1146 
1147     cur++;
1148     if (cur == lenEnd)
1149       return Backward(p, backRes, cur);
1150 
1151     newLen = ReadMatchDistances(p, &numPairs);
1152     if (newLen >= p->numFastBytes)
1153     {
1154       p->numPairs = numPairs;
1155       p->longestMatchLength = newLen;
1156       return Backward(p, backRes, cur);
1157     }
1158     position++;
1159     curOpt = &p->opt[cur];
1160     posPrev = curOpt->posPrev;
1161     if (curOpt->prev1IsChar)
1162     {
1163       posPrev--;
1164       if (curOpt->prev2)
1165       {
1166         state = p->opt[curOpt->posPrev2].state;
1167         if (curOpt->backPrev2 < LZMA_NUM_REPS)
1168           state = kRepNextStates[state];
1169         else
1170           state = kMatchNextStates[state];
1171       }
1172       else
1173         state = p->opt[posPrev].state;
1174       state = kLiteralNextStates[state];
1175     }
1176     else
1177       state = p->opt[posPrev].state;
1178     if (posPrev == cur - 1)
1179     {
1180       if (IsShortRep(curOpt))
1181         state = kShortRepNextStates[state];
1182       else
1183         state = kLiteralNextStates[state];
1184     }
1185     else
1186     {
1187       UInt32 pos;
1188       const COptimal *prevOpt;
1189       if (curOpt->prev1IsChar && curOpt->prev2)
1190       {
1191         posPrev = curOpt->posPrev2;
1192         pos = curOpt->backPrev2;
1193         state = kRepNextStates[state];
1194       }
1195       else
1196       {
1197         pos = curOpt->backPrev;
1198         if (pos < LZMA_NUM_REPS)
1199           state = kRepNextStates[state];
1200         else
1201           state = kMatchNextStates[state];
1202       }
1203       prevOpt = &p->opt[posPrev];
1204       if (pos < LZMA_NUM_REPS)
1205       {
1206         UInt32 i;
1207         reps[0] = prevOpt->backs[pos];
1208         for (i = 1; i <= pos; i++)
1209           reps[i] = prevOpt->backs[i - 1];
1210         for (; i < LZMA_NUM_REPS; i++)
1211           reps[i] = prevOpt->backs[i];
1212       }
1213       else
1214       {
1215         UInt32 i;
1216         reps[0] = (pos - LZMA_NUM_REPS);
1217         for (i = 1; i < LZMA_NUM_REPS; i++)
1218           reps[i] = prevOpt->backs[i - 1];
1219       }
1220     }
1221     curOpt->state = (CState)state;
1222 
1223     curOpt->backs[0] = reps[0];
1224     curOpt->backs[1] = reps[1];
1225     curOpt->backs[2] = reps[2];
1226     curOpt->backs[3] = reps[3];
1227 
1228     curPrice = curOpt->price;
1229     nextIsChar = False;
1230     data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1;
1231     curByte = *data;
1232     matchByte = *(data - (reps[0] + 1));
1233 
1234     posState = (position & p->pbMask);
1235 
1236     curAnd1Price = curPrice + GET_PRICE_0(p->isMatch[state][posState]);
1237     {
1238       const CLzmaProb *probs = LIT_PROBS(position, *(data - 1));
1239       curAnd1Price +=
1240         (!IsCharState(state) ?
1241           LitEnc_GetPriceMatched(probs, curByte, matchByte, p->ProbPrices) :
1242           LitEnc_GetPrice(probs, curByte, p->ProbPrices));
1243     }
1244 
1245     nextOpt = &p->opt[cur + 1];
1246 
1247     if (curAnd1Price < nextOpt->price)
1248     {
1249       nextOpt->price = curAnd1Price;
1250       nextOpt->posPrev = cur;
1251       MakeAsChar(nextOpt);
1252       nextIsChar = True;
1253     }
1254 
1255     matchPrice = curPrice + GET_PRICE_1(p->isMatch[state][posState]);
1256     repMatchPrice = matchPrice + GET_PRICE_1(p->isRep[state]);
1257 
1258     if (matchByte == curByte && !(nextOpt->posPrev < cur && nextOpt->backPrev == 0))
1259     {
1260       UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(p, state, posState);
1261       if (shortRepPrice <= nextOpt->price)
1262       {
1263         nextOpt->price = shortRepPrice;
1264         nextOpt->posPrev = cur;
1265         MakeAsShortRep(nextOpt);
1266         nextIsChar = True;
1267       }
1268     }
1269     numAvailFull = p->numAvail;
1270     {
1271       UInt32 temp = kNumOpts - 1 - cur;
1272       if (temp < numAvailFull)
1273         numAvailFull = temp;
1274     }
1275 
1276     if (numAvailFull < 2)
1277       continue;
1278     numAvail = (numAvailFull <= p->numFastBytes ? numAvailFull : p->numFastBytes);
1279 
1280     if (!nextIsChar && matchByte != curByte) /* speed optimization */
1281     {
1282       /* try Literal + rep0 */
1283       UInt32 temp;
1284       UInt32 lenTest2;
1285       const Byte *data2 = data - (reps[0] + 1);
1286       UInt32 limit = p->numFastBytes + 1;
1287       if (limit > numAvailFull)
1288         limit = numAvailFull;
1289 
1290       for (temp = 1; temp < limit && data[temp] == data2[temp]; temp++);
1291       lenTest2 = temp - 1;
1292       if (lenTest2 >= 2)
1293       {
1294         UInt32 state2 = kLiteralNextStates[state];
1295         UInt32 posStateNext = (position + 1) & p->pbMask;
1296         UInt32 nextRepMatchPrice = curAnd1Price +
1297             GET_PRICE_1(p->isMatch[state2][posStateNext]) +
1298             GET_PRICE_1(p->isRep[state2]);
1299         /* for (; lenTest2 >= 2; lenTest2--) */
1300         {
1301           UInt32 curAndLenPrice;
1302           COptimal *opt;
1303           UInt32 offset = cur + 1 + lenTest2;
1304           while (lenEnd < offset)
1305             p->opt[++lenEnd].price = kInfinityPrice;
1306           curAndLenPrice = nextRepMatchPrice + GetRepPrice(p, 0, lenTest2, state2, posStateNext);
1307           opt = &p->opt[offset];
1308           if (curAndLenPrice < opt->price)
1309           {
1310             opt->price = curAndLenPrice;
1311             opt->posPrev = cur + 1;
1312             opt->backPrev = 0;
1313             opt->prev1IsChar = True;
1314             opt->prev2 = False;
1315           }
1316         }
1317       }
1318     }
1319 
1320     startLen = 2; /* speed optimization */
1321     {
1322     UInt32 repIndex;
1323     for (repIndex = 0; repIndex < LZMA_NUM_REPS; repIndex++)
1324     {
1325       UInt32 lenTest;
1326       UInt32 lenTestTemp;
1327       UInt32 price;
1328       const Byte *data2 = data - (reps[repIndex] + 1);
1329       if (data[0] != data2[0] || data[1] != data2[1])
1330         continue;
1331       for (lenTest = 2; lenTest < numAvail && data[lenTest] == data2[lenTest]; lenTest++);
1332       while (lenEnd < cur + lenTest)
1333         p->opt[++lenEnd].price = kInfinityPrice;
1334       lenTestTemp = lenTest;
1335       price = repMatchPrice + GetPureRepPrice(p, repIndex, state, posState);
1336       do
1337       {
1338         UInt32 curAndLenPrice = price + p->repLenEnc.prices[posState][lenTest - 2];
1339         COptimal *opt = &p->opt[cur + lenTest];
1340         if (curAndLenPrice < opt->price)
1341         {
1342           opt->price = curAndLenPrice;
1343           opt->posPrev = cur;
1344           opt->backPrev = repIndex;
1345           opt->prev1IsChar = False;
1346         }
1347       }
1348       while (--lenTest >= 2);
1349       lenTest = lenTestTemp;
1350 
1351       if (repIndex == 0)
1352         startLen = lenTest + 1;
1353 
1354       /* if (_maxMode) */
1355         {
1356           UInt32 lenTest2 = lenTest + 1;
1357           UInt32 limit = lenTest2 + p->numFastBytes;
1358           UInt32 nextRepMatchPrice;
1359           if (limit > numAvailFull)
1360             limit = numAvailFull;
1361           for (; lenTest2 < limit && data[lenTest2] == data2[lenTest2]; lenTest2++);
1362           lenTest2 -= lenTest + 1;
1363           if (lenTest2 >= 2)
1364           {
1365             UInt32 state2 = kRepNextStates[state];
1366             UInt32 posStateNext = (position + lenTest) & p->pbMask;
1367             UInt32 curAndLenCharPrice =
1368                 price + p->repLenEnc.prices[posState][lenTest - 2] +
1369                 GET_PRICE_0(p->isMatch[state2][posStateNext]) +
1370                 LitEnc_GetPriceMatched(LIT_PROBS(position + lenTest, data[lenTest - 1]),
1371                     data[lenTest], data2[lenTest], p->ProbPrices);
1372             state2 = kLiteralNextStates[state2];
1373             posStateNext = (position + lenTest + 1) & p->pbMask;
1374             nextRepMatchPrice = curAndLenCharPrice +
1375                 GET_PRICE_1(p->isMatch[state2][posStateNext]) +
1376                 GET_PRICE_1(p->isRep[state2]);
1377 
1378             /* for (; lenTest2 >= 2; lenTest2--) */
1379             {
1380               UInt32 curAndLenPrice;
1381               COptimal *opt;
1382               UInt32 offset = cur + lenTest + 1 + lenTest2;
1383               while (lenEnd < offset)
1384                 p->opt[++lenEnd].price = kInfinityPrice;
1385               curAndLenPrice = nextRepMatchPrice + GetRepPrice(p, 0, lenTest2, state2, posStateNext);
1386               opt = &p->opt[offset];
1387               if (curAndLenPrice < opt->price)
1388               {
1389                 opt->price = curAndLenPrice;
1390                 opt->posPrev = cur + lenTest + 1;
1391                 opt->backPrev = 0;
1392                 opt->prev1IsChar = True;
1393                 opt->prev2 = True;
1394                 opt->posPrev2 = cur;
1395                 opt->backPrev2 = repIndex;
1396               }
1397             }
1398           }
1399         }
1400     }
1401     }
1402     /* for (UInt32 lenTest = 2; lenTest <= newLen; lenTest++) */
1403     if (newLen > numAvail)
1404     {
1405       newLen = numAvail;
1406       for (numPairs = 0; newLen > matches[numPairs]; numPairs += 2);
1407       matches[numPairs] = newLen;
1408       numPairs += 2;
1409     }
1410     if (newLen >= startLen)
1411     {
1412       UInt32 normalMatchPrice = matchPrice + GET_PRICE_0(p->isRep[state]);
1413       UInt32 offs, curBack, posSlot;
1414       UInt32 lenTest;
1415       while (lenEnd < cur + newLen)
1416         p->opt[++lenEnd].price = kInfinityPrice;
1417 
1418       offs = 0;
1419       while (startLen > matches[offs])
1420         offs += 2;
1421       curBack = matches[offs + 1];
1422       GetPosSlot2(curBack, posSlot);
1423       for (lenTest = /*2*/ startLen; ; lenTest++)
1424       {
1425         UInt32 curAndLenPrice = normalMatchPrice + p->lenEnc.prices[posState][lenTest - LZMA_MATCH_LEN_MIN];
1426         UInt32 lenToPosState = GetLenToPosState(lenTest);
1427         COptimal *opt;
1428         if (curBack < kNumFullDistances)
1429           curAndLenPrice += p->distancesPrices[lenToPosState][curBack];
1430         else
1431           curAndLenPrice += p->posSlotPrices[lenToPosState][posSlot] + p->alignPrices[curBack & kAlignMask];
1432 
1433         opt = &p->opt[cur + lenTest];
1434         if (curAndLenPrice < opt->price)
1435         {
1436           opt->price = curAndLenPrice;
1437           opt->posPrev = cur;
1438           opt->backPrev = curBack + LZMA_NUM_REPS;
1439           opt->prev1IsChar = False;
1440         }
1441 
1442         if (/*_maxMode && */lenTest == matches[offs])
1443         {
1444           /* Try Match + Literal + Rep0 */
1445           const Byte *data2 = data - (curBack + 1);
1446           UInt32 lenTest2 = lenTest + 1;
1447           UInt32 limit = lenTest2 + p->numFastBytes;
1448           UInt32 nextRepMatchPrice;
1449           if (limit > numAvailFull)
1450             limit = numAvailFull;
1451           for (; lenTest2 < limit && data[lenTest2] == data2[lenTest2]; lenTest2++);
1452           lenTest2 -= lenTest + 1;
1453           if (lenTest2 >= 2)
1454           {
1455             UInt32 state2 = kMatchNextStates[state];
1456             UInt32 posStateNext = (position + lenTest) & p->pbMask;
1457             UInt32 curAndLenCharPrice = curAndLenPrice +
1458                 GET_PRICE_0(p->isMatch[state2][posStateNext]) +
1459                 LitEnc_GetPriceMatched(LIT_PROBS(position + lenTest, data[lenTest - 1]),
1460                     data[lenTest], data2[lenTest], p->ProbPrices);
1461             state2 = kLiteralNextStates[state2];
1462             posStateNext = (posStateNext + 1) & p->pbMask;
1463             nextRepMatchPrice = curAndLenCharPrice +
1464                 GET_PRICE_1(p->isMatch[state2][posStateNext]) +
1465                 GET_PRICE_1(p->isRep[state2]);
1466 
1467             /* for (; lenTest2 >= 2; lenTest2--) */
1468             {
1469               UInt32 offset = cur + lenTest + 1 + lenTest2;
1470               UInt32 curAndLenPrice;
1471               COptimal *opt;
1472               while (lenEnd < offset)
1473                 p->opt[++lenEnd].price = kInfinityPrice;
1474               curAndLenPrice = nextRepMatchPrice + GetRepPrice(p, 0, lenTest2, state2, posStateNext);
1475               opt = &p->opt[offset];
1476               if (curAndLenPrice < opt->price)
1477               {
1478                 opt->price = curAndLenPrice;
1479                 opt->posPrev = cur + lenTest + 1;
1480                 opt->backPrev = 0;
1481                 opt->prev1IsChar = True;
1482                 opt->prev2 = True;
1483                 opt->posPrev2 = cur;
1484                 opt->backPrev2 = curBack + LZMA_NUM_REPS;
1485               }
1486             }
1487           }
1488           offs += 2;
1489           if (offs == numPairs)
1490             break;
1491           curBack = matches[offs + 1];
1492           if (curBack >= kNumFullDistances)
1493             GetPosSlot2(curBack, posSlot);
1494         }
1495       }
1496     }
1497   }
1498 }
1499 
1500 #define ChangePair(smallDist, bigDist) (((bigDist) >> 7) > (smallDist))
1501 
GetOptimumFast(CLzmaEnc * p,UInt32 * backRes)1502 static UInt32 GetOptimumFast(CLzmaEnc *p, UInt32 *backRes)
1503 {
1504   UInt32 numAvail, mainLen, mainDist, numPairs, repIndex, repLen, i;
1505   const Byte *data;
1506   const UInt32 *matches;
1507 
1508   if (p->additionalOffset == 0)
1509     mainLen = ReadMatchDistances(p, &numPairs);
1510   else
1511   {
1512     mainLen = p->longestMatchLength;
1513     numPairs = p->numPairs;
1514   }
1515 
1516   numAvail = p->numAvail;
1517   *backRes = (UInt32)-1;
1518   if (numAvail < 2)
1519     return 1;
1520   if (numAvail > LZMA_MATCH_LEN_MAX)
1521     numAvail = LZMA_MATCH_LEN_MAX;
1522   data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1;
1523 
1524   repLen = repIndex = 0;
1525   for (i = 0; i < LZMA_NUM_REPS; i++)
1526   {
1527     UInt32 len;
1528     const Byte *data2 = data - (p->reps[i] + 1);
1529     if (data[0] != data2[0] || data[1] != data2[1])
1530       continue;
1531     for (len = 2; len < numAvail && data[len] == data2[len]; len++);
1532     if (len >= p->numFastBytes)
1533     {
1534       *backRes = i;
1535       MovePos(p, len - 1);
1536       return len;
1537     }
1538     if (len > repLen)
1539     {
1540       repIndex = i;
1541       repLen = len;
1542     }
1543   }
1544 
1545   matches = p->matches;
1546   if (mainLen >= p->numFastBytes)
1547   {
1548     *backRes = matches[numPairs - 1] + LZMA_NUM_REPS;
1549     MovePos(p, mainLen - 1);
1550     return mainLen;
1551   }
1552 
1553   mainDist = 0; /* for GCC */
1554   if (mainLen >= 2)
1555   {
1556     mainDist = matches[numPairs - 1];
1557     while (numPairs > 2 && mainLen == matches[numPairs - 4] + 1)
1558     {
1559       if (!ChangePair(matches[numPairs - 3], mainDist))
1560         break;
1561       numPairs -= 2;
1562       mainLen = matches[numPairs - 2];
1563       mainDist = matches[numPairs - 1];
1564     }
1565     if (mainLen == 2 && mainDist >= 0x80)
1566       mainLen = 1;
1567   }
1568 
1569   if (repLen >= 2 && (
1570         (repLen + 1 >= mainLen) ||
1571         (repLen + 2 >= mainLen && mainDist >= (1 << 9)) ||
1572         (repLen + 3 >= mainLen && mainDist >= (1 << 15))))
1573   {
1574     *backRes = repIndex;
1575     MovePos(p, repLen - 1);
1576     return repLen;
1577   }
1578 
1579   if (mainLen < 2 || numAvail <= 2)
1580     return 1;
1581 
1582   p->longestMatchLength = ReadMatchDistances(p, &p->numPairs);
1583   if (p->longestMatchLength >= 2)
1584   {
1585     UInt32 newDistance = matches[p->numPairs - 1];
1586     if ((p->longestMatchLength >= mainLen && newDistance < mainDist) ||
1587         (p->longestMatchLength == mainLen + 1 && !ChangePair(mainDist, newDistance)) ||
1588         (p->longestMatchLength > mainLen + 1) ||
1589         (p->longestMatchLength + 1 >= mainLen && mainLen >= 3 && ChangePair(newDistance, mainDist)))
1590       return 1;
1591   }
1592 
1593   data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1;
1594   for (i = 0; i < LZMA_NUM_REPS; i++)
1595   {
1596     UInt32 len, limit;
1597     const Byte *data2 = data - (p->reps[i] + 1);
1598     if (data[0] != data2[0] || data[1] != data2[1])
1599       continue;
1600     limit = mainLen - 1;
1601     for (len = 2; len < limit && data[len] == data2[len]; len++);
1602     if (len >= limit)
1603       return 1;
1604   }
1605   *backRes = mainDist + LZMA_NUM_REPS;
1606   MovePos(p, mainLen - 2);
1607   return mainLen;
1608 }
1609 
WriteEndMarker(CLzmaEnc * p,UInt32 posState)1610 static void WriteEndMarker(CLzmaEnc *p, UInt32 posState)
1611 {
1612   UInt32 len;
1613   RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][posState], 1);
1614   RangeEnc_EncodeBit(&p->rc, &p->isRep[p->state], 0);
1615   p->state = kMatchNextStates[p->state];
1616   len = LZMA_MATCH_LEN_MIN;
1617   LenEnc_Encode2(&p->lenEnc, &p->rc, len - LZMA_MATCH_LEN_MIN, posState, !p->fastMode, p->ProbPrices);
1618   RcTree_Encode(&p->rc, p->posSlotEncoder[GetLenToPosState(len)], kNumPosSlotBits, (1 << kNumPosSlotBits) - 1);
1619   RangeEnc_EncodeDirectBits(&p->rc, (((UInt32)1 << 30) - 1) >> kNumAlignBits, 30 - kNumAlignBits);
1620   RcTree_ReverseEncode(&p->rc, p->posAlignEncoder, kNumAlignBits, kAlignMask);
1621 }
1622 
CheckErrors(CLzmaEnc * p)1623 static SRes CheckErrors(CLzmaEnc *p)
1624 {
1625   if (p->result != SZ_OK)
1626     return p->result;
1627   if (p->rc.res != SZ_OK)
1628     p->result = SZ_ERROR_WRITE;
1629   if (p->matchFinderBase.result != SZ_OK)
1630     p->result = SZ_ERROR_READ;
1631   if (p->result != SZ_OK)
1632     p->finished = True;
1633   return p->result;
1634 }
1635 
Flush(CLzmaEnc * p,UInt32 nowPos)1636 static SRes Flush(CLzmaEnc *p, UInt32 nowPos)
1637 {
1638   /* ReleaseMFStream(); */
1639   p->finished = True;
1640   if (p->writeEndMark)
1641     WriteEndMarker(p, nowPos & p->pbMask);
1642   RangeEnc_FlushData(&p->rc);
1643   RangeEnc_FlushStream(&p->rc);
1644   return CheckErrors(p);
1645 }
1646 
FillAlignPrices(CLzmaEnc * p)1647 static void FillAlignPrices(CLzmaEnc *p)
1648 {
1649   UInt32 i;
1650   for (i = 0; i < kAlignTableSize; i++)
1651     p->alignPrices[i] = RcTree_ReverseGetPrice(p->posAlignEncoder, kNumAlignBits, i, p->ProbPrices);
1652   p->alignPriceCount = 0;
1653 }
1654 
FillDistancesPrices(CLzmaEnc * p)1655 static void FillDistancesPrices(CLzmaEnc *p)
1656 {
1657   UInt32 tempPrices[kNumFullDistances];
1658   UInt32 i, lenToPosState;
1659   for (i = kStartPosModelIndex; i < kNumFullDistances; i++)
1660   {
1661     UInt32 posSlot = GetPosSlot1(i);
1662     UInt32 footerBits = ((posSlot >> 1) - 1);
1663     UInt32 base = ((2 | (posSlot & 1)) << footerBits);
1664     tempPrices[i] = RcTree_ReverseGetPrice(p->posEncoders + base - posSlot - 1, footerBits, i - base, p->ProbPrices);
1665   }
1666 
1667   for (lenToPosState = 0; lenToPosState < kNumLenToPosStates; lenToPosState++)
1668   {
1669     UInt32 posSlot;
1670     const CLzmaProb *encoder = p->posSlotEncoder[lenToPosState];
1671     UInt32 *posSlotPrices = p->posSlotPrices[lenToPosState];
1672     for (posSlot = 0; posSlot < p->distTableSize; posSlot++)
1673       posSlotPrices[posSlot] = RcTree_GetPrice(encoder, kNumPosSlotBits, posSlot, p->ProbPrices);
1674     for (posSlot = kEndPosModelIndex; posSlot < p->distTableSize; posSlot++)
1675       posSlotPrices[posSlot] += ((((posSlot >> 1) - 1) - kNumAlignBits) << kNumBitPriceShiftBits);
1676 
1677     {
1678       UInt32 *distancesPrices = p->distancesPrices[lenToPosState];
1679       UInt32 i;
1680       for (i = 0; i < kStartPosModelIndex; i++)
1681         distancesPrices[i] = posSlotPrices[i];
1682       for (; i < kNumFullDistances; i++)
1683         distancesPrices[i] = posSlotPrices[GetPosSlot1(i)] + tempPrices[i];
1684     }
1685   }
1686   p->matchPriceCount = 0;
1687 }
1688 
LzmaEnc_Construct(CLzmaEnc * p)1689 void LzmaEnc_Construct(CLzmaEnc *p)
1690 {
1691   RangeEnc_Construct(&p->rc);
1692   MatchFinder_Construct(&p->matchFinderBase);
1693   #ifndef _7ZIP_ST
1694   MatchFinderMt_Construct(&p->matchFinderMt);
1695   p->matchFinderMt.MatchFinder = &p->matchFinderBase;
1696   #endif
1697 
1698   {
1699     CLzmaEncProps props;
1700     LzmaEncProps_Init(&props);
1701     LzmaEnc_SetProps(p, &props);
1702   }
1703 
1704   #ifndef LZMA_LOG_BSR
1705   LzmaEnc_FastPosInit(p->g_FastPos);
1706   #endif
1707 
1708   LzmaEnc_InitPriceTables(p->ProbPrices);
1709   p->litProbs = 0;
1710   p->saveState.litProbs = 0;
1711 }
1712 
LzmaEnc_Create(ISzAlloc * alloc)1713 CLzmaEncHandle LzmaEnc_Create(ISzAlloc *alloc)
1714 {
1715   void *p;
1716   p = alloc->Alloc(alloc, sizeof(CLzmaEnc));
1717   if (p != 0)
1718     LzmaEnc_Construct((CLzmaEnc *)p);
1719   return p;
1720 }
1721 
LzmaEnc_FreeLits(CLzmaEnc * p,ISzAlloc * alloc)1722 void LzmaEnc_FreeLits(CLzmaEnc *p, ISzAlloc *alloc)
1723 {
1724   alloc->Free(alloc, p->litProbs);
1725   alloc->Free(alloc, p->saveState.litProbs);
1726   p->litProbs = 0;
1727   p->saveState.litProbs = 0;
1728 }
1729 
LzmaEnc_Destruct(CLzmaEnc * p,ISzAlloc * alloc,ISzAlloc * allocBig)1730 void LzmaEnc_Destruct(CLzmaEnc *p, ISzAlloc *alloc, ISzAlloc *allocBig)
1731 {
1732   #ifndef _7ZIP_ST
1733   MatchFinderMt_Destruct(&p->matchFinderMt, allocBig);
1734   #endif
1735   MatchFinder_Free(&p->matchFinderBase, allocBig);
1736   LzmaEnc_FreeLits(p, alloc);
1737   RangeEnc_Free(&p->rc, alloc);
1738 }
1739 
LzmaEnc_Destroy(CLzmaEncHandle p,ISzAlloc * alloc,ISzAlloc * allocBig)1740 void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAlloc *alloc, ISzAlloc *allocBig)
1741 {
1742   LzmaEnc_Destruct((CLzmaEnc *)p, alloc, allocBig);
1743   alloc->Free(alloc, p);
1744 }
1745 
LzmaEnc_CodeOneBlock(CLzmaEnc * p,Bool useLimits,UInt32 maxPackSize,UInt32 maxUnpackSize)1746 static SRes LzmaEnc_CodeOneBlock(CLzmaEnc *p, Bool useLimits, UInt32 maxPackSize, UInt32 maxUnpackSize)
1747 {
1748   UInt32 nowPos32, startPos32;
1749   if (p->needInit)
1750   {
1751     p->matchFinder.Init(p->matchFinderObj);
1752     p->needInit = 0;
1753   }
1754 
1755   if (p->finished)
1756     return p->result;
1757   RINOK(CheckErrors(p));
1758 
1759   nowPos32 = (UInt32)p->nowPos64;
1760   startPos32 = nowPos32;
1761 
1762   if (p->nowPos64 == 0)
1763   {
1764     UInt32 numPairs;
1765     Byte curByte;
1766     if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) == 0)
1767       return Flush(p, nowPos32);
1768     ReadMatchDistances(p, &numPairs);
1769     RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][0], 0);
1770     p->state = kLiteralNextStates[p->state];
1771     curByte = p->matchFinder.GetIndexByte(p->matchFinderObj, 0 - p->additionalOffset);
1772     LitEnc_Encode(&p->rc, p->litProbs, curByte);
1773     p->additionalOffset--;
1774     nowPos32++;
1775   }
1776 
1777   if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) != 0)
1778   for (;;)
1779   {
1780     UInt32 pos, len, posState;
1781 
1782     if (p->fastMode)
1783       len = GetOptimumFast(p, &pos);
1784     else
1785       len = GetOptimum(p, nowPos32, &pos);
1786 
1787     #ifdef SHOW_STAT2
1788     printf("\n pos = %4X,   len = %d   pos = %d", nowPos32, len, pos);
1789     #endif
1790 
1791     posState = nowPos32 & p->pbMask;
1792     if (len == 1 && pos == (UInt32)-1)
1793     {
1794       Byte curByte;
1795       CLzmaProb *probs;
1796       const Byte *data;
1797 
1798       RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][posState], 0);
1799       data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset;
1800       curByte = *data;
1801       probs = LIT_PROBS(nowPos32, *(data - 1));
1802       if (IsCharState(p->state))
1803         LitEnc_Encode(&p->rc, probs, curByte);
1804       else
1805         LitEnc_EncodeMatched(&p->rc, probs, curByte, *(data - p->reps[0] - 1));
1806       p->state = kLiteralNextStates[p->state];
1807     }
1808     else
1809     {
1810       RangeEnc_EncodeBit(&p->rc, &p->isMatch[p->state][posState], 1);
1811       if (pos < LZMA_NUM_REPS)
1812       {
1813         RangeEnc_EncodeBit(&p->rc, &p->isRep[p->state], 1);
1814         if (pos == 0)
1815         {
1816           RangeEnc_EncodeBit(&p->rc, &p->isRepG0[p->state], 0);
1817           RangeEnc_EncodeBit(&p->rc, &p->isRep0Long[p->state][posState], ((len == 1) ? 0 : 1));
1818         }
1819         else
1820         {
1821           UInt32 distance = p->reps[pos];
1822           RangeEnc_EncodeBit(&p->rc, &p->isRepG0[p->state], 1);
1823           if (pos == 1)
1824             RangeEnc_EncodeBit(&p->rc, &p->isRepG1[p->state], 0);
1825           else
1826           {
1827             RangeEnc_EncodeBit(&p->rc, &p->isRepG1[p->state], 1);
1828             RangeEnc_EncodeBit(&p->rc, &p->isRepG2[p->state], pos - 2);
1829             if (pos == 3)
1830               p->reps[3] = p->reps[2];
1831             p->reps[2] = p->reps[1];
1832           }
1833           p->reps[1] = p->reps[0];
1834           p->reps[0] = distance;
1835         }
1836         if (len == 1)
1837           p->state = kShortRepNextStates[p->state];
1838         else
1839         {
1840           LenEnc_Encode2(&p->repLenEnc, &p->rc, len - LZMA_MATCH_LEN_MIN, posState, !p->fastMode, p->ProbPrices);
1841           p->state = kRepNextStates[p->state];
1842         }
1843       }
1844       else
1845       {
1846         UInt32 posSlot;
1847         RangeEnc_EncodeBit(&p->rc, &p->isRep[p->state], 0);
1848         p->state = kMatchNextStates[p->state];
1849         LenEnc_Encode2(&p->lenEnc, &p->rc, len - LZMA_MATCH_LEN_MIN, posState, !p->fastMode, p->ProbPrices);
1850         pos -= LZMA_NUM_REPS;
1851         GetPosSlot(pos, posSlot);
1852         RcTree_Encode(&p->rc, p->posSlotEncoder[GetLenToPosState(len)], kNumPosSlotBits, posSlot);
1853 
1854         if (posSlot >= kStartPosModelIndex)
1855         {
1856           UInt32 footerBits = ((posSlot >> 1) - 1);
1857           UInt32 base = ((2 | (posSlot & 1)) << footerBits);
1858           UInt32 posReduced = pos - base;
1859 
1860           if (posSlot < kEndPosModelIndex)
1861             RcTree_ReverseEncode(&p->rc, p->posEncoders + base - posSlot - 1, footerBits, posReduced);
1862           else
1863           {
1864             RangeEnc_EncodeDirectBits(&p->rc, posReduced >> kNumAlignBits, footerBits - kNumAlignBits);
1865             RcTree_ReverseEncode(&p->rc, p->posAlignEncoder, kNumAlignBits, posReduced & kAlignMask);
1866             p->alignPriceCount++;
1867           }
1868         }
1869         p->reps[3] = p->reps[2];
1870         p->reps[2] = p->reps[1];
1871         p->reps[1] = p->reps[0];
1872         p->reps[0] = pos;
1873         p->matchPriceCount++;
1874       }
1875     }
1876     p->additionalOffset -= len;
1877     nowPos32 += len;
1878     if (p->additionalOffset == 0)
1879     {
1880       UInt32 processed;
1881       if (!p->fastMode)
1882       {
1883         if (p->matchPriceCount >= (1 << 7))
1884           FillDistancesPrices(p);
1885         if (p->alignPriceCount >= kAlignTableSize)
1886           FillAlignPrices(p);
1887       }
1888       if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) == 0)
1889         break;
1890       processed = nowPos32 - startPos32;
1891       if (useLimits)
1892       {
1893         if (processed + kNumOpts + 300 >= maxUnpackSize ||
1894             RangeEnc_GetProcessed(&p->rc) + kNumOpts * 2 >= maxPackSize)
1895           break;
1896       }
1897       else if (processed >= (1 << 15))
1898       {
1899         p->nowPos64 += nowPos32 - startPos32;
1900         return CheckErrors(p);
1901       }
1902     }
1903   }
1904   p->nowPos64 += nowPos32 - startPos32;
1905   return Flush(p, nowPos32);
1906 }
1907 
1908 #define kBigHashDicLimit ((UInt32)1 << 24)
1909 
LzmaEnc_Alloc(CLzmaEnc * p,UInt32 keepWindowSize,ISzAlloc * alloc,ISzAlloc * allocBig)1910 static SRes LzmaEnc_Alloc(CLzmaEnc *p, UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig)
1911 {
1912   UInt32 beforeSize = kNumOpts;
1913   if (!RangeEnc_Alloc(&p->rc, alloc))
1914     return SZ_ERROR_MEM;
1915   #ifndef _7ZIP_ST
1916   p->mtMode = (p->multiThread && !p->fastMode && (p->matchFinderBase.btMode != 0));
1917   #endif
1918 
1919   {
1920     unsigned lclp = p->lc + p->lp;
1921     if (p->litProbs == 0 || p->saveState.litProbs == 0 || p->lclp != lclp)
1922     {
1923       LzmaEnc_FreeLits(p, alloc);
1924       p->litProbs = (CLzmaProb *)alloc->Alloc(alloc, (0x300 << lclp) * sizeof(CLzmaProb));
1925       p->saveState.litProbs = (CLzmaProb *)alloc->Alloc(alloc, (0x300 << lclp) * sizeof(CLzmaProb));
1926       if (p->litProbs == 0 || p->saveState.litProbs == 0)
1927       {
1928         LzmaEnc_FreeLits(p, alloc);
1929         return SZ_ERROR_MEM;
1930       }
1931       p->lclp = lclp;
1932     }
1933   }
1934 
1935   p->matchFinderBase.bigHash = (p->dictSize > kBigHashDicLimit);
1936 
1937   if (beforeSize + p->dictSize < keepWindowSize)
1938     beforeSize = keepWindowSize - p->dictSize;
1939 
1940   #ifndef _7ZIP_ST
1941   if (p->mtMode)
1942   {
1943     RINOK(MatchFinderMt_Create(&p->matchFinderMt, p->dictSize, beforeSize, p->numFastBytes, LZMA_MATCH_LEN_MAX, allocBig));
1944     p->matchFinderObj = &p->matchFinderMt;
1945     MatchFinderMt_CreateVTable(&p->matchFinderMt, &p->matchFinder);
1946   }
1947   else
1948   #endif
1949   {
1950     if (!MatchFinder_Create(&p->matchFinderBase, p->dictSize, beforeSize, p->numFastBytes, LZMA_MATCH_LEN_MAX, allocBig))
1951       return SZ_ERROR_MEM;
1952     p->matchFinderObj = &p->matchFinderBase;
1953     MatchFinder_CreateVTable(&p->matchFinderBase, &p->matchFinder);
1954   }
1955   return SZ_OK;
1956 }
1957 
LzmaEnc_Init(CLzmaEnc * p)1958 void LzmaEnc_Init(CLzmaEnc *p)
1959 {
1960   UInt32 i;
1961   p->state = 0;
1962   for (i = 0 ; i < LZMA_NUM_REPS; i++)
1963     p->reps[i] = 0;
1964 
1965   RangeEnc_Init(&p->rc);
1966 
1967 
1968   for (i = 0; i < kNumStates; i++)
1969   {
1970     UInt32 j;
1971     for (j = 0; j < LZMA_NUM_PB_STATES_MAX; j++)
1972     {
1973       p->isMatch[i][j] = kProbInitValue;
1974       p->isRep0Long[i][j] = kProbInitValue;
1975     }
1976     p->isRep[i] = kProbInitValue;
1977     p->isRepG0[i] = kProbInitValue;
1978     p->isRepG1[i] = kProbInitValue;
1979     p->isRepG2[i] = kProbInitValue;
1980   }
1981 
1982   {
1983     UInt32 num = 0x300 << (p->lp + p->lc);
1984     for (i = 0; i < num; i++)
1985       p->litProbs[i] = kProbInitValue;
1986   }
1987 
1988   {
1989     for (i = 0; i < kNumLenToPosStates; i++)
1990     {
1991       CLzmaProb *probs = p->posSlotEncoder[i];
1992       UInt32 j;
1993       for (j = 0; j < (1 << kNumPosSlotBits); j++)
1994         probs[j] = kProbInitValue;
1995     }
1996   }
1997   {
1998     for (i = 0; i < kNumFullDistances - kEndPosModelIndex; i++)
1999       p->posEncoders[i] = kProbInitValue;
2000   }
2001 
2002   LenEnc_Init(&p->lenEnc.p);
2003   LenEnc_Init(&p->repLenEnc.p);
2004 
2005   for (i = 0; i < (1 << kNumAlignBits); i++)
2006     p->posAlignEncoder[i] = kProbInitValue;
2007 
2008   p->optimumEndIndex = 0;
2009   p->optimumCurrentIndex = 0;
2010   p->additionalOffset = 0;
2011 
2012   p->pbMask = (1 << p->pb) - 1;
2013   p->lpMask = (1 << p->lp) - 1;
2014 }
2015 
LzmaEnc_InitPrices(CLzmaEnc * p)2016 void LzmaEnc_InitPrices(CLzmaEnc *p)
2017 {
2018   if (!p->fastMode)
2019   {
2020     FillDistancesPrices(p);
2021     FillAlignPrices(p);
2022   }
2023 
2024   p->lenEnc.tableSize =
2025   p->repLenEnc.tableSize =
2026       p->numFastBytes + 1 - LZMA_MATCH_LEN_MIN;
2027   LenPriceEnc_UpdateTables(&p->lenEnc, 1 << p->pb, p->ProbPrices);
2028   LenPriceEnc_UpdateTables(&p->repLenEnc, 1 << p->pb, p->ProbPrices);
2029 }
2030 
LzmaEnc_AllocAndInit(CLzmaEnc * p,UInt32 keepWindowSize,ISzAlloc * alloc,ISzAlloc * allocBig)2031 static SRes LzmaEnc_AllocAndInit(CLzmaEnc *p, UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig)
2032 {
2033   UInt32 i;
2034   for (i = 0; i < (UInt32)kDicLogSizeMaxCompress; i++)
2035     if (p->dictSize <= ((UInt32)1 << i))
2036       break;
2037   p->distTableSize = i * 2;
2038 
2039   p->finished = False;
2040   p->result = SZ_OK;
2041   RINOK(LzmaEnc_Alloc(p, keepWindowSize, alloc, allocBig));
2042   LzmaEnc_Init(p);
2043   LzmaEnc_InitPrices(p);
2044   p->nowPos64 = 0;
2045   return SZ_OK;
2046 }
2047 
LzmaEnc_Prepare(CLzmaEncHandle pp,ISeqOutStream * outStream,ISeqInStream * inStream,ISzAlloc * alloc,ISzAlloc * allocBig)2048 static SRes LzmaEnc_Prepare(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream,
2049     ISzAlloc *alloc, ISzAlloc *allocBig)
2050 {
2051   CLzmaEnc *p = (CLzmaEnc *)pp;
2052   p->matchFinderBase.stream = inStream;
2053   p->needInit = 1;
2054   p->rc.outStream = outStream;
2055   return LzmaEnc_AllocAndInit(p, 0, alloc, allocBig);
2056 }
2057 
LzmaEnc_PrepareForLzma2(CLzmaEncHandle pp,ISeqInStream * inStream,UInt32 keepWindowSize,ISzAlloc * alloc,ISzAlloc * allocBig)2058 SRes LzmaEnc_PrepareForLzma2(CLzmaEncHandle pp,
2059     ISeqInStream *inStream, UInt32 keepWindowSize,
2060     ISzAlloc *alloc, ISzAlloc *allocBig)
2061 {
2062   CLzmaEnc *p = (CLzmaEnc *)pp;
2063   p->matchFinderBase.stream = inStream;
2064   p->needInit = 1;
2065   return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig);
2066 }
2067 
LzmaEnc_SetInputBuf(CLzmaEnc * p,const Byte * src,SizeT srcLen)2068 static void LzmaEnc_SetInputBuf(CLzmaEnc *p, const Byte *src, SizeT srcLen)
2069 {
2070   p->matchFinderBase.directInput = 1;
2071   p->matchFinderBase.bufferBase = (Byte *)src;
2072   p->matchFinderBase.directInputRem = srcLen;
2073 }
2074 
LzmaEnc_MemPrepare(CLzmaEncHandle pp,const Byte * src,SizeT srcLen,UInt32 keepWindowSize,ISzAlloc * alloc,ISzAlloc * allocBig)2075 SRes LzmaEnc_MemPrepare(CLzmaEncHandle pp, const Byte *src, SizeT srcLen,
2076     UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig)
2077 {
2078   CLzmaEnc *p = (CLzmaEnc *)pp;
2079   LzmaEnc_SetInputBuf(p, src, srcLen);
2080   p->needInit = 1;
2081 
2082   return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig);
2083 }
2084 
LzmaEnc_Finish(CLzmaEncHandle pp)2085 void LzmaEnc_Finish(CLzmaEncHandle pp)
2086 {
2087   #ifndef _7ZIP_ST
2088   CLzmaEnc *p = (CLzmaEnc *)pp;
2089   if (p->mtMode)
2090     MatchFinderMt_ReleaseStream(&p->matchFinderMt);
2091   #else
2092   pp = pp;
2093   #endif
2094 }
2095 
2096 typedef struct
2097 {
2098   ISeqOutStream funcTable;
2099   Byte *data;
2100   SizeT rem;
2101   Bool overflow;
2102 } CSeqOutStreamBuf;
2103 
MyWrite(void * pp,const void * data,size_t size)2104 static size_t MyWrite(void *pp, const void *data, size_t size)
2105 {
2106   CSeqOutStreamBuf *p = (CSeqOutStreamBuf *)pp;
2107   if (p->rem < size)
2108   {
2109     size = p->rem;
2110     p->overflow = True;
2111   }
2112   memcpy(p->data, data, size);
2113   p->rem -= size;
2114   p->data += size;
2115   return size;
2116 }
2117 
2118 
LzmaEnc_GetNumAvailableBytes(CLzmaEncHandle pp)2119 UInt32 LzmaEnc_GetNumAvailableBytes(CLzmaEncHandle pp)
2120 {
2121   const CLzmaEnc *p = (CLzmaEnc *)pp;
2122   return p->matchFinder.GetNumAvailableBytes(p->matchFinderObj);
2123 }
2124 
LzmaEnc_GetCurBuf(CLzmaEncHandle pp)2125 const Byte *LzmaEnc_GetCurBuf(CLzmaEncHandle pp)
2126 {
2127   const CLzmaEnc *p = (CLzmaEnc *)pp;
2128   return p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset;
2129 }
2130 
LzmaEnc_CodeOneMemBlock(CLzmaEncHandle pp,Bool reInit,Byte * dest,size_t * destLen,UInt32 desiredPackSize,UInt32 * unpackSize)2131 SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle pp, Bool reInit,
2132     Byte *dest, size_t *destLen, UInt32 desiredPackSize, UInt32 *unpackSize)
2133 {
2134   CLzmaEnc *p = (CLzmaEnc *)pp;
2135   UInt64 nowPos64;
2136   SRes res;
2137   CSeqOutStreamBuf outStream;
2138 
2139   outStream.funcTable.Write = MyWrite;
2140   outStream.data = dest;
2141   outStream.rem = *destLen;
2142   outStream.overflow = False;
2143 
2144   p->writeEndMark = False;
2145   p->finished = False;
2146   p->result = SZ_OK;
2147 
2148   if (reInit)
2149     LzmaEnc_Init(p);
2150   LzmaEnc_InitPrices(p);
2151   nowPos64 = p->nowPos64;
2152   RangeEnc_Init(&p->rc);
2153   p->rc.outStream = &outStream.funcTable;
2154 
2155   res = LzmaEnc_CodeOneBlock(p, True, desiredPackSize, *unpackSize);
2156 
2157   *unpackSize = (UInt32)(p->nowPos64 - nowPos64);
2158   *destLen -= outStream.rem;
2159   if (outStream.overflow)
2160     return SZ_ERROR_OUTPUT_EOF;
2161 
2162   return res;
2163 }
2164 
LzmaEnc_Encode2(CLzmaEnc * p,ICompressProgress * progress)2165 static SRes LzmaEnc_Encode2(CLzmaEnc *p, ICompressProgress *progress)
2166 {
2167   SRes res = SZ_OK;
2168 
2169   #ifndef _7ZIP_ST
2170   Byte allocaDummy[0x300];
2171   allocaDummy[0] = 0;
2172   allocaDummy[1] = allocaDummy[0];
2173   #endif
2174 
2175   for (;;)
2176   {
2177     res = LzmaEnc_CodeOneBlock(p, False, 0, 0);
2178     if (res != SZ_OK || p->finished != 0)
2179       break;
2180     if (progress != 0)
2181     {
2182       res = progress->Progress(progress, p->nowPos64, RangeEnc_GetProcessed(&p->rc));
2183       if (res != SZ_OK)
2184       {
2185         res = SZ_ERROR_PROGRESS;
2186         break;
2187       }
2188     }
2189   }
2190   LzmaEnc_Finish(p);
2191   return res;
2192 }
2193 
LzmaEnc_Encode(CLzmaEncHandle pp,ISeqOutStream * outStream,ISeqInStream * inStream,ICompressProgress * progress,ISzAlloc * alloc,ISzAlloc * allocBig)2194 SRes LzmaEnc_Encode(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress,
2195     ISzAlloc *alloc, ISzAlloc *allocBig)
2196 {
2197   RINOK(LzmaEnc_Prepare(pp, outStream, inStream, alloc, allocBig));
2198   return LzmaEnc_Encode2((CLzmaEnc *)pp, progress);
2199 }
2200 
LzmaEnc_WriteProperties(CLzmaEncHandle pp,Byte * props,SizeT * size)2201 SRes LzmaEnc_WriteProperties(CLzmaEncHandle pp, Byte *props, SizeT *size)
2202 {
2203   CLzmaEnc *p = (CLzmaEnc *)pp;
2204   int i;
2205   UInt32 dictSize = p->dictSize;
2206   if (*size < LZMA_PROPS_SIZE)
2207     return SZ_ERROR_PARAM;
2208   *size = LZMA_PROPS_SIZE;
2209   props[0] = (Byte)((p->pb * 5 + p->lp) * 9 + p->lc);
2210 
2211   for (i = 11; i <= 30; i++)
2212   {
2213     if (dictSize <= ((UInt32)2 << i))
2214     {
2215       dictSize = (2 << i);
2216       break;
2217     }
2218     if (dictSize <= ((UInt32)3 << i))
2219     {
2220       dictSize = (3 << i);
2221       break;
2222     }
2223   }
2224 
2225   for (i = 0; i < 4; i++)
2226     props[1 + i] = (Byte)(dictSize >> (8 * i));
2227   return SZ_OK;
2228 }
2229 
LzmaEnc_MemEncode(CLzmaEncHandle pp,Byte * dest,SizeT * destLen,const Byte * src,SizeT srcLen,int writeEndMark,ICompressProgress * progress,ISzAlloc * alloc,ISzAlloc * allocBig)2230 SRes LzmaEnc_MemEncode(CLzmaEncHandle pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
2231     int writeEndMark, ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig)
2232 {
2233   SRes res;
2234   CLzmaEnc *p = (CLzmaEnc *)pp;
2235 
2236   CSeqOutStreamBuf outStream;
2237 
2238   LzmaEnc_SetInputBuf(p, src, srcLen);
2239 
2240   outStream.funcTable.Write = MyWrite;
2241   outStream.data = dest;
2242   outStream.rem = *destLen;
2243   outStream.overflow = False;
2244 
2245   p->writeEndMark = writeEndMark;
2246 
2247   p->rc.outStream = &outStream.funcTable;
2248   res = LzmaEnc_MemPrepare(pp, src, srcLen, 0, alloc, allocBig);
2249   if (res == SZ_OK)
2250     res = LzmaEnc_Encode2(p, progress);
2251 
2252   *destLen -= outStream.rem;
2253   if (outStream.overflow)
2254     return SZ_ERROR_OUTPUT_EOF;
2255   return res;
2256 }
2257 
LzmaEncode(Byte * dest,SizeT * destLen,const Byte * src,SizeT srcLen,const CLzmaEncProps * props,Byte * propsEncoded,SizeT * propsSize,int writeEndMark,ICompressProgress * progress,ISzAlloc * alloc,ISzAlloc * allocBig)2258 SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
2259     const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark,
2260     ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig)
2261 {
2262   CLzmaEnc *p = (CLzmaEnc *)LzmaEnc_Create(alloc);
2263   SRes res;
2264   if (p == 0)
2265     return SZ_ERROR_MEM;
2266 
2267   res = LzmaEnc_SetProps(p, props);
2268   if (res == SZ_OK)
2269   {
2270     res = LzmaEnc_WriteProperties(p, propsEncoded, propsSize);
2271     if (res == SZ_OK)
2272       res = LzmaEnc_MemEncode(p, dest, destLen, src, srcLen,
2273           writeEndMark, progress, alloc, allocBig);
2274   }
2275 
2276   LzmaEnc_Destroy(p, alloc, allocBig);
2277   return res;
2278 }
2279