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