xref: /aosp_15_r20/external/lzma/CPP/7zip/Compress/BZip2Encoder.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
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 Z7_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       const UInt32 blockSize = Encoder->ReadRleBlock(m_Block);
102       m_UnpackSize = 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 Z7_ST
150   ThreadsInfo = NULL;
151   m_NumThreadsPrev = 0;
152   NumThreads = 1;
153   #endif
154 }
155 
156 #ifndef Z7_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     NumBlocks++;
226     const UInt32 blockSize = _props.BlockSizeMult * kBlockSizeStep - 1;
227     unsigned numReps = 1;
228     buffer[i++] = prevByte;
229     while (i < blockSize) // "- 1" to support RLE
230     {
231       Byte b;
232       if (!m_InStream.ReadByte(b))
233         break;
234       if (b != prevByte)
235       {
236         if (numReps >= kRleModeRepSize)
237           buffer[i++] = (Byte)(numReps - kRleModeRepSize);
238         buffer[i++] = b;
239         numReps = 1;
240         prevByte = b;
241         continue;
242       }
243       numReps++;
244       if (numReps <= kRleModeRepSize)
245         buffer[i++] = b;
246       else if (numReps == kRleModeRepSize + 255)
247       {
248         buffer[i++] = (Byte)(numReps - kRleModeRepSize);
249         numReps = 0;
250       }
251     }
252     // it's to support original BZip2 decoder
253     if (numReps >= kRleModeRepSize)
254       buffer[i++] = (Byte)(numReps - kRleModeRepSize);
255   }
256   return i;
257 }
258 
WriteBits2(UInt32 value,unsigned numBits)259 void CThreadInfo::WriteBits2(UInt32 value, unsigned numBits) { m_OutStreamCurrent->WriteBits(value, numBits); }
WriteByte2(Byte b)260 void CThreadInfo::WriteByte2(Byte b) { WriteBits2(b, 8); }
WriteBit2(Byte v)261 void CThreadInfo::WriteBit2(Byte v) { WriteBits2(v, 1); }
WriteCrc2(UInt32 v)262 void CThreadInfo::WriteCrc2(UInt32 v)
263 {
264   for (unsigned i = 0; i < 4; i++)
265     WriteByte2(((Byte)(v >> (24 - i * 8))));
266 }
267 
WriteBits(UInt32 value,unsigned numBits)268 void CEncoder::WriteBits(UInt32 value, unsigned numBits) { m_OutStream.WriteBits(value, numBits); }
WriteByte(Byte b)269 void CEncoder::WriteByte(Byte b) { WriteBits(b, 8); }
270 // void CEncoder::WriteBit(Byte v) { WriteBits(v, 1); }
WriteCrc(UInt32 v)271 void CEncoder::WriteCrc(UInt32 v)
272 {
273   for (unsigned i = 0; i < 4; i++)
274     WriteByte(((Byte)(v >> (24 - i * 8))));
275 }
276 
277 
278 // blockSize > 0
EncodeBlock(const Byte * block,UInt32 blockSize)279 void CThreadInfo::EncodeBlock(const Byte *block, UInt32 blockSize)
280 {
281   WriteBit2(0); // Randomised = false
282 
283   {
284     UInt32 origPtr = BlockSort(m_BlockSorterIndex, block, blockSize);
285     // if (m_BlockSorterIndex[origPtr] != 0) throw 1;
286     m_BlockSorterIndex[origPtr] = blockSize;
287     WriteBits2(origPtr, kNumOrigBits);
288   }
289 
290   CMtf8Encoder mtf;
291   unsigned numInUse = 0;
292   {
293     Byte inUse[256];
294     Byte inUse16[16];
295     UInt32 i;
296     for (i = 0; i < 256; i++)
297       inUse[i] = 0;
298     for (i = 0; i < 16; i++)
299       inUse16[i] = 0;
300     for (i = 0; i < blockSize; i++)
301       inUse[block[i]] = 1;
302     for (i = 0; i < 256; i++)
303       if (inUse[i])
304       {
305         inUse16[i >> 4] = 1;
306         mtf.Buf[numInUse++] = (Byte)i;
307       }
308     for (i = 0; i < 16; i++)
309       WriteBit2(inUse16[i]);
310     for (i = 0; i < 256; i++)
311       if (inUse16[i >> 4])
312         WriteBit2(inUse[i]);
313   }
314   unsigned alphaSize = numInUse + 2;
315 
316   Byte *mtfs = m_MtfArray;
317   UInt32 mtfArraySize = 0;
318   UInt32 symbolCounts[kMaxAlphaSize];
319   {
320     for (unsigned i = 0; i < kMaxAlphaSize; i++)
321       symbolCounts[i] = 0;
322   }
323 
324   {
325     UInt32 rleSize = 0;
326     UInt32 i = 0;
327     const UInt32 *bsIndex = m_BlockSorterIndex;
328     block--;
329     do
330     {
331       unsigned pos = mtf.FindAndMove(block[bsIndex[i]]);
332       if (pos == 0)
333         rleSize++;
334       else
335       {
336         while (rleSize != 0)
337         {
338           rleSize--;
339           mtfs[mtfArraySize++] = (Byte)(rleSize & 1);
340           symbolCounts[rleSize & 1]++;
341           rleSize >>= 1;
342         }
343         if (pos >= 0xFE)
344         {
345           mtfs[mtfArraySize++] = 0xFF;
346           mtfs[mtfArraySize++] = (Byte)(pos - 0xFE);
347         }
348         else
349           mtfs[mtfArraySize++] = (Byte)(pos + 1);
350         symbolCounts[(size_t)pos + 1]++;
351       }
352     }
353     while (++i < blockSize);
354 
355     while (rleSize != 0)
356     {
357       rleSize--;
358       mtfs[mtfArraySize++] = (Byte)(rleSize & 1);
359       symbolCounts[rleSize & 1]++;
360       rleSize >>= 1;
361     }
362 
363     if (alphaSize < 256)
364       mtfs[mtfArraySize++] = (Byte)(alphaSize - 1);
365     else
366     {
367       mtfs[mtfArraySize++] = 0xFF;
368       mtfs[mtfArraySize++] = (Byte)(alphaSize - 256);
369     }
370     symbolCounts[(size_t)alphaSize - 1]++;
371   }
372 
373   UInt32 numSymbols = 0;
374   {
375     for (unsigned i = 0; i < kMaxAlphaSize; i++)
376       numSymbols += symbolCounts[i];
377   }
378 
379   unsigned bestNumTables = kNumTablesMin;
380   UInt32 bestPrice = 0xFFFFFFFF;
381   UInt32 startPos = m_OutStreamCurrent->GetPos();
382   Byte startCurByte = m_OutStreamCurrent->GetCurByte();
383   for (unsigned nt = kNumTablesMin; nt <= kNumTablesMax + 1; nt++)
384   {
385     unsigned numTables;
386 
387     if (m_OptimizeNumTables)
388     {
389       m_OutStreamCurrent->SetPos(startPos);
390       m_OutStreamCurrent->SetCurState((startPos & 7), startCurByte);
391       if (nt <= kNumTablesMax)
392         numTables = nt;
393       else
394         numTables = bestNumTables;
395     }
396     else
397     {
398       if (numSymbols < 200)  numTables = 2;
399       else if (numSymbols < 600) numTables = 3;
400       else if (numSymbols < 1200) numTables = 4;
401       else if (numSymbols < 2400) numTables = 5;
402       else numTables = 6;
403     }
404 
405     WriteBits2(numTables, kNumTablesBits);
406 
407     UInt32 numSelectors = (numSymbols + kGroupSize - 1) / kGroupSize;
408     WriteBits2(numSelectors, kNumSelectorsBits);
409 
410     {
411       UInt32 remFreq = numSymbols;
412       unsigned gs = 0;
413       unsigned t = numTables;
414       do
415       {
416         UInt32 tFreq = remFreq / t;
417         unsigned ge = gs;
418         UInt32 aFreq = 0;
419         while (aFreq < tFreq) //  && ge < alphaSize)
420           aFreq += symbolCounts[ge++];
421 
422         if (ge > gs + 1 && t != numTables && t != 1 && (((numTables - t) & 1) == 1))
423           aFreq -= symbolCounts[--ge];
424 
425         Byte *lens = Lens[(size_t)t - 1];
426         unsigned i = 0;
427         do
428           lens[i] = (Byte)((i >= gs && i < ge) ? 0 : 1);
429         while (++i < alphaSize);
430         gs = ge;
431         remFreq -= aFreq;
432       }
433       while (--t != 0);
434     }
435 
436 
437     for (unsigned pass = 0; pass < kNumHuffPasses; pass++)
438     {
439       {
440         unsigned t = 0;
441         do
442           memset(Freqs[t], 0, sizeof(Freqs[t]));
443         while (++t < numTables);
444       }
445 
446       {
447         UInt32 mtfPos = 0;
448         UInt32 g = 0;
449         do
450         {
451           UInt32 symbols[kGroupSize];
452           unsigned i = 0;
453           do
454           {
455             UInt32 symbol = mtfs[mtfPos++];
456             if (symbol >= 0xFF)
457               symbol += mtfs[mtfPos++];
458             symbols[i] = symbol;
459           }
460           while (++i < kGroupSize && mtfPos < mtfArraySize);
461 
462           UInt32 bestPrice2 = 0xFFFFFFFF;
463           unsigned t = 0;
464           do
465           {
466             const Byte *lens = Lens[t];
467             UInt32 price = 0;
468             unsigned j = 0;
469             do
470               price += lens[symbols[j]];
471             while (++j < i);
472             if (price < bestPrice2)
473             {
474               m_Selectors[g] = (Byte)t;
475               bestPrice2 = price;
476             }
477           }
478           while (++t < numTables);
479           UInt32 *freqs = Freqs[m_Selectors[g++]];
480           unsigned j = 0;
481           do
482             freqs[symbols[j]]++;
483           while (++j < i);
484         }
485         while (mtfPos < mtfArraySize);
486       }
487 
488       unsigned t = 0;
489       do
490       {
491         UInt32 *freqs = Freqs[t];
492         unsigned i = 0;
493         do
494           if (freqs[i] == 0)
495             freqs[i] = 1;
496         while (++i < alphaSize);
497         Huffman_Generate(freqs, Codes[t], Lens[t], kMaxAlphaSize, kMaxHuffmanLenForEncoding);
498       }
499       while (++t < numTables);
500     }
501 
502     {
503       Byte mtfSel[kNumTablesMax];
504       {
505         unsigned t = 0;
506         do
507           mtfSel[t] = (Byte)t;
508         while (++t < numTables);
509       }
510 
511       UInt32 i = 0;
512       do
513       {
514         Byte sel = m_Selectors[i];
515         unsigned pos;
516         for (pos = 0; mtfSel[pos] != sel; pos++)
517           WriteBit2(1);
518         WriteBit2(0);
519         for (; pos > 0; pos--)
520           mtfSel[pos] = mtfSel[(size_t)pos - 1];
521         mtfSel[0] = sel;
522       }
523       while (++i < numSelectors);
524     }
525 
526     {
527       unsigned t = 0;
528       do
529       {
530         const Byte *lens = Lens[t];
531         UInt32 len = lens[0];
532         WriteBits2(len, kNumLevelsBits);
533         unsigned i = 0;
534         do
535         {
536           UInt32 level = lens[i];
537           while (len != level)
538           {
539             WriteBit2(1);
540             if (len < level)
541             {
542               WriteBit2(0);
543               len++;
544             }
545             else
546             {
547               WriteBit2(1);
548               len--;
549             }
550           }
551           WriteBit2(0);
552         }
553         while (++i < alphaSize);
554       }
555       while (++t < numTables);
556     }
557 
558     {
559       UInt32 groupSize = 0;
560       UInt32 groupIndex = 0;
561       const Byte *lens = NULL;
562       const UInt32 *codes = NULL;
563       UInt32 mtfPos = 0;
564       do
565       {
566         UInt32 symbol = mtfs[mtfPos++];
567         if (symbol >= 0xFF)
568           symbol += mtfs[mtfPos++];
569         if (groupSize == 0)
570         {
571           groupSize = kGroupSize;
572           unsigned t = m_Selectors[groupIndex++];
573           lens = Lens[t];
574           codes = Codes[t];
575         }
576         groupSize--;
577         m_OutStreamCurrent->WriteBits(codes[symbol], lens[symbol]);
578       }
579       while (mtfPos < mtfArraySize);
580     }
581 
582     if (!m_OptimizeNumTables)
583       break;
584     UInt32 price = m_OutStreamCurrent->GetPos() - startPos;
585     if (price <= bestPrice)
586     {
587       if (nt == kNumTablesMax)
588         break;
589       bestPrice = price;
590       bestNumTables = nt;
591     }
592   }
593 }
594 
595 // blockSize > 0
EncodeBlockWithHeaders(const Byte * block,UInt32 blockSize)596 UInt32 CThreadInfo::EncodeBlockWithHeaders(const Byte *block, UInt32 blockSize)
597 {
598   WriteByte2(kBlockSig0);
599   WriteByte2(kBlockSig1);
600   WriteByte2(kBlockSig2);
601   WriteByte2(kBlockSig3);
602   WriteByte2(kBlockSig4);
603   WriteByte2(kBlockSig5);
604 
605   CBZip2Crc crc;
606   unsigned numReps = 0;
607   Byte prevByte = block[0];
608   UInt32 i = 0;
609   do
610   {
611     Byte b = block[i];
612     if (numReps == kRleModeRepSize)
613     {
614       for (; b > 0; b--)
615         crc.UpdateByte(prevByte);
616       numReps = 0;
617       continue;
618     }
619     if (prevByte == b)
620       numReps++;
621     else
622     {
623       numReps = 1;
624       prevByte = b;
625     }
626     crc.UpdateByte(b);
627   }
628   while (++i < blockSize);
629   UInt32 crcRes = crc.GetDigest();
630   WriteCrc2(crcRes);
631   EncodeBlock(block, blockSize);
632   return crcRes;
633 }
634 
EncodeBlock2(const Byte * block,UInt32 blockSize,UInt32 numPasses)635 void CThreadInfo::EncodeBlock2(const Byte *block, UInt32 blockSize, UInt32 numPasses)
636 {
637   UInt32 numCrcs = m_NumCrcs;
638   bool needCompare = false;
639 
640   UInt32 startBytePos = m_OutStreamCurrent->GetBytePos();
641   UInt32 startPos = m_OutStreamCurrent->GetPos();
642   Byte startCurByte = m_OutStreamCurrent->GetCurByte();
643   Byte endCurByte = 0;
644   UInt32 endPos = 0;
645   if (numPasses > 1 && blockSize >= (1 << 10))
646   {
647     UInt32 blockSize0 = blockSize / 2; // ????
648 
649     for (; (block[blockSize0] == block[(size_t)blockSize0 - 1]
650             || block[(size_t)blockSize0 - 1] == block[(size_t)blockSize0 - 2])
651           && blockSize0 < blockSize;
652         blockSize0++);
653 
654     if (blockSize0 < blockSize)
655     {
656       EncodeBlock2(block, blockSize0, numPasses - 1);
657       EncodeBlock2(block + blockSize0, blockSize - blockSize0, numPasses - 1);
658       endPos = m_OutStreamCurrent->GetPos();
659       endCurByte = m_OutStreamCurrent->GetCurByte();
660       if ((endPos & 7) > 0)
661         WriteBits2(0, 8 - (endPos & 7));
662       m_OutStreamCurrent->SetCurState((startPos & 7), startCurByte);
663       needCompare = true;
664     }
665   }
666 
667   UInt32 startBytePos2 = m_OutStreamCurrent->GetBytePos();
668   UInt32 startPos2 = m_OutStreamCurrent->GetPos();
669   UInt32 crcVal = EncodeBlockWithHeaders(block, blockSize);
670   UInt32 endPos2 = m_OutStreamCurrent->GetPos();
671 
672   if (needCompare)
673   {
674     UInt32 size2 = endPos2 - startPos2;
675     if (size2 < endPos - startPos)
676     {
677       UInt32 numBytes = m_OutStreamCurrent->GetBytePos() - startBytePos2;
678       Byte *buffer = m_OutStreamCurrent->GetStream();
679       for (UInt32 i = 0; i < numBytes; i++)
680         buffer[startBytePos + i] = buffer[startBytePos2 + i];
681       m_OutStreamCurrent->SetPos(startPos + endPos2 - startPos2);
682       m_NumCrcs = numCrcs;
683       m_CRCs[m_NumCrcs++] = crcVal;
684     }
685     else
686     {
687       m_OutStreamCurrent->SetPos(endPos);
688       m_OutStreamCurrent->SetCurState((endPos & 7), endCurByte);
689     }
690   }
691   else
692   {
693     m_NumCrcs = numCrcs;
694     m_CRCs[m_NumCrcs++] = crcVal;
695   }
696 }
697 
EncodeBlock3(UInt32 blockSize)698 HRESULT CThreadInfo::EncodeBlock3(UInt32 blockSize)
699 {
700   CMsbfEncoderTemp outStreamTemp;
701   outStreamTemp.SetStream(m_TempArray);
702   outStreamTemp.Init();
703   m_OutStreamCurrent = &outStreamTemp;
704 
705   m_NumCrcs = 0;
706 
707   EncodeBlock2(m_Block, blockSize, Encoder->_props.NumPasses);
708 
709   #ifndef Z7_ST
710   if (Encoder->MtMode)
711     Encoder->ThreadsInfo[m_BlockIndex].CanWriteEvent.Lock();
712   #endif
713   for (UInt32 i = 0; i < m_NumCrcs; i++)
714     Encoder->CombinedCrc.Update(m_CRCs[i]);
715   Encoder->WriteBytes(m_TempArray, outStreamTemp.GetPos(), outStreamTemp.GetCurByte());
716   HRESULT res = S_OK;
717   #ifndef Z7_ST
718   if (Encoder->MtMode)
719   {
720     UInt32 blockIndex = m_BlockIndex + 1;
721     if (blockIndex == Encoder->NumThreads)
722       blockIndex = 0;
723 
724     if (Encoder->Progress)
725     {
726       const UInt64 packSize = Encoder->m_OutStream.GetProcessedSize();
727       res = Encoder->Progress->SetRatioInfo(&m_UnpackSize, &packSize);
728     }
729 
730     Encoder->ThreadsInfo[blockIndex].CanWriteEvent.Set();
731   }
732   #endif
733   return res;
734 }
735 
WriteBytes(const Byte * data,UInt32 sizeInBits,Byte lastByte)736 void CEncoder::WriteBytes(const Byte *data, UInt32 sizeInBits, Byte lastByte)
737 {
738   UInt32 bytesSize = (sizeInBits >> 3);
739   for (UInt32 i = 0; i < bytesSize; i++)
740     m_OutStream.WriteBits(data[i], 8);
741   WriteBits(lastByte, (sizeInBits & 7));
742 }
743 
744 
CodeReal(ISequentialInStream * inStream,ISequentialOutStream * outStream,const UInt64 *,const UInt64 *,ICompressProgressInfo * progress)745 HRESULT CEncoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
746     const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress)
747 {
748   NumBlocks = 0;
749   #ifndef Z7_ST
750   Progress = progress;
751   RINOK(Create())
752   for (UInt32 t = 0; t < NumThreads; t++)
753   #endif
754   {
755     #ifndef Z7_ST
756     CThreadInfo &ti = ThreadsInfo[t];
757     if (MtMode)
758     {
759       WRes             wres = ti.StreamWasFinishedEvent.Reset();
760       if (wres == 0) { wres = ti.WaitingWasStartedEvent.Reset();
761       if (wres == 0) { wres = ti.CanWriteEvent.Reset(); }}
762       if (wres != 0)
763         return HRESULT_FROM_WIN32(wres);
764     }
765     #else
766     CThreadInfo &ti = ThreadsInfo;
767     ti.Encoder = this;
768     #endif
769 
770     ti.m_OptimizeNumTables = _props.DoOptimizeNumTables();
771 
772     if (!ti.Alloc())
773       return E_OUTOFMEMORY;
774   }
775 
776 
777   if (!m_InStream.Create(kBufferSize))
778     return E_OUTOFMEMORY;
779   if (!m_OutStream.Create(kBufferSize))
780     return E_OUTOFMEMORY;
781 
782 
783   m_InStream.SetStream(inStream);
784   m_InStream.Init();
785 
786   m_OutStream.SetStream(outStream);
787   m_OutStream.Init();
788 
789   CombinedCrc.Init();
790   #ifndef Z7_ST
791   NextBlockIndex = 0;
792   StreamWasFinished = false;
793   CloseThreads = false;
794   CanStartWaitingEvent.Reset();
795   #endif
796 
797   WriteByte(kArSig0);
798   WriteByte(kArSig1);
799   WriteByte(kArSig2);
800   WriteByte((Byte)(kArSig3 + _props.BlockSizeMult));
801 
802   #ifndef Z7_ST
803 
804   if (MtMode)
805   {
806     ThreadsInfo[0].CanWriteEvent.Set();
807     Result = S_OK;
808     CanProcessEvent.Set();
809     UInt32 t;
810     for (t = 0; t < NumThreads; t++)
811       ThreadsInfo[t].StreamWasFinishedEvent.Lock();
812     CanProcessEvent.Reset();
813     CanStartWaitingEvent.Set();
814     for (t = 0; t < NumThreads; t++)
815       ThreadsInfo[t].WaitingWasStartedEvent.Lock();
816     CanStartWaitingEvent.Reset();
817     RINOK(Result)
818   }
819   else
820   #endif
821   {
822     for (;;)
823     {
824       CThreadInfo &ti =
825       #ifndef Z7_ST
826       ThreadsInfo[0];
827       #else
828       ThreadsInfo;
829       #endif
830       UInt32 blockSize = ReadRleBlock(ti.m_Block);
831       if (blockSize == 0)
832         break;
833       RINOK(ti.EncodeBlock3(blockSize))
834       if (progress)
835       {
836         const UInt64 unpackSize = m_InStream.GetProcessedSize();
837         const UInt64 packSize = m_OutStream.GetProcessedSize();
838         RINOK(progress->SetRatioInfo(&unpackSize, &packSize))
839       }
840     }
841   }
842   WriteByte(kFinSig0);
843   WriteByte(kFinSig1);
844   WriteByte(kFinSig2);
845   WriteByte(kFinSig3);
846   WriteByte(kFinSig4);
847   WriteByte(kFinSig5);
848 
849   WriteCrc(CombinedCrc.GetDigest());
850   RINOK(Flush())
851   if (!m_InStream.WasFinished())
852     return E_FAIL;
853   return S_OK;
854 }
855 
Z7_COM7F_IMF(CEncoder::Code (ISequentialInStream * inStream,ISequentialOutStream * outStream,const UInt64 * inSize,const UInt64 * outSize,ICompressProgressInfo * progress))856 Z7_COM7F_IMF(CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
857     const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress))
858 {
859   try { return CodeReal(inStream, outStream, inSize, outSize, progress); }
860   catch(const CInBufferException &e) { return e.ErrorCode; }
861   catch(const COutBufferException &e) { return e.ErrorCode; }
862   catch(...) { return S_FALSE; }
863 }
864 
Z7_COM7F_IMF(CEncoder::SetCoderProperties (const PROPID * propIDs,const PROPVARIANT * coderProps,UInt32 numProps))865 Z7_COM7F_IMF(CEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *coderProps, UInt32 numProps))
866 {
867   int level = -1;
868   CEncProps props;
869   for (UInt32 i = 0; i < numProps; i++)
870   {
871     const PROPVARIANT &prop = coderProps[i];
872     PROPID propID = propIDs[i];
873 
874     if (propID == NCoderPropID::kAffinity)
875     {
876       if (prop.vt == VT_UI8)
877         props.Affinity = prop.uhVal.QuadPart;
878       else
879         return E_INVALIDARG;
880       continue;
881     }
882 
883     if (propID >= NCoderPropID::kReduceSize)
884       continue;
885     if (prop.vt != VT_UI4)
886       return E_INVALIDARG;
887     UInt32 v = (UInt32)prop.ulVal;
888     switch (propID)
889     {
890       case NCoderPropID::kNumPasses: props.NumPasses = v; break;
891       case NCoderPropID::kDictionarySize: props.BlockSizeMult = v / kBlockSizeStep; break;
892       case NCoderPropID::kLevel: level = (int)v; break;
893       case NCoderPropID::kNumThreads:
894       {
895         #ifndef Z7_ST
896         SetNumberOfThreads(v);
897         #endif
898         break;
899       }
900       default: return E_INVALIDARG;
901     }
902   }
903   props.Normalize(level);
904   _props = props;
905   return S_OK;
906 }
907 
908 #ifndef Z7_ST
Z7_COM7F_IMF(CEncoder::SetNumberOfThreads (UInt32 numThreads))909 Z7_COM7F_IMF(CEncoder::SetNumberOfThreads(UInt32 numThreads))
910 {
911   const UInt32 kNumThreadsMax = 64;
912   if (numThreads < 1) numThreads = 1;
913   if (numThreads > kNumThreadsMax) numThreads = kNumThreadsMax;
914   NumThreads = numThreads;
915   return S_OK;
916 }
917 #endif
918 
919 }}
920