1 // BZip2Encoder.cpp
2 
3 #include "StdAfx.h"
4 
5 #include "../../../C/Alloc.h"
6 #include "../../../C/BwtSort.h"
7 #include "../../../C/HuffEnc.h"
8 
9 #include "BZip2Crc.h"
10 #include "BZip2Encoder.h"
11 #include "Mtf8.h"
12 
13 namespace NCompress {
14 namespace NBZip2 {
15 
16 const unsigned kMaxHuffmanLenForEncoding = 16; // it must be < kMaxHuffmanLen = 20
17 
18 static const UInt32 kBufferSize = (1 << 17);
19 static const unsigned kNumHuffPasses = 4;
20 
Alloc()21 bool CThreadInfo::Alloc()
22 {
23   if (!m_BlockSorterIndex)
24   {
25     m_BlockSorterIndex = (UInt32 *)::BigAlloc(BLOCK_SORT_BUF_SIZE(kBlockSizeMax) * sizeof(UInt32));
26     if (!m_BlockSorterIndex)
27       return false;
28   }
29 
30   if (!m_Block)
31   {
32     m_Block = (Byte *)::MidAlloc(kBlockSizeMax * 5 + kBlockSizeMax / 10 + (20 << 10));
33     if (!m_Block)
34       return false;
35     m_MtfArray = m_Block + kBlockSizeMax;
36     m_TempArray = m_MtfArray + kBlockSizeMax * 2 + 2;
37   }
38   return true;
39 }
40 
Free()41 void CThreadInfo::Free()
42 {
43   ::BigFree(m_BlockSorterIndex);
44   m_BlockSorterIndex = NULL;
45   ::MidFree(m_Block);
46   m_Block = NULL;
47 }
48 
49 #ifndef _7ZIP_ST
50 
MFThread(void * threadCoderInfo)51 static THREAD_FUNC_DECL MFThread(void *threadCoderInfo)
52 {
53   return ((CThreadInfo *)threadCoderInfo)->ThreadFunc();
54 }
55 
Create()56 HRESULT CThreadInfo::Create()
57 {
58   WRes             wres = StreamWasFinishedEvent.Create();
59   if (wres == 0) { wres = WaitingWasStartedEvent.Create();
60   if (wres == 0) { wres = CanWriteEvent.Create();
61   if (wres == 0)
62   {
63     if (Encoder->_props.Affinity != 0)
64       wres = Thread.Create_With_Affinity(MFThread, this, (CAffinityMask)Encoder->_props.Affinity);
65     else
66       wres = Thread.Create(MFThread, this);
67   }}}
68   return HRESULT_FROM_WIN32(wres);
69 }
70 
FinishStream(bool needLeave)71 void CThreadInfo::FinishStream(bool needLeave)
72 {
73   Encoder->StreamWasFinished = true;
74   StreamWasFinishedEvent.Set();
75   if (needLeave)
76     Encoder->CS.Leave();
77   Encoder->CanStartWaitingEvent.Lock();
78   WaitingWasStartedEvent.Set();
79 }
80 
ThreadFunc()81 THREAD_FUNC_RET_TYPE CThreadInfo::ThreadFunc()
82 {
83   for (;;)
84   {
85     Encoder->CanProcessEvent.Lock();
86     Encoder->CS.Enter();
87     if (Encoder->CloseThreads)
88     {
89       Encoder->CS.Leave();
90       return 0;
91     }
92     if (Encoder->StreamWasFinished)
93     {
94       FinishStream(true);
95       continue;
96     }
97     HRESULT res = S_OK;
98     bool needLeave = true;
99     try
100     {
101       UInt32 blockSize = Encoder->ReadRleBlock(m_Block);
102       m_PackSize = Encoder->m_InStream.GetProcessedSize();
103       m_BlockIndex = Encoder->NextBlockIndex;
104       if (++Encoder->NextBlockIndex == Encoder->NumThreads)
105         Encoder->NextBlockIndex = 0;
106       if (blockSize == 0)
107       {
108         FinishStream(true);
109         continue;
110       }
111       Encoder->CS.Leave();
112       needLeave = false;
113       res = EncodeBlock3(blockSize);
114     }
115     catch(const CInBufferException &e)  { res = e.ErrorCode; }
116     catch(const COutBufferException &e) { res = e.ErrorCode; }
117     catch(...) { res = E_FAIL; }
118     if (res != S_OK)
119     {
120       Encoder->Result = res;
121       FinishStream(needLeave);
122       continue;
123     }
124   }
125 }
126 
127 #endif
128 
Normalize(int level)129 void CEncProps::Normalize(int level)
130 {
131   if (level < 0) level = 5;
132   if (level > 9) level = 9;
133 
134   if (NumPasses == (UInt32)(Int32)-1)
135     NumPasses = (level >= 9 ? 7 : (level >= 7 ? 2 : 1));
136   if (NumPasses < 1) NumPasses = 1;
137   if (NumPasses > kNumPassesMax) NumPasses = kNumPassesMax;
138 
139   if (BlockSizeMult == (UInt32)(Int32)-1)
140     BlockSizeMult = (level >= 5 ? 9 : (level >= 1 ? (unsigned)level * 2 - 1: 1));
141   if (BlockSizeMult < kBlockSizeMultMin) BlockSizeMult = kBlockSizeMultMin;
142   if (BlockSizeMult > kBlockSizeMultMax) BlockSizeMult = kBlockSizeMultMax;
143 }
144 
CEncoder()145 CEncoder::CEncoder()
146 {
147   _props.Normalize(-1);
148 
149   #ifndef _7ZIP_ST
150   ThreadsInfo = NULL;
151   m_NumThreadsPrev = 0;
152   NumThreads = 1;
153   #endif
154 }
155 
156 #ifndef _7ZIP_ST
~CEncoder()157 CEncoder::~CEncoder()
158 {
159   Free();
160 }
161 
Create()162 HRESULT CEncoder::Create()
163 {
164   {
165     WRes             wres = CanProcessEvent.CreateIfNotCreated_Reset();
166     if (wres == 0) { wres = CanStartWaitingEvent.CreateIfNotCreated_Reset(); }
167     if (wres != 0)
168       return HRESULT_FROM_WIN32(wres);
169   }
170 
171   if (ThreadsInfo && m_NumThreadsPrev == NumThreads)
172     return S_OK;
173   try
174   {
175     Free();
176     MtMode = (NumThreads > 1);
177     m_NumThreadsPrev = NumThreads;
178     ThreadsInfo = new CThreadInfo[NumThreads];
179     if (!ThreadsInfo)
180       return E_OUTOFMEMORY;
181   }
182   catch(...) { return E_OUTOFMEMORY; }
183   for (UInt32 t = 0; t < NumThreads; t++)
184   {
185     CThreadInfo &ti = ThreadsInfo[t];
186     ti.Encoder = this;
187     if (MtMode)
188     {
189       HRESULT res = ti.Create();
190       if (res != S_OK)
191       {
192         NumThreads = t;
193         Free();
194         return res;
195       }
196     }
197   }
198   return S_OK;
199 }
200 
Free()201 void CEncoder::Free()
202 {
203   if (!ThreadsInfo)
204     return;
205   CloseThreads = true;
206   CanProcessEvent.Set();
207   for (UInt32 t = 0; t < NumThreads; t++)
208   {
209     CThreadInfo &ti = ThreadsInfo[t];
210     if (MtMode)
211       ti.Thread.Wait_Close();
212     ti.Free();
213   }
214   delete []ThreadsInfo;
215   ThreadsInfo = NULL;
216 }
217 #endif
218 
ReadRleBlock(Byte * buffer)219 UInt32 CEncoder::ReadRleBlock(Byte *buffer)
220 {
221   UInt32 i = 0;
222   Byte prevByte;
223   if (m_InStream.ReadByte(prevByte))
224   {
225     UInt32 blockSize = _props.BlockSizeMult * kBlockSizeStep - 1;
226     unsigned numReps = 1;
227     buffer[i++] = prevByte;
228     while (i < blockSize) // "- 1" to support RLE
229     {
230       Byte b;
231       if (!m_InStream.ReadByte(b))
232         break;
233       if (b != prevByte)
234       {
235         if (numReps >= kRleModeRepSize)
236           buffer[i++] = (Byte)(numReps - kRleModeRepSize);
237         buffer[i++] = b;
238         numReps = 1;
239         prevByte = b;
240         continue;
241       }
242       numReps++;
243       if (numReps <= kRleModeRepSize)
244         buffer[i++] = b;
245       else if (numReps == kRleModeRepSize + 255)
246       {
247         buffer[i++] = (Byte)(numReps - kRleModeRepSize);
248         numReps = 0;
249       }
250     }
251     // it's to support original BZip2 decoder
252     if (numReps >= kRleModeRepSize)
253       buffer[i++] = (Byte)(numReps - kRleModeRepSize);
254   }
255   return i;
256 }
257 
WriteBits2(UInt32 value,unsigned numBits)258 void CThreadInfo::WriteBits2(UInt32 value, unsigned numBits) { m_OutStreamCurrent->WriteBits(value, numBits); }
WriteByte2(Byte b)259 void CThreadInfo::WriteByte2(Byte b) { WriteBits2(b, 8); }
WriteBit2(Byte v)260 void CThreadInfo::WriteBit2(Byte v) { WriteBits2(v, 1); }
WriteCrc2(UInt32 v)261 void CThreadInfo::WriteCrc2(UInt32 v)
262 {
263   for (unsigned i = 0; i < 4; i++)
264     WriteByte2(((Byte)(v >> (24 - i * 8))));
265 }
266 
WriteBits(UInt32 value,unsigned numBits)267 void CEncoder::WriteBits(UInt32 value, unsigned numBits) { m_OutStream.WriteBits(value, numBits); }
WriteByte(Byte b)268 void CEncoder::WriteByte(Byte b) { WriteBits(b, 8); }
269 // void CEncoder::WriteBit(Byte v) { WriteBits(v, 1); }
WriteCrc(UInt32 v)270 void CEncoder::WriteCrc(UInt32 v)
271 {
272   for (unsigned i = 0; i < 4; i++)
273     WriteByte(((Byte)(v >> (24 - i * 8))));
274 }
275 
276 
277 // blockSize > 0
EncodeBlock(const Byte * block,UInt32 blockSize)278 void CThreadInfo::EncodeBlock(const Byte *block, UInt32 blockSize)
279 {
280   WriteBit2(0); // Randomised = false
281 
282   {
283     UInt32 origPtr = BlockSort(m_BlockSorterIndex, block, blockSize);
284     // if (m_BlockSorterIndex[origPtr] != 0) throw 1;
285     m_BlockSorterIndex[origPtr] = blockSize;
286     WriteBits2(origPtr, kNumOrigBits);
287   }
288 
289   CMtf8Encoder mtf;
290   unsigned numInUse = 0;
291   {
292     Byte inUse[256];
293     Byte inUse16[16];
294     UInt32 i;
295     for (i = 0; i < 256; i++)
296       inUse[i] = 0;
297     for (i = 0; i < 16; i++)
298       inUse16[i] = 0;
299     for (i = 0; i < blockSize; i++)
300       inUse[block[i]] = 1;
301     for (i = 0; i < 256; i++)
302       if (inUse[i])
303       {
304         inUse16[i >> 4] = 1;
305         mtf.Buf[numInUse++] = (Byte)i;
306       }
307     for (i = 0; i < 16; i++)
308       WriteBit2(inUse16[i]);
309     for (i = 0; i < 256; i++)
310       if (inUse16[i >> 4])
311         WriteBit2(inUse[i]);
312   }
313   unsigned alphaSize = numInUse + 2;
314 
315   Byte *mtfs = m_MtfArray;
316   UInt32 mtfArraySize = 0;
317   UInt32 symbolCounts[kMaxAlphaSize];
318   {
319     for (unsigned i = 0; i < kMaxAlphaSize; i++)
320       symbolCounts[i] = 0;
321   }
322 
323   {
324     UInt32 rleSize = 0;
325     UInt32 i = 0;
326     const UInt32 *bsIndex = m_BlockSorterIndex;
327     block--;
328     do
329     {
330       unsigned pos = mtf.FindAndMove(block[bsIndex[i]]);
331       if (pos == 0)
332         rleSize++;
333       else
334       {
335         while (rleSize != 0)
336         {
337           rleSize--;
338           mtfs[mtfArraySize++] = (Byte)(rleSize & 1);
339           symbolCounts[rleSize & 1]++;
340           rleSize >>= 1;
341         }
342         if (pos >= 0xFE)
343         {
344           mtfs[mtfArraySize++] = 0xFF;
345           mtfs[mtfArraySize++] = (Byte)(pos - 0xFE);
346         }
347         else
348           mtfs[mtfArraySize++] = (Byte)(pos + 1);
349         symbolCounts[(size_t)pos + 1]++;
350       }
351     }
352     while (++i < blockSize);
353 
354     while (rleSize != 0)
355     {
356       rleSize--;
357       mtfs[mtfArraySize++] = (Byte)(rleSize & 1);
358       symbolCounts[rleSize & 1]++;
359       rleSize >>= 1;
360     }
361 
362     if (alphaSize < 256)
363       mtfs[mtfArraySize++] = (Byte)(alphaSize - 1);
364     else
365     {
366       mtfs[mtfArraySize++] = 0xFF;
367       mtfs[mtfArraySize++] = (Byte)(alphaSize - 256);
368     }
369     symbolCounts[(size_t)alphaSize - 1]++;
370   }
371 
372   UInt32 numSymbols = 0;
373   {
374     for (unsigned i = 0; i < kMaxAlphaSize; i++)
375       numSymbols += symbolCounts[i];
376   }
377 
378   unsigned bestNumTables = kNumTablesMin;
379   UInt32 bestPrice = 0xFFFFFFFF;
380   UInt32 startPos = m_OutStreamCurrent->GetPos();
381   Byte startCurByte = m_OutStreamCurrent->GetCurByte();
382   for (unsigned nt = kNumTablesMin; nt <= kNumTablesMax + 1; nt++)
383   {
384     unsigned numTables;
385 
386     if (m_OptimizeNumTables)
387     {
388       m_OutStreamCurrent->SetPos(startPos);
389       m_OutStreamCurrent->SetCurState((startPos & 7), startCurByte);
390       if (nt <= kNumTablesMax)
391         numTables = nt;
392       else
393         numTables = bestNumTables;
394     }
395     else
396     {
397       if (numSymbols < 200)  numTables = 2;
398       else if (numSymbols < 600) numTables = 3;
399       else if (numSymbols < 1200) numTables = 4;
400       else if (numSymbols < 2400) numTables = 5;
401       else numTables = 6;
402     }
403 
404     WriteBits2(numTables, kNumTablesBits);
405 
406     UInt32 numSelectors = (numSymbols + kGroupSize - 1) / kGroupSize;
407     WriteBits2(numSelectors, kNumSelectorsBits);
408 
409     {
410       UInt32 remFreq = numSymbols;
411       unsigned gs = 0;
412       unsigned t = numTables;
413       do
414       {
415         UInt32 tFreq = remFreq / t;
416         unsigned ge = gs;
417         UInt32 aFreq = 0;
418         while (aFreq < tFreq) //  && ge < alphaSize)
419           aFreq += symbolCounts[ge++];
420 
421         if (ge > gs + 1 && t != numTables && t != 1 && (((numTables - t) & 1) == 1))
422           aFreq -= symbolCounts[--ge];
423 
424         Byte *lens = Lens[(size_t)t - 1];
425         unsigned i = 0;
426         do
427           lens[i] = (Byte)((i >= gs && i < ge) ? 0 : 1);
428         while (++i < alphaSize);
429         gs = ge;
430         remFreq -= aFreq;
431       }
432       while (--t != 0);
433     }
434 
435 
436     for (unsigned pass = 0; pass < kNumHuffPasses; pass++)
437     {
438       {
439         unsigned t = 0;
440         do
441           memset(Freqs[t], 0, sizeof(Freqs[t]));
442         while (++t < numTables);
443       }
444 
445       {
446         UInt32 mtfPos = 0;
447         UInt32 g = 0;
448         do
449         {
450           UInt32 symbols[kGroupSize];
451           unsigned i = 0;
452           do
453           {
454             UInt32 symbol = mtfs[mtfPos++];
455             if (symbol >= 0xFF)
456               symbol += mtfs[mtfPos++];
457             symbols[i] = symbol;
458           }
459           while (++i < kGroupSize && mtfPos < mtfArraySize);
460 
461           UInt32 bestPrice2 = 0xFFFFFFFF;
462           unsigned t = 0;
463           do
464           {
465             const Byte *lens = Lens[t];
466             UInt32 price = 0;
467             unsigned j = 0;
468             do
469               price += lens[symbols[j]];
470             while (++j < i);
471             if (price < bestPrice2)
472             {
473               m_Selectors[g] = (Byte)t;
474               bestPrice2 = price;
475             }
476           }
477           while (++t < numTables);
478           UInt32 *freqs = Freqs[m_Selectors[g++]];
479           unsigned j = 0;
480           do
481             freqs[symbols[j]]++;
482           while (++j < i);
483         }
484         while (mtfPos < mtfArraySize);
485       }
486 
487       unsigned t = 0;
488       do
489       {
490         UInt32 *freqs = Freqs[t];
491         unsigned i = 0;
492         do
493           if (freqs[i] == 0)
494             freqs[i] = 1;
495         while (++i < alphaSize);
496         Huffman_Generate(freqs, Codes[t], Lens[t], kMaxAlphaSize, kMaxHuffmanLenForEncoding);
497       }
498       while (++t < numTables);
499     }
500 
501     {
502       Byte mtfSel[kNumTablesMax];
503       {
504         unsigned t = 0;
505         do
506           mtfSel[t] = (Byte)t;
507         while (++t < numTables);
508       }
509 
510       UInt32 i = 0;
511       do
512       {
513         Byte sel = m_Selectors[i];
514         unsigned pos;
515         for (pos = 0; mtfSel[pos] != sel; pos++)
516           WriteBit2(1);
517         WriteBit2(0);
518         for (; pos > 0; pos--)
519           mtfSel[pos] = mtfSel[(size_t)pos - 1];
520         mtfSel[0] = sel;
521       }
522       while (++i < numSelectors);
523     }
524 
525     {
526       unsigned t = 0;
527       do
528       {
529         const Byte *lens = Lens[t];
530         UInt32 len = lens[0];
531         WriteBits2(len, kNumLevelsBits);
532         unsigned i = 0;
533         do
534         {
535           UInt32 level = lens[i];
536           while (len != level)
537           {
538             WriteBit2(1);
539             if (len < level)
540             {
541               WriteBit2(0);
542               len++;
543             }
544             else
545             {
546               WriteBit2(1);
547               len--;
548             }
549           }
550           WriteBit2(0);
551         }
552         while (++i < alphaSize);
553       }
554       while (++t < numTables);
555     }
556 
557     {
558       UInt32 groupSize = 0;
559       UInt32 groupIndex = 0;
560       const Byte *lens = 0;
561       const UInt32 *codes = 0;
562       UInt32 mtfPos = 0;
563       do
564       {
565         UInt32 symbol = mtfs[mtfPos++];
566         if (symbol >= 0xFF)
567           symbol += mtfs[mtfPos++];
568         if (groupSize == 0)
569         {
570           groupSize = kGroupSize;
571           unsigned t = m_Selectors[groupIndex++];
572           lens = Lens[t];
573           codes = Codes[t];
574         }
575         groupSize--;
576         m_OutStreamCurrent->WriteBits(codes[symbol], lens[symbol]);
577       }
578       while (mtfPos < mtfArraySize);
579     }
580 
581     if (!m_OptimizeNumTables)
582       break;
583     UInt32 price = m_OutStreamCurrent->GetPos() - startPos;
584     if (price <= bestPrice)
585     {
586       if (nt == kNumTablesMax)
587         break;
588       bestPrice = price;
589       bestNumTables = nt;
590     }
591   }
592 }
593 
594 // blockSize > 0
EncodeBlockWithHeaders(const Byte * block,UInt32 blockSize)595 UInt32 CThreadInfo::EncodeBlockWithHeaders(const Byte *block, UInt32 blockSize)
596 {
597   WriteByte2(kBlockSig0);
598   WriteByte2(kBlockSig1);
599   WriteByte2(kBlockSig2);
600   WriteByte2(kBlockSig3);
601   WriteByte2(kBlockSig4);
602   WriteByte2(kBlockSig5);
603 
604   CBZip2Crc crc;
605   unsigned numReps = 0;
606   Byte prevByte = block[0];
607   UInt32 i = 0;
608   do
609   {
610     Byte b = block[i];
611     if (numReps == kRleModeRepSize)
612     {
613       for (; b > 0; b--)
614         crc.UpdateByte(prevByte);
615       numReps = 0;
616       continue;
617     }
618     if (prevByte == b)
619       numReps++;
620     else
621     {
622       numReps = 1;
623       prevByte = b;
624     }
625     crc.UpdateByte(b);
626   }
627   while (++i < blockSize);
628   UInt32 crcRes = crc.GetDigest();
629   WriteCrc2(crcRes);
630   EncodeBlock(block, blockSize);
631   return crcRes;
632 }
633 
EncodeBlock2(const Byte * block,UInt32 blockSize,UInt32 numPasses)634 void CThreadInfo::EncodeBlock2(const Byte *block, UInt32 blockSize, UInt32 numPasses)
635 {
636   UInt32 numCrcs = m_NumCrcs;
637   bool needCompare = false;
638 
639   UInt32 startBytePos = m_OutStreamCurrent->GetBytePos();
640   UInt32 startPos = m_OutStreamCurrent->GetPos();
641   Byte startCurByte = m_OutStreamCurrent->GetCurByte();
642   Byte endCurByte = 0;
643   UInt32 endPos = 0;
644   if (numPasses > 1 && blockSize >= (1 << 10))
645   {
646     UInt32 blockSize0 = blockSize / 2; // ????
647 
648     for (; (block[blockSize0] == block[(size_t)blockSize0 - 1]
649             || block[(size_t)blockSize0 - 1] == block[(size_t)blockSize0 - 2])
650           && blockSize0 < blockSize;
651         blockSize0++);
652 
653     if (blockSize0 < blockSize)
654     {
655       EncodeBlock2(block, blockSize0, numPasses - 1);
656       EncodeBlock2(block + blockSize0, blockSize - blockSize0, numPasses - 1);
657       endPos = m_OutStreamCurrent->GetPos();
658       endCurByte = m_OutStreamCurrent->GetCurByte();
659       if ((endPos & 7) > 0)
660         WriteBits2(0, 8 - (endPos & 7));
661       m_OutStreamCurrent->SetCurState((startPos & 7), startCurByte);
662       needCompare = true;
663     }
664   }
665 
666   UInt32 startBytePos2 = m_OutStreamCurrent->GetBytePos();
667   UInt32 startPos2 = m_OutStreamCurrent->GetPos();
668   UInt32 crcVal = EncodeBlockWithHeaders(block, blockSize);
669   UInt32 endPos2 = m_OutStreamCurrent->GetPos();
670 
671   if (needCompare)
672   {
673     UInt32 size2 = endPos2 - startPos2;
674     if (size2 < endPos - startPos)
675     {
676       UInt32 numBytes = m_OutStreamCurrent->GetBytePos() - startBytePos2;
677       Byte *buffer = m_OutStreamCurrent->GetStream();
678       for (UInt32 i = 0; i < numBytes; i++)
679         buffer[startBytePos + i] = buffer[startBytePos2 + i];
680       m_OutStreamCurrent->SetPos(startPos + endPos2 - startPos2);
681       m_NumCrcs = numCrcs;
682       m_CRCs[m_NumCrcs++] = crcVal;
683     }
684     else
685     {
686       m_OutStreamCurrent->SetPos(endPos);
687       m_OutStreamCurrent->SetCurState((endPos & 7), endCurByte);
688     }
689   }
690   else
691   {
692     m_NumCrcs = numCrcs;
693     m_CRCs[m_NumCrcs++] = crcVal;
694   }
695 }
696 
EncodeBlock3(UInt32 blockSize)697 HRESULT CThreadInfo::EncodeBlock3(UInt32 blockSize)
698 {
699   CMsbfEncoderTemp outStreamTemp;
700   outStreamTemp.SetStream(m_TempArray);
701   outStreamTemp.Init();
702   m_OutStreamCurrent = &outStreamTemp;
703 
704   m_NumCrcs = 0;
705 
706   EncodeBlock2(m_Block, blockSize, Encoder->_props.NumPasses);
707 
708   #ifndef _7ZIP_ST
709   if (Encoder->MtMode)
710     Encoder->ThreadsInfo[m_BlockIndex].CanWriteEvent.Lock();
711   #endif
712   for (UInt32 i = 0; i < m_NumCrcs; i++)
713     Encoder->CombinedCrc.Update(m_CRCs[i]);
714   Encoder->WriteBytes(m_TempArray, outStreamTemp.GetPos(), outStreamTemp.GetCurByte());
715   HRESULT res = S_OK;
716   #ifndef _7ZIP_ST
717   if (Encoder->MtMode)
718   {
719     UInt32 blockIndex = m_BlockIndex + 1;
720     if (blockIndex == Encoder->NumThreads)
721       blockIndex = 0;
722 
723     if (Encoder->Progress)
724     {
725       UInt64 unpackSize = Encoder->m_OutStream.GetProcessedSize();
726       res = Encoder->Progress->SetRatioInfo(&m_PackSize, &unpackSize);
727     }
728 
729     Encoder->ThreadsInfo[blockIndex].CanWriteEvent.Set();
730   }
731   #endif
732   return res;
733 }
734 
WriteBytes(const Byte * data,UInt32 sizeInBits,Byte lastByte)735 void CEncoder::WriteBytes(const Byte *data, UInt32 sizeInBits, Byte lastByte)
736 {
737   UInt32 bytesSize = (sizeInBits >> 3);
738   for (UInt32 i = 0; i < bytesSize; i++)
739     m_OutStream.WriteBits(data[i], 8);
740   WriteBits(lastByte, (sizeInBits & 7));
741 }
742 
743 
CodeReal(ISequentialInStream * inStream,ISequentialOutStream * outStream,const UInt64 *,const UInt64 *,ICompressProgressInfo * progress)744 HRESULT CEncoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
745     const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress)
746 {
747   #ifndef _7ZIP_ST
748   Progress = progress;
749   RINOK(Create());
750   for (UInt32 t = 0; t < NumThreads; t++)
751   #endif
752   {
753     #ifndef _7ZIP_ST
754     CThreadInfo &ti = ThreadsInfo[t];
755     if (MtMode)
756     {
757       WRes             wres = ti.StreamWasFinishedEvent.Reset();
758       if (wres == 0) { wres = ti.WaitingWasStartedEvent.Reset();
759       if (wres == 0) { wres = ti.CanWriteEvent.Reset(); }}
760       if (wres != 0)
761         return HRESULT_FROM_WIN32(wres);
762     }
763     #else
764     CThreadInfo &ti = ThreadsInfo;
765     ti.Encoder = this;
766     #endif
767 
768     ti.m_OptimizeNumTables = _props.DoOptimizeNumTables();
769 
770     if (!ti.Alloc())
771       return E_OUTOFMEMORY;
772   }
773 
774 
775   if (!m_InStream.Create(kBufferSize))
776     return E_OUTOFMEMORY;
777   if (!m_OutStream.Create(kBufferSize))
778     return E_OUTOFMEMORY;
779 
780 
781   m_InStream.SetStream(inStream);
782   m_InStream.Init();
783 
784   m_OutStream.SetStream(outStream);
785   m_OutStream.Init();
786 
787   CombinedCrc.Init();
788   #ifndef _7ZIP_ST
789   NextBlockIndex = 0;
790   StreamWasFinished = false;
791   CloseThreads = false;
792   CanStartWaitingEvent.Reset();
793   #endif
794 
795   WriteByte(kArSig0);
796   WriteByte(kArSig1);
797   WriteByte(kArSig2);
798   WriteByte((Byte)(kArSig3 + _props.BlockSizeMult));
799 
800   #ifndef _7ZIP_ST
801 
802   if (MtMode)
803   {
804     ThreadsInfo[0].CanWriteEvent.Set();
805     Result = S_OK;
806     CanProcessEvent.Set();
807     UInt32 t;
808     for (t = 0; t < NumThreads; t++)
809       ThreadsInfo[t].StreamWasFinishedEvent.Lock();
810     CanProcessEvent.Reset();
811     CanStartWaitingEvent.Set();
812     for (t = 0; t < NumThreads; t++)
813       ThreadsInfo[t].WaitingWasStartedEvent.Lock();
814     CanStartWaitingEvent.Reset();
815     RINOK(Result);
816   }
817   else
818   #endif
819   {
820     for (;;)
821     {
822       CThreadInfo &ti =
823       #ifndef _7ZIP_ST
824       ThreadsInfo[0];
825       #else
826       ThreadsInfo;
827       #endif
828       UInt32 blockSize = ReadRleBlock(ti.m_Block);
829       if (blockSize == 0)
830         break;
831       RINOK(ti.EncodeBlock3(blockSize));
832       if (progress)
833       {
834         UInt64 packSize = m_InStream.GetProcessedSize();
835         UInt64 unpackSize = m_OutStream.GetProcessedSize();
836         RINOK(progress->SetRatioInfo(&packSize, &unpackSize));
837       }
838     }
839   }
840   WriteByte(kFinSig0);
841   WriteByte(kFinSig1);
842   WriteByte(kFinSig2);
843   WriteByte(kFinSig3);
844   WriteByte(kFinSig4);
845   WriteByte(kFinSig5);
846 
847   WriteCrc(CombinedCrc.GetDigest());
848   return Flush();
849 }
850 
Code(ISequentialInStream * inStream,ISequentialOutStream * outStream,const UInt64 * inSize,const UInt64 * outSize,ICompressProgressInfo * progress)851 STDMETHODIMP CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
852     const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
853 {
854   try { return CodeReal(inStream, outStream, inSize, outSize, progress); }
855   catch(const CInBufferException &e) { return e.ErrorCode; }
856   catch(const COutBufferException &e) { return e.ErrorCode; }
857   catch(...) { return S_FALSE; }
858 }
859 
SetCoderProperties(const PROPID * propIDs,const PROPVARIANT * coderProps,UInt32 numProps)860 HRESULT CEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *coderProps, UInt32 numProps)
861 {
862   int level = -1;
863   CEncProps props;
864   for (UInt32 i = 0; i < numProps; i++)
865   {
866     const PROPVARIANT &prop = coderProps[i];
867     PROPID propID = propIDs[i];
868 
869     if (propID == NCoderPropID::kAffinity)
870     {
871       if (prop.vt == VT_UI8)
872         props.Affinity = prop.uhVal.QuadPart;
873       else
874         return E_INVALIDARG;
875       continue;
876     }
877 
878     if (propID >= NCoderPropID::kReduceSize)
879       continue;
880     if (prop.vt != VT_UI4)
881       return E_INVALIDARG;
882     UInt32 v = (UInt32)prop.ulVal;
883     switch (propID)
884     {
885       case NCoderPropID::kNumPasses: props.NumPasses = v; break;
886       case NCoderPropID::kDictionarySize: props.BlockSizeMult = v / kBlockSizeStep; break;
887       case NCoderPropID::kLevel: level = (int)v; break;
888       case NCoderPropID::kNumThreads:
889       {
890         #ifndef _7ZIP_ST
891         SetNumberOfThreads(v);
892         #endif
893         break;
894       }
895       default: return E_INVALIDARG;
896     }
897   }
898   props.Normalize(level);
899   _props = props;
900   return S_OK;
901 }
902 
903 #ifndef _7ZIP_ST
SetNumberOfThreads(UInt32 numThreads)904 STDMETHODIMP CEncoder::SetNumberOfThreads(UInt32 numThreads)
905 {
906   const UInt32 kNumThreadsMax = 64;
907   if (numThreads < 1) numThreads = 1;
908   if (numThreads > kNumThreadsMax) numThreads = kNumThreadsMax;
909   NumThreads = numThreads;
910   return S_OK;
911 }
912 #endif
913 
914 }}
915