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