dlzma: changed license to WTFPL ;-)
[iv.d.git] / dlzma / enc.d
blob1f80a5568a9e62313675e5d4d63b6f46803590c4
1 /* converted by Ketmar // Invisible Vector <ketmar@ketmar.no-ip.org>
2 * Understanding is not required. Only obedience.
4 * This program is free software. It comes without any warranty, to
5 * the extent permitted by applicable law. You can redistribute it
6 * and/or modify it under the terms of the Do What The Fuck You Want
7 * To Public License, Version 2, as published by Sam Hocevar. See
8 * http://www.wtfpl.net/txt/copying/ for more details.
9 */
10 module iv.dlzma.enc;
11 nothrow:
13 /* use slightly smaller (around 300 bytes) code with branching in compressor? */
14 //version = LZMA_ENC_USE_BRANCH;
16 private import iv.dlzma;
19 // ////////////////////////////////////////////////////////////////////////// //
20 // ////////////////////////////////////////////////////////////////////////// //
21 // ////////////////////////////////////////////////////////////////////////// //
22 // ////////////////////////////////////////////////////////////////////////// //
23 private:
25 private void SetUi32 (const(void)* p, in uint v) nothrow @trusted @nogc { pragma(inline, true); *(cast(uint*)p) = v; }
26 private ushort GetUi16 (const(void)* v) nothrow @trusted @nogc { pragma(inline, true); return *(cast(const(ushort)*)v); }
28 alias CLzRef = uint;
30 struct CMatchFinder {
31 ubyte *buffer;
32 uint pos;
33 uint posLimit;
34 uint streamPos; /* wrap over Zero is allowed (streamPos < pos). Use (uint32_t)(streamPos - pos) */
35 uint lenLimit;
37 uint cyclicBufferPos;
38 uint cyclicBufferSize; /* it must be = (historySize + 1) */
40 ubyte streamEndWasReached;
41 ubyte btMode;
42 ubyte bigHash;
43 ubyte directInput;
45 uint matchMaxLen;
46 CLzRef *hash;
47 CLzRef *son;
48 uint hashMask;
49 uint cutValue;
51 ubyte *bufferBase;
52 ISeqInStream *stream;
54 uint blockSize;
55 uint keepSizeBefore;
56 uint keepSizeAfter;
58 uint numHashBytes;
59 usize directInputRem;
60 uint historySize;
61 uint fixedHashSize;
62 uint hashSizeSum;
63 SRes result;
64 uint[256] crc;
65 usize numRefs;
67 ulong expectedDataSize;
70 //#define Inline_MatchFinder_GetPointerToCurrentPos(p) ((const ubyte *)(p)->buffer)
72 //#define Inline_MatchFinder_GetNumAvailableBytes(p) ((uint)((p)->streamPos - (p)->pos))
73 enum Inline_MatchFinder_GetNumAvailableBytes(string p) = `(cast(uint)((`~p~`).streamPos - (`~p~`).pos))`;
76 #define Inline_MatchFinder_IsFinishedOK(p) \
77 ((p)->streamEndWasReached \
78 && (p)->streamPos == (p)->pos \
79 && (!(p)->directInput || (p)->directInputRem == 0))
83 int MatchFinder_NeedMove(CMatchFinder *p);
84 /* uint8_t *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p); */
85 void MatchFinder_MoveBlock(CMatchFinder *p);
86 void MatchFinder_ReadIfRequired(CMatchFinder *p);
88 void MatchFinder_Construct(CMatchFinder *p);
90 /* Conditions:
91 historySize <= 3 GB
92 keepAddBufferBefore + matchMaxLen + keepAddBufferAfter < 511MB
94 int MatchFinder_Create(CMatchFinder *p, uint historySize,
95 uint keepAddBufferBefore, uint matchMaxLen, uint keepAddBufferAfter,
96 ISzAllocPtr alloc);
97 void MatchFinder_Free(CMatchFinder *p, ISzAllocPtr alloc);
98 void MatchFinder_Normalize3(uint subValue, CLzRef *items, usize numItems);
99 // void MatchFinder_ReduceOffsets(CMatchFinder *p, uint32_t subValue);
103 #define Inline_MatchFinder_InitPos(p, val) \
104 (p)->pos = (val); \
105 (p)->streamPos = (val);
109 #define Inline_MatchFinder_ReduceOffsets(p, subValue) \
110 (p)->pos -= (subValue); \
111 (p)->streamPos -= (subValue);
115 uint* GetMatchesSpec1(uint lenLimit, uint curMatch, uint pos, const ubyte *buffer, CLzRef *son,
116 usize _cyclicBufferPos, uint _cyclicBufferSize, uint _cutValue,
117 uint *distances, uint maxLen);
121 Conditions:
122 Mf_GetNumAvailableBytes_Func must be called before each Mf_GetMatchLen_Func.
123 Mf_GetPointerToCurrentPos_Func's result must be used only before any other function
126 alias Mf_Init_Func = void function (void *object);
127 alias Mf_GetNumAvailableBytes_Func = uint function (void *object);
128 alias Mf_GetPointerToCurrentPos_Func = const(ubyte)* function (void *object);
129 alias Mf_GetMatches_Func = uint* function (void *object, uint *distances);
130 alias Mf_Skip_Func = void function (void *object, uint);
132 struct /*_IMatchFinder*/ IMatchFinder2 {
133 Mf_Init_Func Init;
134 Mf_GetNumAvailableBytes_Func GetNumAvailableBytes;
135 Mf_GetPointerToCurrentPos_Func GetPointerToCurrentPos;
136 Mf_GetMatches_Func GetMatches;
137 Mf_Skip_Func Skip;
141 void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder2 *vTable);
143 void MatchFinder_Init_LowHash(CMatchFinder *p);
144 void MatchFinder_Init_HighHash(CMatchFinder *p);
145 void MatchFinder_Init_4(CMatchFinder *p);
146 void MatchFinder_Init(CMatchFinder *p);
148 uint* Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, uint *distances);
149 uint* Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, uint *distances);
151 void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, uint num);
152 void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, uint num);
154 void LzFindPrepare(void);
158 /* LzHash.h -- HASH functions for LZ algorithms
159 2019-10-30 : Igor Pavlov : Public domain */
162 (kHash2Size >= (1 << 8)) : Required
163 (kHash3Size >= (1 << 16)) : Required
166 enum kHash2Size = (1 << 10);
167 enum kHash3Size = (1 << 16);
168 // #define kHash4Size (1 << 20)
170 enum kFix3HashSize = (kHash2Size);
171 enum kFix4HashSize = (kHash2Size + kHash3Size);
172 // #define kFix5HashSize (kHash2Size + kHash3Size + kHash4Size)
175 We use up to 3 crc values for hash:
176 crc0
177 crc1 << Shift_1
178 crc2 << Shift_2
179 (Shift_1 = 5) and (Shift_2 = 10) is good tradeoff.
180 Small values for Shift are not good for collision rate.
181 Big value for Shift_2 increases the minimum size
182 of hash table, that will be slow for small files.
185 enum kLzHash_CrcShift_1 = 5;
186 enum kLzHash_CrcShift_2 = 10;
190 enum kBlockMoveAlign = (1 << 7); // alignment for memmove()
191 enum kBlockSizeAlign = (1 << 16); // alignment for block allocation
192 enum kBlockSizeReserveMin = (1 << 24); // it's 1/256 from 4 GB dictinary
194 enum kEmptyHashValue = 0;
196 enum kMaxValForNormalize = cast(uint)0;
197 // #define kMaxValForNormalize ((uint)(1 << 20) + 0xFFF) // for debug
199 // #define kNormalizeAlign (1 << 7) // alignment for speculated accesses
202 // #define kFix5HashSize (kHash2Size + kHash3Size + kHash4Size)
203 enum kFix5HashSize = kFix4HashSize;
205 // (crc[0 ... 255] & 0xFF) provides one-to-one correspondence to [0 ... 255]
208 HASH3_CALC:
209 if (cur[0]) and (h2) match, then cur[1] also match
210 if (cur[0]) and (hv) match, then cur[1] and cur[2] also match
212 enum HASH3_CALC = q{
213 uint temp = p.crc[cur[0]] ^ cur[1];
214 h2 = temp & (kHash2Size - 1);
215 hv = (temp ^ (cast(uint)cur[2] << 8)) & p.hashMask;
218 enum HASH4_CALC = q{
219 uint temp = p.crc[cur[0]] ^ cur[1];
220 h2 = temp & (kHash2Size - 1);
221 temp ^= (cast(uint)cur[2] << 8);
222 h3 = temp & (kHash3Size - 1);
223 hv = (temp ^ (p.crc[cur[3]] << kLzHash_CrcShift_1)) & p.hashMask;
226 enum HASH5_CALC = q{
227 uint temp = p.crc[cur[0]] ^ cur[1];
228 h2 = temp & (kHash2Size - 1);
229 temp ^= (cast(uint)cur[2] << 8);
230 h3 = temp & (kHash3Size - 1);
231 temp ^= (p.crc[cur[3]] << kLzHash_CrcShift_1);
232 /* h4 = temp & p->hash4Mask; */ /* (kHash4Size - 1); */
233 hv = (temp ^ (p.crc[cur[4]] << kLzHash_CrcShift_2)) & p.hashMask;
236 enum HASH_ZIP_CALC = `hv = ((cur[2] | (cast(uint)cur[0] << 8)) ^ p.crc[cur[1]]) & 0xFFFF;`;
239 private void LzInWindow_Free(CMatchFinder *p, ISzAllocPtr alloc)
241 if (!p.directInput)
243 ISzAlloc_Free(alloc, p.bufferBase);
244 p.bufferBase = null;
249 private int LzInWindow_Create2(CMatchFinder *p, uint blockSize, ISzAllocPtr alloc)
251 if (blockSize == 0)
252 return 0;
253 if (!p.bufferBase || p.blockSize != blockSize)
255 // usize blockSizeT;
256 LzInWindow_Free(p, alloc);
257 p.blockSize = blockSize;
258 // blockSizeT = blockSize;
260 // printf("\nblockSize = 0x%x\n", blockSize);
262 #if defined _WIN64
263 // we can allocate 4GiB, but still use uint for (p->blockSize)
264 // we use uint type for (p->blockSize), because
265 // we don't want to wrap over 4 GiB,
266 // when we use (p->streamPos - p->pos) that is uint.
267 if (blockSize >= (uint)0 - (uint)kBlockSizeAlign)
269 blockSizeT = ((usize)1 << 32);
270 printf("\nchanged to blockSizeT = 4GiB\n");
272 #endif
275 p.bufferBase = cast(ubyte *)ISzAlloc_Alloc(alloc, blockSize);
276 // printf("\nbufferBase = %p\n", p->bufferBase);
277 // return 0; // for debug
279 return (p.bufferBase != null);
282 private const(ubyte)* MatchFinder_GetPointerToCurrentPos(CMatchFinder *p) { pragma(inline, true); return p.buffer; }
284 private uint MatchFinder_GetNumAvailableBytes(CMatchFinder *p) { pragma(inline, true); return mixin(Inline_MatchFinder_GetNumAvailableBytes!"p"); }
287 //MY_NO_INLINE
288 private void MatchFinder_ReadBlock(CMatchFinder *p)
290 if (p.streamEndWasReached || p.result != SZ_OK)
291 return;
293 /* We use (p->streamPos - p->pos) value.
294 (p->streamPos < p->pos) is allowed. */
296 if (p.directInput)
298 uint curSize = 0xFFFFFFFF - mixin(Inline_MatchFinder_GetNumAvailableBytes!"p");
299 if (curSize > p.directInputRem)
300 curSize = cast(uint)p.directInputRem;
301 p.directInputRem -= curSize;
302 p.streamPos += curSize;
303 if (p.directInputRem == 0)
304 p.streamEndWasReached = 1;
305 return;
308 for (;;)
310 ubyte *dest = p.buffer + mixin(Inline_MatchFinder_GetNumAvailableBytes!"p");
311 usize size = cast(usize)(p.bufferBase + p.blockSize - dest);
312 if (size == 0)
314 /* we call ReadBlock() after NeedMove() and MoveBlock().
315 NeedMove() and MoveBlock() povide more than (keepSizeAfter)
316 to the end of (blockSize).
317 So we don't execute this branch in normal code flow.
318 We can go here, if we will call ReadBlock() before NeedMove(), MoveBlock().
320 // p->result = SZ_ERROR_FAIL; // we can show error here
321 return;
324 // #define kRead 3
325 // if (size > kRead) size = kRead; // for debug
327 //p.result = ISeqInStream_Read(p.stream, dest, &size);
328 p.result = p.stream.Read(p.stream, dest, &size);
329 if (p.result != SZ_OK)
330 return;
331 if (size == 0)
333 p.streamEndWasReached = 1;
334 return;
336 p.streamPos += cast(uint)size;
337 if (mixin(Inline_MatchFinder_GetNumAvailableBytes!"p") > p.keepSizeAfter)
338 return;
339 /* here and in another (p->keepSizeAfter) checks we keep on 1 byte more than was requested by Create() function
340 (Inline_MatchFinder_GetNumAvailableBytes(p) >= p->keepSizeAfter) - minimal required size */
343 // on exit: (p->result != SZ_OK || p->streamEndWasReached || Inline_MatchFinder_GetNumAvailableBytes(p) > p->keepSizeAfter)
348 //MY_NO_INLINE
349 private void MatchFinder_MoveBlock (CMatchFinder *p) @nogc {
350 import core.stdc.string : memmove;
351 const usize offset = cast(usize)(p.buffer - p.bufferBase) - p.keepSizeBefore;
352 const usize keepBefore = (offset & (kBlockMoveAlign - 1)) + p.keepSizeBefore;
353 p.buffer = p.bufferBase + keepBefore;
354 memmove(p.bufferBase,
355 p.bufferBase + (offset & ~(cast(usize)kBlockMoveAlign - 1)),
356 keepBefore + cast(usize)mixin(Inline_MatchFinder_GetNumAvailableBytes!"p"));
359 /* We call MoveBlock() before ReadBlock().
360 So MoveBlock() can be wasteful operation, if the whole input data
361 can fit in current block even without calling MoveBlock().
362 in important case where (dataSize <= historySize)
363 condition (p->blockSize > dataSize + p->keepSizeAfter) is met
364 So there is no MoveBlock() in that case case.
367 private int MatchFinder_NeedMove (CMatchFinder *p) @nogc {
368 if (p.directInput)
369 return 0;
370 if (p.streamEndWasReached || p.result != SZ_OK)
371 return 0;
372 return (cast(usize)(p.bufferBase + p.blockSize - p.buffer) <= p.keepSizeAfter);
375 private void MatchFinder_ReadIfRequired (CMatchFinder *p) {
376 if (p.keepSizeAfter >= mixin(Inline_MatchFinder_GetNumAvailableBytes!"p"))
377 MatchFinder_ReadBlock(p);
381 private void MatchFinder_SetDefaultSettings (CMatchFinder* p) @nogc {
382 p.cutValue = 32;
383 p.btMode = 1;
384 p.numHashBytes = 4;
385 p.bigHash = 0;
388 enum kCrcPoly = 0xEDB88320;
390 private void MatchFinder_Construct (CMatchFinder* p) @nogc {
391 uint i;
392 p.bufferBase = null;
393 p.directInput = 0;
394 p.hash = null;
395 p.expectedDataSize = cast(ulong)cast(long)-1;
396 MatchFinder_SetDefaultSettings(p);
398 for (i = 0; i < 256; i++)
400 uint r = cast(uint)i;
401 uint j;
402 for (j = 0; j < 8; j++)
403 r = (r >> 1) ^ (kCrcPoly & (cast(uint)0 - (r & 1)));
404 p.crc[i] = r;
408 private void MatchFinder_FreeThisClassMemory(CMatchFinder *p, ISzAllocPtr alloc)
410 ISzAlloc_Free(alloc, p.hash);
411 p.hash = null;
414 private void MatchFinder_Free(CMatchFinder *p, ISzAllocPtr alloc)
416 MatchFinder_FreeThisClassMemory(p, alloc);
417 LzInWindow_Free(p, alloc);
420 private CLzRef* AllocRefs(usize num, ISzAllocPtr alloc)
422 usize sizeInBytes = cast(usize)num * CLzRef.sizeof;
423 if (sizeInBytes / CLzRef.sizeof != num)
424 return null;
425 return cast(CLzRef *)ISzAlloc_Alloc(alloc, sizeInBytes);
428 static assert(kBlockSizeReserveMin >= kBlockSizeAlign * 2, "Stop_Compiling_Bad_Reserve");
432 private uint GetBlockSize (CMatchFinder* p, uint historySize) @nogc {
433 uint blockSize = (p.keepSizeBefore + p.keepSizeAfter);
435 if (historySize > kMaxHistorySize)
436 return 0;
438 // printf("\nhistorySize == 0x%x\n", historySize);
440 if (p.keepSizeBefore < historySize || blockSize < p.keepSizeBefore) // if 32-bit overflow
441 return 0;
444 const uint kBlockSizeMax = cast(uint)0 - cast(uint)kBlockSizeAlign;
445 const uint rem = kBlockSizeMax - blockSize;
446 const uint reserve = (blockSize >> (blockSize < (cast(uint)1 << 30) ? 1 : 2))
447 + (1 << 12) + kBlockMoveAlign + kBlockSizeAlign; // do not overflow 32-bit here
448 if (blockSize >= kBlockSizeMax
449 || rem < kBlockSizeReserveMin) // we reject settings that will be slow
450 return 0;
451 if (reserve >= rem)
452 blockSize = kBlockSizeMax;
453 else
455 blockSize += reserve;
456 blockSize &= ~cast(uint)(kBlockSizeAlign - 1);
459 // printf("\n LzFind_blockSize = %x\n", blockSize);
460 // printf("\n LzFind_blockSize = %d\n", blockSize >> 20);
461 return blockSize;
465 private int MatchFinder_Create(CMatchFinder *p, uint historySize,
466 uint keepAddBufferBefore, uint matchMaxLen, uint keepAddBufferAfter,
467 ISzAllocPtr alloc)
469 /* we need one additional byte in (p->keepSizeBefore),
470 since we use MoveBlock() after (p->pos++) and before dictionary using */
471 // keepAddBufferBefore = (uint)0xFFFFFFFF - (1 << 22); // for debug
472 p.keepSizeBefore = historySize + keepAddBufferBefore + 1;
474 keepAddBufferAfter += matchMaxLen;
475 /* we need (p->keepSizeAfter >= p->numHashBytes) */
476 if (keepAddBufferAfter < p.numHashBytes)
477 keepAddBufferAfter = p.numHashBytes;
478 // keepAddBufferAfter -= 2; // for debug
479 p.keepSizeAfter = keepAddBufferAfter;
481 if (p.directInput)
482 p.blockSize = 0;
483 if (p.directInput || LzInWindow_Create2(p, GetBlockSize(p, historySize), alloc))
485 const uint newCyclicBufferSize = historySize + 1; // do not change it
486 uint hs;
487 p.matchMaxLen = matchMaxLen;
489 // uint hs4;
490 p.fixedHashSize = 0;
491 hs = (1 << 16) - 1;
492 if (p.numHashBytes != 2)
494 hs = historySize;
495 if (hs > p.expectedDataSize)
496 hs = cast(uint)p.expectedDataSize;
497 if (hs != 0)
498 hs--;
499 hs |= (hs >> 1);
500 hs |= (hs >> 2);
501 hs |= (hs >> 4);
502 hs |= (hs >> 8);
503 // we propagated 16 bits in (hs). Low 16 bits must be set later
504 hs >>= 1;
505 if (hs >= (1 << 24))
507 if (p.numHashBytes == 3)
508 hs = (1 << 24) - 1;
509 else
510 hs >>= 1;
511 /* if (bigHash) mode, GetHeads4b() in LzFindMt.c needs (hs >= ((1 << 24) - 1))) */
514 // hs = ((uint)1 << 25) - 1; // for test
516 // (hash_size >= (1 << 16)) : Required for (numHashBytes > 2)
517 hs |= (1 << 16) - 1; /* don't change it! */
519 // bt5: we adjust the size with recommended minimum size
520 if (p.numHashBytes >= 5)
521 hs |= (256 << kLzHash_CrcShift_2) - 1;
523 p.hashMask = hs;
524 hs++;
527 hs4 = (1 << 20);
528 if (hs4 > hs)
529 hs4 = hs;
530 // hs4 = (1 << 16); // for test
531 p->hash4Mask = hs4 - 1;
534 if (p.numHashBytes > 2) p.fixedHashSize += kHash2Size;
535 if (p.numHashBytes > 3) p.fixedHashSize += kHash3Size;
536 // if (p->numHashBytes > 4) p->fixedHashSize += hs4; // kHash4Size;
537 hs += p.fixedHashSize;
541 usize newSize;
542 usize numSons;
543 p.historySize = historySize;
544 p.hashSizeSum = hs;
545 p.cyclicBufferSize = newCyclicBufferSize; // it must be = (historySize + 1)
547 numSons = newCyclicBufferSize;
548 if (p.btMode)
549 numSons <<= 1;
550 newSize = hs + numSons;
552 // aligned size is not required here, but it can be better for some loops
553 enum NUM_REFS_ALIGN_MASK = 0xF;
554 newSize = (newSize + NUM_REFS_ALIGN_MASK) & ~cast(usize)NUM_REFS_ALIGN_MASK;
556 if (p.hash && p.numRefs == newSize)
557 return 1;
559 MatchFinder_FreeThisClassMemory(p, alloc);
560 p.numRefs = newSize;
561 p.hash = AllocRefs(newSize, alloc);
563 if (p.hash)
565 p.son = p.hash + p.hashSizeSum;
566 return 1;
571 MatchFinder_Free(p, alloc);
572 return 0;
576 private void MatchFinder_SetLimits (CMatchFinder* p) @nogc {
577 uint k;
578 uint n = kMaxValForNormalize - p.pos;
579 if (n == 0)
580 n = cast(uint)cast(int)-1; // we allow (pos == 0) at start even with (kMaxValForNormalize == 0)
582 k = p.cyclicBufferSize - p.cyclicBufferPos;
583 if (k < n)
584 n = k;
586 k = mixin(Inline_MatchFinder_GetNumAvailableBytes!"p");
588 const uint ksa = p.keepSizeAfter;
589 uint mm = p.matchMaxLen;
590 if (k > ksa)
591 k -= ksa; // we must limit exactly to keepSizeAfter for ReadBlock
592 else if (k >= mm)
594 // the limitation for (p->lenLimit) update
595 k -= mm; // optimization : to reduce the number of checks
596 k++;
597 // k = 1; // non-optimized version : for debug
599 else
601 mm = k;
602 if (k != 0)
603 k = 1;
605 p.lenLimit = mm;
607 if (k < n)
608 n = k;
610 p.posLimit = p.pos + n;
614 private void MatchFinder_Init_LowHash (CMatchFinder* p) @nogc {
615 usize i;
616 CLzRef *items = p.hash;
617 const usize numItems = p.fixedHashSize;
618 for (i = 0; i < numItems; i++)
619 items[i] = kEmptyHashValue;
623 private void MatchFinder_Init_HighHash (CMatchFinder* p) @nogc {
624 usize i;
625 CLzRef *items = p.hash + p.fixedHashSize;
626 const usize numItems = cast(usize)p.hashMask + 1;
627 for (i = 0; i < numItems; i++)
628 items[i] = kEmptyHashValue;
632 private void MatchFinder_Init_4 (CMatchFinder* p) @nogc {
633 p.buffer = p.bufferBase;
635 /* kEmptyHashValue = 0 (Zero) is used in hash tables as NO-VALUE marker.
636 the code in CMatchFinderMt expects (pos = 1) */
637 p.pos =
638 p.streamPos =
639 1; // it's smallest optimal value. do not change it
640 // 0; // for debug
642 p.result = SZ_OK;
643 p.streamEndWasReached = 0;
647 // (CYC_TO_POS_OFFSET == 0) is expected by some optimized code
648 enum CYC_TO_POS_OFFSET = 0;
649 // #define CYC_TO_POS_OFFSET 1 // for debug
651 private void MatchFinder_Init (CMatchFinder* p) {
652 MatchFinder_Init_HighHash(p);
653 MatchFinder_Init_LowHash(p);
654 MatchFinder_Init_4(p);
655 // if (readData)
656 MatchFinder_ReadBlock(p);
658 /* if we init (cyclicBufferPos = pos), then we can use one variable
659 instead of both (cyclicBufferPos) and (pos) : only before (cyclicBufferPos) wrapping */
660 p.cyclicBufferPos = (p.pos - CYC_TO_POS_OFFSET); // init with relation to (pos)
661 // p->cyclicBufferPos = 0; // smallest value
662 // p->son[0] = p->son[1] = 0; // unused: we can init skipped record for speculated accesses.
663 MatchFinder_SetLimits(p);
668 // kEmptyHashValue must be zero
669 // #define SASUB_32(i) v = items[i]; m = v - subValue; if (v < subValue) m = kEmptyHashValue; items[i] = m;
670 //#define SASUB_32(i) v = items[i]; if (v < subValue) v = subValue; items[i] = v - subValue;
671 enum SASUB_32(string i) = `v = items[`~i~`]; if (v < subValue) v = subValue; items[`~i~`] = v - subValue;`;
673 //MY_NO_INLINE
674 private void LzFind_SaturSub_32 (uint subValue, CLzRef* items, const(CLzRef)* lim) @nogc {
677 uint v;
678 mixin(SASUB_32!"0");
679 mixin(SASUB_32!"1");
680 mixin(SASUB_32!"2");
681 mixin(SASUB_32!"3");
682 mixin(SASUB_32!"4");
683 mixin(SASUB_32!"5");
684 mixin(SASUB_32!"6");
685 mixin(SASUB_32!"7");
686 items += 8;
688 while (items != lim);
692 //MY_NO_INLINE
693 private void MatchFinder_Normalize3 (uint subValue, CLzRef* items, usize numItems) @nogc {
694 enum K_NORM_ALIGN_BLOCK_SIZE = (1 << 6);
696 CLzRef *lim;
698 for (; numItems != 0 && (cast(uint)cast(ptrdiff_t)items & (K_NORM_ALIGN_BLOCK_SIZE - 1)) != 0; numItems--)
700 uint v;
701 mixin(SASUB_32!"0");
702 items++;
706 enum K_NORM_ALIGN_MASK = (K_NORM_ALIGN_BLOCK_SIZE / 4 - 1);
707 lim = items + (numItems & ~cast(usize)K_NORM_ALIGN_MASK);
708 numItems &= K_NORM_ALIGN_MASK;
709 if (items != lim)
711 LzFind_SaturSub_32(subValue, items, lim);
713 items = lim;
717 for (; numItems != 0; numItems--)
719 uint v;
720 mixin(SASUB_32!"0");
721 items++;
727 // call MatchFinder_CheckLimits() only after (p->pos++) update
729 //MY_NO_INLINE
730 private void MatchFinder_CheckLimits (CMatchFinder* p) {
731 if (// !p->streamEndWasReached && p->result == SZ_OK &&
732 p.keepSizeAfter == mixin(Inline_MatchFinder_GetNumAvailableBytes!"p"))
734 // we try to read only in exact state (p->keepSizeAfter == Inline_MatchFinder_GetNumAvailableBytes(p))
735 if (MatchFinder_NeedMove(p))
736 MatchFinder_MoveBlock(p);
737 MatchFinder_ReadBlock(p);
740 if (p.pos == kMaxValForNormalize)
741 if (mixin(Inline_MatchFinder_GetNumAvailableBytes!"p") >= p.numHashBytes) // optional optimization for last bytes of data.
743 if we disable normalization for last bytes of data, and
744 if (data_size == 4 GiB), we don't call wastfull normalization,
745 but (pos) will be wrapped over Zero (0) in that case.
746 And we cannot resume later to normal operation
749 // MatchFinder_Normalize(p);
750 /* after normalization we need (p->pos >= p->historySize + 1); */
751 /* we can reduce subValue to aligned value, if want to keep alignment
752 of (p->pos) and (p->buffer) for speculated accesses. */
753 const uint subValue = (p.pos - p.historySize - 1) /* & ~(uint)(kNormalizeAlign - 1) */;
754 // const uint subValue = (1 << 15); // for debug
755 // printf("\nMatchFinder_Normalize() subValue == 0x%x\n", subValue);
756 usize numSonRefs = p.cyclicBufferSize;
757 if (p.btMode)
758 numSonRefs <<= 1;
760 //Inline_MatchFinder_ReduceOffsets(p, subValue);
761 p.pos -= subValue;
762 p.streamPos -= subValue;
764 MatchFinder_Normalize3(subValue, p.hash, cast(usize)p.hashSizeSum + numSonRefs);
767 if (p.cyclicBufferPos == p.cyclicBufferSize)
768 p.cyclicBufferPos = 0;
770 MatchFinder_SetLimits(p);
775 (lenLimit > maxLen)
777 //MY_FORCE_INLINE
778 private uint * Hc_GetMatchesSpec (usize lenLimit, uint curMatch, uint pos, const(ubyte)* cur, CLzRef *son,
779 usize _cyclicBufferPos, uint _cyclicBufferSize, uint cutValue,
780 uint *d, uint maxLen) @nogc
783 son[_cyclicBufferPos] = curMatch;
784 for (;;)
786 uint delta = pos - curMatch;
787 if (cutValue-- == 0 || delta >= _cyclicBufferSize)
788 return d;
790 const ubyte *pb = cur - delta;
791 curMatch = son[_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)];
792 if (pb[maxLen] == cur[maxLen] && *pb == *cur)
794 uint len = 0;
795 while (++len != lenLimit)
796 if (pb[len] != cur[len])
797 break;
798 if (maxLen < len)
800 maxLen = len;
801 *d++ = len;
802 *d++ = delta - 1;
803 if (len == lenLimit)
804 return d;
811 const(ubyte)* lim = cur + lenLimit;
812 son[_cyclicBufferPos] = curMatch;
816 uint delta;
818 if (curMatch == 0)
819 break;
820 // if (curMatch2 >= curMatch) return null;
821 delta = pos - curMatch;
822 if (delta >= _cyclicBufferSize)
823 break;
825 ptrdiff_t diff;
826 curMatch = son[_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)];
827 diff = cast(ptrdiff_t)0 - cast(ptrdiff_t)delta;
828 if (cur[maxLen] == cur[cast(ptrdiff_t)maxLen + diff])
830 const(ubyte)* c = cur;
831 while (*c == c[diff])
833 if (++c == lim)
835 d[0] = cast(uint)(lim - cur);
836 d[1] = delta - 1;
837 return d + 2;
841 const uint len = cast(uint)(c - cur);
842 if (maxLen < len)
844 maxLen = len;
845 d[0] = cast(uint)len;
846 d[1] = delta - 1;
847 d += 2;
853 while (--cutValue);
855 return d;
859 //MY_FORCE_INLINE
860 private uint* GetMatchesSpec1 (uint lenLimit, uint curMatch, uint pos, const(ubyte)* cur, CLzRef *son,
861 usize _cyclicBufferPos, uint _cyclicBufferSize, uint cutValue,
862 uint *d, uint maxLen) @nogc
864 CLzRef *ptr0 = son + (cast(usize)_cyclicBufferPos << 1) + 1;
865 CLzRef *ptr1 = son + (cast(usize)_cyclicBufferPos << 1);
866 uint len0 = 0, len1 = 0;
868 uint cmCheck;
870 // if (curMatch >= pos) { *ptr0 = *ptr1 = kEmptyHashValue; return null; }
872 cmCheck = cast(uint)(pos - _cyclicBufferSize);
873 if (cast(uint)pos <= _cyclicBufferSize)
874 cmCheck = 0;
876 if (cmCheck < curMatch)
879 const uint delta = pos - curMatch;
881 CLzRef *pair = son + (cast(usize)(_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1);
882 const ubyte *pb = cur - delta;
883 uint len = (len0 < len1 ? len0 : len1);
884 const uint pair0 = pair[0];
885 if (pb[len] == cur[len])
887 if (++len != lenLimit && pb[len] == cur[len])
888 while (++len != lenLimit)
889 if (pb[len] != cur[len])
890 break;
891 if (maxLen < len)
893 maxLen = cast(uint)len;
894 *d++ = cast(uint)len;
895 *d++ = delta - 1;
896 if (len == lenLimit)
898 *ptr1 = pair0;
899 *ptr0 = pair[1];
900 return d;
904 if (pb[len] < cur[len])
906 *ptr1 = curMatch;
907 // const uint curMatch2 = pair[1];
908 // if (curMatch2 >= curMatch) { *ptr0 = *ptr1 = kEmptyHashValue; return null; }
909 // curMatch = curMatch2;
910 curMatch = pair[1];
911 ptr1 = pair + 1;
912 len1 = len;
914 else
916 *ptr0 = curMatch;
917 curMatch = pair[0];
918 ptr0 = pair;
919 len0 = len;
923 while(--cutValue && cmCheck < curMatch);
925 *ptr0 = *ptr1 = kEmptyHashValue;
926 return d;
930 private void SkipMatchesSpec (uint lenLimit, uint curMatch, uint pos, const(ubyte)* cur, CLzRef *son,
931 usize _cyclicBufferPos, uint _cyclicBufferSize, uint cutValue) @nogc
933 CLzRef *ptr0 = son + (cast(usize)_cyclicBufferPos << 1) + 1;
934 CLzRef *ptr1 = son + (cast(usize)_cyclicBufferPos << 1);
935 uint len0 = 0, len1 = 0;
937 uint cmCheck;
939 cmCheck = cast(uint)(pos - _cyclicBufferSize);
940 if (cast(uint)pos <= _cyclicBufferSize)
941 cmCheck = 0;
943 if (// curMatch >= pos || // failure
944 cmCheck < curMatch)
947 const uint delta = pos - curMatch;
949 CLzRef *pair = son + (cast(usize)(_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1);
950 const ubyte *pb = cur - delta;
951 uint len = (len0 < len1 ? len0 : len1);
952 if (pb[len] == cur[len])
954 while (++len != lenLimit)
955 if (pb[len] != cur[len])
956 break;
958 if (len == lenLimit)
960 *ptr1 = pair[0];
961 *ptr0 = pair[1];
962 return;
966 if (pb[len] < cur[len])
968 *ptr1 = curMatch;
969 curMatch = pair[1];
970 ptr1 = pair + 1;
971 len1 = len;
973 else
975 *ptr0 = curMatch;
976 curMatch = pair[0];
977 ptr0 = pair;
978 len0 = len;
982 while(--cutValue && cmCheck < curMatch);
984 *ptr0 = *ptr1 = kEmptyHashValue;
985 return;
989 enum MOVE_POS = q{
990 ++p.cyclicBufferPos;
991 p.buffer++;
992 { const uint pos1 = p.pos + 1; p.pos = pos1; if (pos1 == p.posLimit) MatchFinder_CheckLimits(p); }
995 enum MOVE_POS_RET = MOVE_POS~`return distances;`;
997 //MY_NO_INLINE
998 private void MatchFinder_MovePos (CMatchFinder *p) {
999 pragma(inline, true);
1000 /* we go here at the end of stream data, when (avail < num_hash_bytes)
1001 We don't update sons[cyclicBufferPos << btMode].
1002 So (sons) record will contain junk. And we cannot resume match searching
1003 to normal operation, even if we will provide more input data in buffer.
1004 p->sons[p->cyclicBufferPos << p->btMode] = 0; // kEmptyHashValue
1005 if (p->btMode)
1006 p->sons[(p->cyclicBufferPos << p->btMode) + 1] = 0; // kEmptyHashValue
1008 mixin(MOVE_POS);
1011 enum GET_MATCHES_HEADER2(string minLen, string ret_op) = `
1012 uint lenLimit; uint hv; ubyte *cur; uint curMatch;
1013 lenLimit = cast(uint)p.lenLimit; { if (lenLimit < `~minLen~`) { MatchFinder_MovePos(p); `~ret_op~`; } }
1014 cur = p.buffer;
1017 enum GET_MATCHES_HEADER(string minLen) = GET_MATCHES_HEADER2!(minLen, "return distances");
1018 //enum SKIP_HEADER(string minLen) = `do { `~GET_MATCHES_HEADER2!(minLen, "continue");
1019 enum SKIP_HEADER(string minLen) = GET_MATCHES_HEADER2!(minLen, "continue");
1021 enum MF_PARAMS(string p) = `lenLimit, curMatch, `~p~`.pos, `~p~`.buffer, `~p~`.son, `~p~`.cyclicBufferPos, `~p~`.cyclicBufferSize, `~p~`.cutValue`;
1023 //#define SKIP_FOOTER SkipMatchesSpec(MF_PARAMS(p)); mixin(MOVE_POS); } while (--num);
1024 enum SKIP_FOOTER = `SkipMatchesSpec(`~MF_PARAMS!"p"~`);`~MOVE_POS;
1027 enum GET_MATCHES_FOOTER_BASE(string _maxLen_, string func) = `
1028 distances = `~func~`(`~MF_PARAMS!"p"~`, distances, cast(uint)`~_maxLen_~`);`~MOVE_POS_RET;
1030 enum GET_MATCHES_FOOTER_BT(string _maxLen_) = GET_MATCHES_FOOTER_BASE!(_maxLen_, "GetMatchesSpec1");
1032 enum GET_MATCHES_FOOTER_HC(string _maxLen_) = GET_MATCHES_FOOTER_BASE!(_maxLen_, "Hc_GetMatchesSpec");
1036 enum UPDATE_maxLen = q{
1037 const ptrdiff_t diff = cast(ptrdiff_t)0 - cast(ptrdiff_t)d2;
1038 const(ubyte)* c = cur + maxLen;
1039 const(ubyte)* lim = cur + lenLimit;
1040 for (; c != lim; c++) if (*(c + diff) != *c) break;
1041 maxLen = cast(uint)(c - cur);
1045 private uint* Bt2_MatchFinder_GetMatches (CMatchFinder* p, uint* distances) {
1046 mixin(GET_MATCHES_HEADER!"2");
1047 hv = GetUi16(cur);
1048 curMatch = p.hash[hv];
1049 p.hash[hv] = p.pos;
1050 mixin(GET_MATCHES_FOOTER_BT!"1");
1053 private uint* Bt3Zip_MatchFinder_GetMatches (CMatchFinder* p, uint* distances) {
1054 mixin(GET_MATCHES_HEADER!"3");
1055 mixin(HASH_ZIP_CALC);
1056 curMatch = p.hash[hv];
1057 p.hash[hv] = p.pos;
1058 mixin(GET_MATCHES_FOOTER_BT!"2");
1062 enum SET_mmm = q{
1063 mmm = p.cyclicBufferSize;
1064 if (pos < mmm) mmm = pos;
1068 private uint* Bt3_MatchFinder_GetMatches (CMatchFinder* p, uint* distances) {
1069 uint mmm;
1070 uint h2, d2, pos;
1071 uint maxLen;
1072 uint *hash;
1073 mixin(GET_MATCHES_HEADER!"3");
1075 mixin(HASH3_CALC);
1077 hash = p.hash;
1078 pos = p.pos;
1080 d2 = pos - hash[h2];
1082 curMatch = (hash + kFix3HashSize)[hv];
1084 hash[h2] = pos;
1085 (hash + kFix3HashSize)[hv] = pos;
1087 mixin(SET_mmm);
1089 maxLen = 2;
1091 if (d2 < mmm && *(cur - d2) == *cur)
1093 mixin(UPDATE_maxLen);
1094 distances[0] = cast(uint)maxLen;
1095 distances[1] = d2 - 1;
1096 distances += 2;
1097 if (maxLen == lenLimit)
1099 mixin(`SkipMatchesSpec(`~MF_PARAMS!"p"~`);`);
1100 mixin(MOVE_POS_RET);
1104 mixin(GET_MATCHES_FOOTER_BT!"maxLen");
1108 private uint* Bt4_MatchFinder_GetMatches (CMatchFinder* p, uint* distances) {
1109 uint mmm;
1110 uint h2, h3, d2, d3, pos;
1111 uint maxLen;
1112 uint *hash;
1113 mixin(GET_MATCHES_HEADER!"4");
1115 mixin(HASH4_CALC);
1117 hash = p.hash;
1118 pos = p.pos;
1120 d2 = pos - hash [h2];
1121 d3 = pos - (hash + kFix3HashSize)[h3];
1122 curMatch = (hash + kFix4HashSize)[hv];
1124 hash [h2] = pos;
1125 (hash + kFix3HashSize)[h3] = pos;
1126 (hash + kFix4HashSize)[hv] = pos;
1128 mixin(SET_mmm);
1130 maxLen = 3;
1132 for (;;)
1134 if (d2 < mmm && *(cur - d2) == *cur)
1136 distances[0] = 2;
1137 distances[1] = d2 - 1;
1138 distances += 2;
1139 if (*(cur - d2 + 2) == cur[2])
1141 // distances[-2] = 3;
1143 else if (d3 < mmm && *(cur - d3) == *cur)
1145 d2 = d3;
1146 distances[1] = d3 - 1;
1147 distances += 2;
1149 else
1150 break;
1152 else if (d3 < mmm && *(cur - d3) == *cur)
1154 d2 = d3;
1155 distances[1] = d3 - 1;
1156 distances += 2;
1158 else
1159 break;
1161 mixin(UPDATE_maxLen);
1162 distances[-2] = cast(uint)maxLen;
1163 if (maxLen == lenLimit)
1165 mixin(`SkipMatchesSpec(`~MF_PARAMS!"p"~`);`);
1166 mixin(MOVE_POS_RET);
1168 break;
1171 mixin(GET_MATCHES_FOOTER_BT!"maxLen");
1175 private uint* Bt5_MatchFinder_GetMatches (CMatchFinder* p, uint* distances) {
1176 uint mmm;
1177 uint h2, h3, d2, d3, maxLen, pos;
1178 uint *hash;
1179 mixin(GET_MATCHES_HEADER!"5");
1181 mixin(HASH5_CALC);
1183 hash = p.hash;
1184 pos = p.pos;
1186 d2 = pos - hash [h2];
1187 d3 = pos - (hash + kFix3HashSize)[h3];
1188 // d4 = pos - (hash + kFix4HashSize)[h4];
1190 curMatch = (hash + kFix5HashSize)[hv];
1192 hash [h2] = pos;
1193 (hash + kFix3HashSize)[h3] = pos;
1194 // (hash + kFix4HashSize)[h4] = pos;
1195 (hash + kFix5HashSize)[hv] = pos;
1197 mixin(SET_mmm);
1199 maxLen = 4;
1201 for (;;)
1203 if (d2 < mmm && *(cur - d2) == *cur)
1205 distances[0] = 2;
1206 distances[1] = d2 - 1;
1207 distances += 2;
1208 if (*(cur - d2 + 2) == cur[2])
1211 else if (d3 < mmm && *(cur - d3) == *cur)
1213 distances[1] = d3 - 1;
1214 distances += 2;
1215 d2 = d3;
1217 else
1218 break;
1220 else if (d3 < mmm && *(cur - d3) == *cur)
1222 distances[1] = d3 - 1;
1223 distances += 2;
1224 d2 = d3;
1226 else
1227 break;
1229 distances[-2] = 3;
1230 if (*(cur - d2 + 3) != cur[3])
1231 break;
1232 mixin(UPDATE_maxLen);
1233 distances[-2] = cast(uint)maxLen;
1234 if (maxLen == lenLimit)
1236 mixin(`SkipMatchesSpec(`~MF_PARAMS!"p"~`);`);
1237 mixin(MOVE_POS_RET);
1239 break;
1242 mixin(GET_MATCHES_FOOTER_BT!"maxLen");
1246 private uint* Hc4_MatchFinder_GetMatches (CMatchFinder* p, uint* distances) {
1247 uint mmm;
1248 uint h2, h3, d2, d3, pos;
1249 uint maxLen;
1250 uint *hash;
1251 mixin(GET_MATCHES_HEADER!"4");
1253 mixin(HASH4_CALC);
1255 hash = p.hash;
1256 pos = p.pos;
1258 d2 = pos - hash [h2];
1259 d3 = pos - (hash + kFix3HashSize)[h3];
1260 curMatch = (hash + kFix4HashSize)[hv];
1262 hash [h2] = pos;
1263 (hash + kFix3HashSize)[h3] = pos;
1264 (hash + kFix4HashSize)[hv] = pos;
1266 mixin(SET_mmm);
1268 maxLen = 3;
1270 for (;;)
1272 if (d2 < mmm && *(cur - d2) == *cur)
1274 distances[0] = 2;
1275 distances[1] = d2 - 1;
1276 distances += 2;
1277 if (*(cur - d2 + 2) == cur[2])
1279 // distances[-2] = 3;
1281 else if (d3 < mmm && *(cur - d3) == *cur)
1283 d2 = d3;
1284 distances[1] = d3 - 1;
1285 distances += 2;
1287 else
1288 break;
1290 else if (d3 < mmm && *(cur - d3) == *cur)
1292 d2 = d3;
1293 distances[1] = d3 - 1;
1294 distances += 2;
1296 else
1297 break;
1299 mixin(UPDATE_maxLen);
1300 distances[-2] = cast(uint)maxLen;
1301 if (maxLen == lenLimit)
1303 p.son[p.cyclicBufferPos] = curMatch;
1304 mixin(MOVE_POS_RET);
1306 break;
1309 mixin(GET_MATCHES_FOOTER_HC!"maxLen");
1313 private uint *Hc5_MatchFinder_GetMatches (CMatchFinder* p, uint* distances) {
1314 uint mmm;
1315 uint h2, h3, d2, d3, maxLen, pos;
1316 uint *hash;
1317 mixin(GET_MATCHES_HEADER!"5");
1319 mixin(HASH5_CALC);
1321 hash = p.hash;
1322 pos = p.pos;
1324 d2 = pos - hash [h2];
1325 d3 = pos - (hash + kFix3HashSize)[h3];
1326 // d4 = pos - (hash + kFix4HashSize)[h4];
1328 curMatch = (hash + kFix5HashSize)[hv];
1330 hash [h2] = pos;
1331 (hash + kFix3HashSize)[h3] = pos;
1332 // (hash + kFix4HashSize)[h4] = pos;
1333 (hash + kFix5HashSize)[hv] = pos;
1335 mixin(SET_mmm);
1337 maxLen = 4;
1339 for (;;)
1341 if (d2 < mmm && *(cur - d2) == *cur)
1343 distances[0] = 2;
1344 distances[1] = d2 - 1;
1345 distances += 2;
1346 if (*(cur - d2 + 2) == cur[2])
1349 else if (d3 < mmm && *(cur - d3) == *cur)
1351 distances[1] = d3 - 1;
1352 distances += 2;
1353 d2 = d3;
1355 else
1356 break;
1358 else if (d3 < mmm && *(cur - d3) == *cur)
1360 distances[1] = d3 - 1;
1361 distances += 2;
1362 d2 = d3;
1364 else
1365 break;
1367 distances[-2] = 3;
1368 if (*(cur - d2 + 3) != cur[3])
1369 break;
1370 mixin(UPDATE_maxLen);
1371 distances[-2] = maxLen;
1372 if (maxLen == lenLimit)
1374 p.son[p.cyclicBufferPos] = curMatch;
1375 mixin(MOVE_POS_RET);
1377 break;
1380 mixin(GET_MATCHES_FOOTER_HC!"maxLen");
1384 private uint* Hc3Zip_MatchFinder_GetMatches (CMatchFinder* p, uint* distances) {
1385 mixin(GET_MATCHES_HEADER!"3");
1386 mixin(HASH_ZIP_CALC);
1387 curMatch = p.hash[hv];
1388 p.hash[hv] = p.pos;
1389 mixin(GET_MATCHES_FOOTER_HC!"2");
1393 private void Bt2_MatchFinder_Skip (CMatchFinder* p, uint num) {
1394 do { mixin(SKIP_HEADER!"2");
1396 hv = GetUi16(cur);
1397 curMatch = p.hash[hv];
1398 p.hash[hv] = p.pos;
1400 mixin(SKIP_FOOTER); } while (--num);
1403 private void Bt3Zip_MatchFinder_Skip (CMatchFinder* p, uint num) {
1404 do { mixin(SKIP_HEADER!"3");
1406 mixin(HASH_ZIP_CALC);
1407 curMatch = p.hash[hv];
1408 p.hash[hv] = p.pos;
1410 mixin(SKIP_FOOTER); } while (--num);
1413 private void Bt3_MatchFinder_Skip (CMatchFinder* p, uint num) {
1414 do { mixin(SKIP_HEADER!"3");
1416 uint h2;
1417 uint *hash;
1418 mixin(HASH3_CALC);
1419 hash = p.hash;
1420 curMatch = (hash + kFix3HashSize)[hv];
1421 hash[h2] =
1422 (hash + kFix3HashSize)[hv] = p.pos;
1424 mixin(SKIP_FOOTER); } while (--num);
1427 private void Bt4_MatchFinder_Skip (CMatchFinder* p, uint num) {
1428 do { mixin(SKIP_HEADER!"4");
1430 uint h2, h3;
1431 uint *hash;
1432 mixin(HASH4_CALC);
1433 hash = p.hash;
1434 curMatch = (hash + kFix4HashSize)[hv];
1435 hash [h2] =
1436 (hash + kFix3HashSize)[h3] =
1437 (hash + kFix4HashSize)[hv] = p.pos;
1439 mixin(SKIP_FOOTER); } while (--num);
1442 private void Bt5_MatchFinder_Skip (CMatchFinder* p, uint num) {
1443 do { mixin(SKIP_HEADER!"5");
1445 uint h2, h3;
1446 uint *hash;
1447 mixin(HASH5_CALC);
1448 hash = p.hash;
1449 curMatch = (hash + kFix5HashSize)[hv];
1450 hash [h2] =
1451 (hash + kFix3HashSize)[h3] =
1452 // (hash + kFix4HashSize)[h4] =
1453 (hash + kFix5HashSize)[hv] = p.pos;
1455 mixin(SKIP_FOOTER); } while (--num);
1459 private void Hc4_MatchFinder_Skip (CMatchFinder* p, uint num) {
1460 enum minLenSKH = 4;
1461 do { if (p.lenLimit < minLenSKH) { MatchFinder_MovePos(p); num--; continue; } {
1462 ubyte *cur;
1463 uint *hash;
1464 uint *son;
1465 uint pos = p.pos;
1466 uint num2 = num;
1467 /* (p->pos == p->posLimit) is not allowed here !!! */
1468 { const uint rem = p.posLimit - pos; if (num2 > rem) num2 = rem; }
1469 num -= num2;
1470 { const uint cycPos = p.cyclicBufferPos;
1471 son = p.son + cycPos;
1472 p.cyclicBufferPos = cycPos + num2; }
1473 cur = p.buffer;
1474 hash = p.hash;
1475 do {
1476 uint curMatch;
1477 uint hv;
1479 uint h2, h3;
1480 mixin(HASH4_CALC);
1481 curMatch = (hash + kFix4HashSize)[hv];
1482 hash [h2] =
1483 (hash + kFix3HashSize)[h3] =
1484 (hash + kFix4HashSize)[hv] = pos;
1486 //HC_SKIP_FOOTER
1487 cur++; pos++; *son++ = curMatch;
1488 } while (--num2);
1489 p.buffer = cur;
1490 p.pos = pos;
1491 if (pos == p.posLimit) MatchFinder_CheckLimits(p);
1492 }} while(num);
1496 private void Hc5_MatchFinder_Skip (CMatchFinder* p, uint num) {
1497 enum minLenSKH = 5;
1498 do { if (p.lenLimit < minLenSKH) { MatchFinder_MovePos(p); num--; continue; } {
1499 ubyte *cur;
1500 uint *hash;
1501 uint *son;
1502 uint pos = p.pos;
1503 uint num2 = num;
1504 /* (p->pos == p->posLimit) is not allowed here !!! */
1505 { const uint rem = p.posLimit - pos; if (num2 > rem) num2 = rem; }
1506 num -= num2;
1507 { const uint cycPos = p.cyclicBufferPos;
1508 son = p.son + cycPos;
1509 p.cyclicBufferPos = cycPos + num2; }
1510 cur = p.buffer;
1511 hash = p.hash;
1512 do {
1513 uint curMatch;
1514 uint hv;
1516 uint h2, h3;
1517 mixin(HASH5_CALC);
1518 curMatch = (hash + kFix5HashSize)[hv];
1519 hash [h2] =
1520 (hash + kFix3HashSize)[h3] =
1521 // (hash + kFix4HashSize)[h4] =
1522 (hash + kFix5HashSize)[hv] = pos;
1524 //HC_SKIP_FOOTER
1525 cur++; pos++; *son++ = curMatch;
1526 } while (--num2);
1527 p.buffer = cur;
1528 p.pos = pos;
1529 if (pos == p.posLimit) MatchFinder_CheckLimits(p);
1530 }} while(num);
1534 private void Hc3Zip_MatchFinder_Skip (CMatchFinder* p, uint num) {
1535 enum minLenSKH = 3;
1536 do { if (p.lenLimit < minLenSKH) { MatchFinder_MovePos(p); num--; continue; } {
1537 ubyte *cur;
1538 uint *hash;
1539 uint *son;
1540 uint pos = p.pos;
1541 uint num2 = num;
1542 /* (p->pos == p->posLimit) is not allowed here !!! */
1543 { const uint rem = p.posLimit - pos; if (num2 > rem) num2 = rem; }
1544 num -= num2;
1545 { const uint cycPos = p.cyclicBufferPos;
1546 son = p.son + cycPos;
1547 p.cyclicBufferPos = cycPos + num2; }
1548 cur = p.buffer;
1549 hash = p.hash;
1550 do {
1551 uint curMatch;
1552 uint hv;
1554 mixin(HASH_ZIP_CALC);
1555 curMatch = hash[hv];
1556 hash[hv] = pos;
1558 //HC_SKIP_FOOTER
1559 cur++; pos++; *son++ = curMatch;
1560 } while (--num2);
1561 p.buffer = cur;
1562 p.pos = pos;
1563 if (pos == p.posLimit) MatchFinder_CheckLimits(p);
1564 }} while(num);
1568 private void MatchFinder_CreateVTable (CMatchFinder* p, IMatchFinder2* vTable) @nogc {
1569 vTable.Init = cast(Mf_Init_Func)&MatchFinder_Init;
1570 vTable.GetNumAvailableBytes = cast(Mf_GetNumAvailableBytes_Func)&MatchFinder_GetNumAvailableBytes;
1571 vTable.GetPointerToCurrentPos = cast(Mf_GetPointerToCurrentPos_Func)&MatchFinder_GetPointerToCurrentPos;
1572 if (!p.btMode)
1574 if (p.numHashBytes <= 4)
1576 vTable.GetMatches = cast(Mf_GetMatches_Func)&Hc4_MatchFinder_GetMatches;
1577 vTable.Skip = cast(Mf_Skip_Func)&Hc4_MatchFinder_Skip;
1579 else
1581 vTable.GetMatches = cast(Mf_GetMatches_Func)&Hc5_MatchFinder_GetMatches;
1582 vTable.Skip = cast(Mf_Skip_Func)&Hc5_MatchFinder_Skip;
1585 else if (p.numHashBytes == 2)
1587 vTable.GetMatches = cast(Mf_GetMatches_Func)&Bt2_MatchFinder_GetMatches;
1588 vTable.Skip = cast(Mf_Skip_Func)&Bt2_MatchFinder_Skip;
1590 else if (p.numHashBytes == 3)
1592 vTable.GetMatches = cast(Mf_GetMatches_Func)&Bt3_MatchFinder_GetMatches;
1593 vTable.Skip = cast(Mf_Skip_Func)&Bt3_MatchFinder_Skip;
1595 else if (p.numHashBytes == 4)
1597 vTable.GetMatches = cast(Mf_GetMatches_Func)&Bt4_MatchFinder_GetMatches;
1598 vTable.Skip = cast(Mf_Skip_Func)&Bt4_MatchFinder_Skip;
1600 else
1602 vTable.GetMatches = cast(Mf_GetMatches_Func)&Bt5_MatchFinder_GetMatches;
1603 vTable.Skip = cast(Mf_Skip_Func)&Bt5_MatchFinder_Skip;
1608 private void LzFindPrepare () @nogc {
1612 // ////////////////////////////////////////////////////////////////////////// //
1613 // ////////////////////////////////////////////////////////////////////////// //
1614 // ////////////////////////////////////////////////////////////////////////// //
1615 // ////////////////////////////////////////////////////////////////////////// //
1616 /* for good normalization speed we still reserve 256 MB before 4 GB range */
1617 enum kLzmaMaxHistorySize = (cast(uint)15 << 28);
1619 enum kNumTopBits = 24;
1620 enum kTopValue = (cast(uint)1 << kNumTopBits);
1622 enum kNumBitModelTotalBits = 11;
1623 enum kBitModelTotal = (1 << kNumBitModelTotalBits);
1624 enum kNumMoveBits = 5;
1625 enum kProbInitValue = (kBitModelTotal >> 1);
1627 enum kNumMoveReducingBits = 4;
1628 enum kNumBitPriceShiftBits = 4;
1629 // #define kBitPrice (1 << kNumBitPriceShiftBits)
1631 enum REP_LEN_COUNT = 64;
1634 //==========================================================================
1636 // LzmaEncProps_Init
1638 //==========================================================================
1639 public void LzmaEncProps_Init (CLzmaEncProps* p) @nogc {
1640 p.level = 5;
1641 p.dictSize = p.mc = 0;
1642 p.reduceSize = cast(ulong)cast(long)-1;
1643 p.lc = p.lp = p.pb = p.algo = p.fb = p.btMode = p.numHashBytes = -1;
1644 p.writeEndMark = 0;
1648 //==========================================================================
1650 // LzmaEncProps_Normalize
1652 //==========================================================================
1653 public void LzmaEncProps_Normalize (CLzmaEncProps* p) @nogc {
1654 int level = p.level;
1655 if (level < 0) level = 5;
1656 p.level = level;
1658 if (p.dictSize == 0)
1659 p.dictSize =
1660 ( level <= 3 ? (cast(uint)1 << (level * 2 + 16)) :
1661 ( level <= 6 ? (cast(uint)1 << (level + 19)) :
1662 ( level <= 7 ? (cast(uint)1 << 25) : (cast(uint)1 << 26)
1663 )));
1665 if (p.dictSize > p.reduceSize)
1667 uint v = cast(uint)p.reduceSize;
1668 const uint kReduceMin = (cast(uint)1 << 12);
1669 if (v < kReduceMin)
1670 v = kReduceMin;
1671 if (p.dictSize > v)
1672 p.dictSize = v;
1675 if (p.lc < 0) p.lc = 3;
1676 if (p.lp < 0) p.lp = 0;
1677 if (p.pb < 0) p.pb = 2;
1679 if (p.algo < 0) p.algo = (level < 5 ? 0 : 1);
1680 if (p.fb < 0) p.fb = (level < 7 ? 32 : 64);
1681 if (p.btMode < 0) p.btMode = (p.algo == 0 ? 0 : 1);
1682 if (p.numHashBytes < 0) p.numHashBytes = (p.btMode ? 4 : 5);
1683 if (p.mc == 0) p.mc = (16 + (cast(uint)p.fb >> 1)) >> (p.btMode ? 0 : 1);
1687 //==========================================================================
1689 // LzmaEncProps_GetDictSize
1691 //==========================================================================
1692 public uint LzmaEncProps_GetDictSize (const(CLzmaEncProps)* props2) @nogc {
1693 CLzmaEncProps props = *props2;
1694 LzmaEncProps_Normalize(&props);
1695 return props.dictSize;
1700 x86/x64:
1702 BSR:
1703 IF (SRC == 0) ZF = 1, DEST is undefined;
1704 AMD : DEST is unchanged;
1705 IF (SRC != 0) ZF = 0; DEST is index of top non-zero bit
1706 BSR is slow in some processors
1708 LZCNT:
1709 IF (SRC == 0) CF = 1, DEST is size_in_bits_of_register(src) (32 or 64)
1710 IF (SRC != 0) CF = 0, DEST = num_lead_zero_bits
1711 IF (DEST == 0) ZF = 1;
1713 LZCNT works only in new processors starting from Haswell.
1714 if LZCNT is not supported by processor, then it's executed as BSR.
1715 LZCNT can be faster than BSR, if supported.
1719 //k8: define this for ARM (for some reason)
1720 // #define LZMA_LOG_BSR
1722 #ifdef LZMA_LOG_BSR
1725 C code: : (30 - __builtin_clz(x))
1726 gcc9/gcc10 for x64 /x86 : 30 - (bsr(x) xor 31)
1727 clang10 for x64 : 31 + (bsr(x) xor -32)
1730 #define MY_clz(x) ((uint)__builtin_clz(x))
1731 // __lzcnt32
1732 // __builtin_ia32_lzcnt_u32
1735 #ifndef BSR2_RET
1737 #define BSR2_RET(pos, res) { uint zz = 30 - MY_clz(pos); \
1738 res = (zz + zz) + (pos >> zz); }
1740 #endif
1743 uint GetPosSlot1(uint pos);
1744 uint GetPosSlot1(uint pos)
1746 uint res;
1747 BSR2_RET(pos, res);
1748 return res;
1750 #define GetPosSlot2(pos, res) { BSR2_RET(pos, res); }
1751 #define GetPosSlot(pos, res) { if (pos < 2) res = pos; else BSR2_RET(pos, res); }
1754 #else // ! LZMA_LOG_BSR
1757 enum kNumLogBits = (11 + usize.sizeof / 8 * 3);
1759 enum kDicLogSizeMaxCompress = ((kNumLogBits - 1) * 2 + 7);
1761 private void LzmaEnc_FastPosInit (ubyte* g_FastPos) @nogc {
1762 uint slot;
1763 g_FastPos[0] = 0;
1764 g_FastPos[1] = 1;
1765 g_FastPos += 2;
1767 for (slot = 2; slot < kNumLogBits * 2; slot++)
1769 usize k = (cast(usize)1 << ((slot >> 1) - 1));
1770 usize j;
1771 for (j = 0; j < k; j++)
1772 g_FastPos[j] = cast(ubyte)slot;
1773 g_FastPos += k;
1777 /* we can use ((limit - pos) >> 31) only if (pos < ((uint)1 << 31)) */
1779 #define BSR2_RET(pos, res) { uint zz = 6 + ((kNumLogBits - 1) & \
1780 (0 - (((((uint)1 << (kNumLogBits + 6)) - 1) - pos) >> 31))); \
1781 res = p->g_FastPos[pos >> zz] + (zz * 2); }
1785 #define BSR2_RET(pos, res) { uint zz = 6 + ((kNumLogBits - 1) & \
1786 (0 - (((((uint)1 << (kNumLogBits)) - 1) - (pos >> 6)) >> 31))); \
1787 res = p->g_FastPos[pos >> zz] + (zz * 2); }
1790 enum BSR2_RET(string pos, string res) = `
1791 { uint zz = (`~pos~` < (1 << (kNumLogBits + 6))) ? 6 : 6 + kNumLogBits - 1;
1792 `~res~` = p.g_FastPos[`~pos~` >> zz] + (zz * 2); }
1796 #define BSR2_RET(pos, res) { res = (pos < (1 << (kNumLogBits + 6))) ? \
1797 p->g_FastPos[pos >> 6] + 12 : \
1798 p->g_FastPos[pos >> (6 + kNumLogBits - 1)] + (6 + (kNumLogBits - 1)) * 2; }
1801 enum GetPosSlot1(string pos) = `p.g_FastPos[`~pos~`]`;
1803 enum GetPosSlot2(string pos, string res) = BSR2_RET!(pos, res);
1805 enum GetPosSlot(string pos, string res) = `{
1806 if (`~pos~` < kNumFullDistances) `~res~` = p.g_FastPos[`~pos~` & (kNumFullDistances - 1)];
1807 else {`~BSR2_RET!(pos, res)~`}
1810 //#endif // LZMA_LOG_BSR
1813 enum LZMA_NUM_REPS = 4;
1815 alias CState = ushort;
1816 alias CExtra = ushort;
1818 struct COptimal {
1819 uint price;
1820 CState state;
1821 CExtra extra;
1822 // 0 : normal
1823 // 1 : LIT : MATCH
1824 // > 1 : MATCH (extra-1) : LIT : REP0 (len)
1825 uint len;
1826 uint dist;
1827 uint[LZMA_NUM_REPS] reps;
1831 // 18.06
1832 enum kNumOpts = (1 << 11);
1833 enum kPackReserve = (kNumOpts * 8);
1834 // #define kNumOpts (1 << 12)
1835 // #define kPackReserve (1 + kNumOpts * 2)
1837 enum kNumLenToPosStates = 4;
1838 enum kNumPosSlotBits = 6;
1839 // #define kDicLogSizeMin 0
1840 enum kDicLogSizeMax = 32;
1841 enum kDistTableSizeMax = (kDicLogSizeMax * 2);
1843 enum kNumAlignBits = 4;
1844 enum kAlignTableSize = (1 << kNumAlignBits);
1845 enum kAlignMask = (kAlignTableSize - 1);
1847 enum kStartPosModelIndex = 4;
1848 enum kEndPosModelIndex = 14;
1849 enum kNumFullDistances = (1 << (kEndPosModelIndex >> 1));
1851 enum LZMA_PB_MAX = 4;
1852 enum LZMA_LC_MAX = 8;
1853 enum LZMA_LP_MAX = 4;
1855 enum LZMA_NUM_PB_STATES_MAX = (1 << LZMA_PB_MAX);
1857 enum kLenNumLowBits = 3;
1858 enum kLenNumLowSymbols = (1 << kLenNumLowBits);
1859 enum kLenNumHighBits = 8;
1860 enum kLenNumHighSymbols = (1 << kLenNumHighBits);
1861 enum kLenNumSymbolsTotal = (kLenNumLowSymbols * 2 + kLenNumHighSymbols);
1863 enum LZMA_MATCH_LEN_MIN = 2;
1864 enum LZMA_MATCH_LEN_MAX = (LZMA_MATCH_LEN_MIN + kLenNumSymbolsTotal - 1);
1866 enum kNumStates = 12;
1869 struct CLenEnc {
1870 CLzmaProb[LZMA_NUM_PB_STATES_MAX << (kLenNumLowBits + 1)] low;
1871 CLzmaProb[kLenNumHighSymbols] high;
1875 struct CLenPriceEnc {
1876 uint tableSize;
1877 uint[kLenNumSymbolsTotal][LZMA_NUM_PB_STATES_MAX] prices;
1878 // uint prices1[LZMA_NUM_PB_STATES_MAX][kLenNumLowSymbols * 2];
1879 // uint prices2[kLenNumSymbolsTotal];
1882 enum GET_PRICE_LEN(string p, string posState, string len) =
1883 `((`~p~`).prices[`~posState~`][cast(usize)(`~len~`) - LZMA_MATCH_LEN_MIN])`;
1886 #define GET_PRICE_LEN(p, posState, len) \
1887 ((p)->prices2[(usize)(len) - 2] + ((p)->prices1[posState][((len) - 2) & (kLenNumLowSymbols * 2 - 1)] & (((len) - 2 - kLenNumLowSymbols * 2) >> 9)))
1890 struct CRangeEnc {
1891 uint range;
1892 uint cache;
1893 ulong low;
1894 ulong cacheSize;
1895 ubyte *buf;
1896 ubyte *bufLim;
1897 ubyte *bufBase;
1898 ISeqOutStream *outStream;
1899 ulong processed;
1900 SRes res;
1904 struct CSaveState {
1905 CLzmaProb *litProbs;
1907 uint state;
1908 uint[LZMA_NUM_REPS] reps;
1910 CLzmaProb[1 << kNumAlignBits] posAlignEncoder;
1911 CLzmaProb[kNumStates] isRep;
1912 CLzmaProb[kNumStates] isRepG0;
1913 CLzmaProb[kNumStates] isRepG1;
1914 CLzmaProb[kNumStates] isRepG2;
1915 CLzmaProb[LZMA_NUM_PB_STATES_MAX][kNumStates] isMatch;
1916 CLzmaProb[LZMA_NUM_PB_STATES_MAX][kNumStates] isRep0Long;
1918 CLzmaProb[1 << kNumPosSlotBits][kNumLenToPosStates] posSlotEncoder;
1919 CLzmaProb[kNumFullDistances] posEncoders;
1921 CLenEnc lenProbs;
1922 CLenEnc repLenProbs;
1926 alias CProbPrice = uint;
1927 alias BoolInt = int;
1930 struct CLzmaEnc {
1931 void *matchFinderObj;
1932 IMatchFinder2 matchFinder;
1934 uint optCur;
1935 uint optEnd;
1937 uint longestMatchLen;
1938 uint numPairs;
1939 uint numAvail;
1941 uint state;
1942 uint numFastBytes;
1943 uint additionalOffset;
1944 uint[LZMA_NUM_REPS] reps;
1945 uint lpMask, pbMask;
1946 CLzmaProb *litProbs;
1947 CRangeEnc rc;
1949 uint backRes;
1951 uint lc, lp, pb;
1952 uint lclp;
1954 BoolInt fastMode;
1955 BoolInt writeEndMark;
1956 BoolInt finished;
1957 BoolInt multiThread;
1958 BoolInt needInit;
1959 // BoolInt _maxMode;
1961 ulong nowPos64;
1963 uint matchPriceCount;
1964 // uint alignPriceCount;
1965 int repLenEncCounter;
1967 uint distTableSize;
1969 uint dictSize;
1970 SRes result;
1972 CMatchFinder matchFinderBase;
1975 // we suppose that we have 8-bytes alignment after CMatchFinder
1977 // LZ thread
1978 CProbPrice[kBitModelTotal >> kNumMoveReducingBits] ProbPrices;
1980 // we want {len , dist} pairs to be 8-bytes aligned in matches array
1981 uint[LZMA_MATCH_LEN_MAX * 2 + 2] matches;
1983 // we want 8-bytes alignment here
1984 uint[kAlignTableSize] alignPrices;
1985 uint[kDistTableSizeMax][kNumLenToPosStates] posSlotPrices;
1986 uint[kNumFullDistances][kNumLenToPosStates] distancesPrices;
1988 CLzmaProb[1 << kNumAlignBits] posAlignEncoder;
1989 CLzmaProb[kNumStates] isRep;
1990 CLzmaProb[kNumStates] isRepG0;
1991 CLzmaProb[kNumStates] isRepG1;
1992 CLzmaProb[kNumStates] isRepG2;
1993 CLzmaProb[LZMA_NUM_PB_STATES_MAX][kNumStates] isMatch;
1994 CLzmaProb[LZMA_NUM_PB_STATES_MAX][kNumStates] isRep0Long;
1995 CLzmaProb[1 << kNumPosSlotBits][kNumLenToPosStates] posSlotEncoder;
1996 CLzmaProb[kNumFullDistances] posEncoders;
1998 CLenEnc lenProbs;
1999 CLenEnc repLenProbs;
2001 //#ifndef LZMA_LOG_BSR
2002 ubyte[1 << kNumLogBits] g_FastPos;
2003 //#endif
2005 CLenPriceEnc lenEnc;
2006 CLenPriceEnc repLenEnc;
2008 COptimal[kNumOpts] opt;
2010 CSaveState saveState;
2012 // BoolInt mf_Failure;
2016 //#define MFB (p.matchFinderBase)
2019 //==========================================================================
2021 // LzmaEnc_SetProps
2023 //==========================================================================
2024 public SRes LzmaEnc_SetProps (CLzmaEncHandle pp, const(CLzmaEncProps)* props2) @nogc {
2025 CLzmaEnc *p = cast(CLzmaEnc *)pp;
2026 CLzmaEncProps props = *props2;
2027 LzmaEncProps_Normalize(&props);
2029 if (props.lc > LZMA_LC_MAX
2030 || props.lp > LZMA_LP_MAX
2031 || props.pb > LZMA_PB_MAX)
2032 return SZ_ERROR_PARAM;
2035 if (props.dictSize > kLzmaMaxHistorySize)
2036 props.dictSize = kLzmaMaxHistorySize;
2038 //#ifndef LZMA_LOG_BSR
2040 const ulong dict64 = props.dictSize;
2041 if (dict64 > (cast(ulong)1 << kDicLogSizeMaxCompress))
2042 return SZ_ERROR_PARAM;
2044 //#endif
2046 p.dictSize = props.dictSize;
2048 uint fb = cast(uint)props.fb;
2049 if (fb < 5)
2050 fb = 5;
2051 if (fb > LZMA_MATCH_LEN_MAX)
2052 fb = LZMA_MATCH_LEN_MAX;
2053 p.numFastBytes = fb;
2055 p.lc = cast(uint)props.lc;
2056 p.lp = cast(uint)props.lp;
2057 p.pb = cast(uint)props.pb;
2058 p.fastMode = (props.algo == 0);
2059 // p->_maxMode = True;
2060 (p.matchFinderBase).btMode = cast(ubyte)(props.btMode ? 1 : 0);
2062 uint numHashBytes = 4;
2063 if (props.btMode)
2065 if (props.numHashBytes < 2) numHashBytes = 2;
2066 else if (props.numHashBytes < 4) numHashBytes = cast(uint)props.numHashBytes;
2068 if (props.numHashBytes >= 5) numHashBytes = 5;
2070 (p.matchFinderBase).numHashBytes = numHashBytes;
2073 (p.matchFinderBase).cutValue = props.mc;
2075 p.writeEndMark = cast(BoolInt)props.writeEndMark;
2077 return SZ_OK;
2081 //==========================================================================
2083 // LzmaEnc_SetDataSize
2085 //==========================================================================
2086 public void LzmaEnc_SetDataSize (CLzmaEncHandle pp, ulong expectedDataSiize) @nogc {
2087 CLzmaEnc *p = cast(CLzmaEnc *)pp;
2088 (p.matchFinderBase).expectedDataSize = expectedDataSiize;
2092 enum kState_Start = 0;
2093 enum kState_LitAfterMatch = 4;
2094 enum kState_LitAfterRep = 5;
2095 enum kState_MatchAfterLit = 7;
2096 enum kState_RepAfterLit = 8;
2098 immutable ubyte[kNumStates] kLiteralNextStates = [0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5];
2099 immutable ubyte[kNumStates] kMatchNextStates = [7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10];
2100 immutable ubyte[kNumStates] kRepNextStates = [8, 8, 8, 8, 8, 8, 8, 11, 11, 11, 11, 11];
2101 immutable ubyte[kNumStates] kShortRepNextStates= [9, 9, 9, 9, 9, 9, 9, 11, 11, 11, 11, 11];
2103 enum IsLitState(string s) = `((`~s~`) < 7)`;
2104 enum GetLenToPosState2(string len) = `(((`~len~`) < kNumLenToPosStates - 1) ? (`~len~`) : kNumLenToPosStates - 1)`;
2105 enum GetLenToPosState(string len) = `(((`~len~`) < kNumLenToPosStates + 1) ? (`~len~`) - 2 : kNumLenToPosStates - 1)`;
2107 enum kInfinityPrice = (1 << 30);
2109 private void RangeEnc_Construct (CRangeEnc* p) @nogc {
2110 p.outStream = null;
2111 p.bufBase = null;
2114 enum RangeEnc_GetProcessed(string p) = `((`~p~`).processed + cast(usize)((`~p~`).buf - (`~p~`).bufBase) + (`~p~`).cacheSize)`;
2115 enum RangeEnc_GetProcessed_sizet(string p) = `(cast(usize)(`~p~`).processed + cast(usize)((`~p~`).buf - (`~p~`).bufBase) + cast(usize)(`~p~`).cacheSize)`;
2117 enum RC_BUF_SIZE = (1 << 16);
2119 private int RangeEnc_Alloc (CRangeEnc *p, ISzAllocPtr alloc) {
2120 if (!p.bufBase)
2122 p.bufBase = cast(ubyte *)ISzAlloc_Alloc(alloc, RC_BUF_SIZE);
2123 if (!p.bufBase)
2124 return 0;
2125 p.bufLim = p.bufBase + RC_BUF_SIZE;
2127 return 1;
2130 private void RangeEnc_Free (CRangeEnc *p, ISzAllocPtr alloc) {
2131 ISzAlloc_Free(alloc, p.bufBase);
2132 p.bufBase = null;
2136 private void RangeEnc_Init (CRangeEnc* p) @nogc {
2137 /* Stream.Init(); */
2138 p.range = 0xFFFFFFFF;
2139 p.cache = 0;
2140 p.low = 0;
2141 p.cacheSize = 0;
2143 p.buf = p.bufBase;
2145 p.processed = 0;
2146 p.res = SZ_OK;
2149 //MY_NO_INLINE
2150 private void RangeEnc_FlushStream (CRangeEnc* p) {
2151 usize num;
2152 if (p.res != SZ_OK)
2153 return;
2154 num = cast(usize)(p.buf - p.bufBase);
2157 if (num != ISeqOutStream_Write(p.outStream, p.bufBase, num))
2158 p.res = SZ_ERROR_WRITE;
2160 if (p.outStream.Write(p.outStream, p.bufBase, num) != num) p.res = SZ_ERROR_WRITE;
2162 p.processed += num;
2163 p.buf = p.bufBase;
2166 //MY_NO_INLINE
2167 private void RangeEnc_ShiftLow(CRangeEnc *p)
2169 uint low = cast(uint)p.low;
2170 uint high = cast(uint)(p.low >> 32);
2171 p.low = cast(uint)(low << 8);
2172 if (low < cast(uint)0xFF000000 || high != 0)
2175 ubyte *buf = p.buf;
2176 *buf++ = cast(ubyte)(p.cache + high);
2177 p.cache = cast(uint)(low >> 24);
2178 p.buf = buf;
2179 if (buf == p.bufLim)
2180 RangeEnc_FlushStream(p);
2181 if (p.cacheSize == 0)
2182 return;
2184 high += 0xFF;
2185 for (;;)
2187 ubyte *buf = p.buf;
2188 *buf++ = cast(ubyte)(high);
2189 p.buf = buf;
2190 if (buf == p.bufLim)
2191 RangeEnc_FlushStream(p);
2192 if (--p.cacheSize == 0)
2193 return;
2196 p.cacheSize++;
2199 private void RangeEnc_FlushData(CRangeEnc *p)
2201 int i;
2202 for (i = 0; i < 5; i++)
2203 RangeEnc_ShiftLow(p);
2206 enum RC_NORM(string p) = `if (range < kTopValue) { range <<= 8; RangeEnc_ShiftLow(`~p~`); }`;
2208 enum RC_BIT_PRE(string p, string prob) = `
2209 ttt = *(`~prob~`);
2210 newBound = (range >> kNumBitModelTotalBits) * ttt;
2213 // #define LZMA_ENC_USE_BRANCH
2215 version(LZMA_ENC_USE_BRANCH) {
2217 enum RC_BIT(string p, string prob, string bit) = `{
2218 `~RC_BIT_PRE!(p, prob)~`
2219 if (`~bit~` == 0) { range = newBound; ttt += (kBitModelTotal - ttt) >> kNumMoveBits; }
2220 else { (`~p~`).low += newBound; range -= newBound; ttt -= ttt >> kNumMoveBits; }
2221 *(`~prob~`) = cast(CLzmaProb)ttt;
2222 `~RC_NORM!p~`
2226 } else {
2228 enum RC_BIT(string p, string prob, string bit) = `{
2229 uint mask;
2230 `~RC_BIT_PRE!(p, prob)~`
2231 mask = 0 - cast(uint)`~bit~`;
2232 range &= mask;
2233 mask &= newBound;
2234 range -= mask;
2235 (`~p~`).low += mask;
2236 mask = cast(uint)`~bit~` - 1;
2237 range += newBound & mask;
2238 mask &= (kBitModelTotal - ((1 << kNumMoveBits) - 1));
2239 mask += ((1 << kNumMoveBits) - 1);
2240 ttt += cast(uint)(cast(int)(mask - ttt) >> kNumMoveBits);
2241 *(`~prob~`) = cast(CLzmaProb)ttt;
2242 `~RC_NORM!p~`
2249 enum RC_BIT_0_BASE(string p, string prob) =
2250 `range = newBound; *(`~prob~`) = cast(CLzmaProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits));`;
2252 enum RC_BIT_1_BASE(string p, string prob) =
2253 `range -= newBound; (`~p~`).low += newBound; *(`~prob~`) = cast(CLzmaProb)(ttt - (ttt >> kNumMoveBits));`;
2255 enum RC_BIT_0(string p, string prob) =
2256 RC_BIT_0_BASE!(p, prob)~
2257 RC_NORM!(p);
2259 enum RC_BIT_1(string p, string prob) =
2260 RC_BIT_1_BASE!(p, prob)~
2261 RC_NORM!(p);
2263 private void RangeEnc_EncodeBit_0(CRangeEnc *p, CLzmaProb *prob)
2265 uint range, ttt, newBound;
2266 range = p.range;
2267 mixin(RC_BIT_PRE!("p", "prob"));
2268 mixin(RC_BIT_0!("p", "prob"));
2269 p.range = range;
2272 private void LitEnc_Encode(CRangeEnc *p, CLzmaProb *probs, uint sym)
2274 uint range = p.range;
2275 sym |= 0x100;
2278 uint ttt, newBound;
2279 // RangeEnc_EncodeBit(p, probs + (sym >> 8), (sym >> 7) & 1);
2280 CLzmaProb *prob = probs + (sym >> 8);
2281 uint bit = (sym >> 7) & 1;
2282 sym <<= 1;
2283 mixin(RC_BIT!("p", "prob", "bit"));
2285 while (sym < 0x10000);
2286 p.range = range;
2289 private void LitEnc_EncodeMatched(CRangeEnc *p, CLzmaProb *probs, uint sym, uint matchByte)
2291 uint range = p.range;
2292 uint offs = 0x100;
2293 sym |= 0x100;
2296 uint ttt, newBound;
2297 CLzmaProb *prob;
2298 uint bit;
2299 matchByte <<= 1;
2300 // RangeEnc_EncodeBit(p, probs + (offs + (matchByte & offs) + (sym >> 8)), (sym >> 7) & 1);
2301 prob = probs + (offs + (matchByte & offs) + (sym >> 8));
2302 bit = (sym >> 7) & 1;
2303 sym <<= 1;
2304 offs &= ~(matchByte ^ sym);
2305 mixin(RC_BIT!("p", "prob", "bit"));
2307 while (sym < 0x10000);
2308 p.range = range;
2313 private void LzmaEnc_InitPriceTables(CProbPrice *ProbPrices)
2315 uint i;
2316 for (i = 0; i < (kBitModelTotal >> kNumMoveReducingBits); i++)
2318 const uint kCyclesBits = kNumBitPriceShiftBits;
2319 uint w = (i << kNumMoveReducingBits) + (1 << (kNumMoveReducingBits - 1));
2320 uint bitCount = 0;
2321 uint j;
2322 for (j = 0; j < kCyclesBits; j++)
2324 w = w * w;
2325 bitCount <<= 1;
2326 while (w >= (cast(uint)1 << 16))
2328 w >>= 1;
2329 bitCount++;
2332 ProbPrices[i] = cast(CProbPrice)((cast(uint)kNumBitModelTotalBits << kCyclesBits) - 15 - bitCount);
2333 // printf("\n%3d: %5d", i, ProbPrices[i]);
2338 enum GET_PRICE(string prob, string bit) =
2339 `p.ProbPrices[((`~prob~`) ^ cast(uint)(((-cast(int)(`~bit~`))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits]`;
2341 enum GET_PRICEa(string prob, string bit) =
2342 `ProbPrices[((`~prob~`) ^ cast(uint)((-(cast(int)(`~bit~`))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits]`;
2344 enum GET_PRICE_0(string prob) = `p.ProbPrices[(`~prob~`) >> kNumMoveReducingBits]`;
2345 enum GET_PRICE_1(string prob) = `p.ProbPrices[((`~prob~`) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits]`;
2347 enum GET_PRICEa_0(string prob) = `ProbPrices[(`~prob~`) >> kNumMoveReducingBits]`;
2348 enum GET_PRICEa_1(string prob) = `ProbPrices[((`~prob~`) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits]`;
2351 private uint LitEnc_GetPrice(const CLzmaProb *probs, uint sym, const CProbPrice *ProbPrices)
2353 uint price = 0;
2354 sym |= 0x100;
2357 uint bit = sym & 1;
2358 sym >>= 1;
2359 price += mixin(GET_PRICEa!("probs[sym]", "bit"));
2361 while (sym >= 2);
2362 return price;
2366 private uint LitEnc_Matched_GetPrice(const CLzmaProb *probs, uint sym, uint matchByte, const CProbPrice *ProbPrices)
2368 uint price = 0;
2369 uint offs = 0x100;
2370 sym |= 0x100;
2373 matchByte <<= 1;
2374 price += mixin(GET_PRICEa!("probs[offs + (matchByte & offs) + (sym >> 8)]", "(sym >> 7) & 1"));
2375 sym <<= 1;
2376 offs &= ~(matchByte ^ sym);
2378 while (sym < 0x10000);
2379 return price;
2383 private void RcTree_ReverseEncode(CRangeEnc *rc, CLzmaProb *probs, uint numBits, uint sym)
2385 uint range = rc.range;
2386 uint m = 1;
2389 uint ttt, newBound;
2390 uint bit = sym & 1;
2391 // RangeEnc_EncodeBit(rc, probs + m, bit);
2392 sym >>= 1;
2393 mixin(RC_BIT!("rc", "probs + m", "bit"));
2394 m = (m << 1) | bit;
2396 while (--numBits);
2397 rc.range = range;
2402 private void LenEnc_Init (CLenEnc* p) @nogc {
2403 uint i;
2404 for (i = 0; i < (LZMA_NUM_PB_STATES_MAX << (kLenNumLowBits + 1)); i++)
2405 p.low[i] = kProbInitValue;
2406 for (i = 0; i < kLenNumHighSymbols; i++)
2407 p.high[i] = kProbInitValue;
2410 private void LenEnc_Encode(CLenEnc *p, CRangeEnc *rc, uint sym, uint posState)
2412 uint range, ttt, newBound;
2413 CLzmaProb *probs = p.low.ptr;
2414 range = rc.range;
2415 mixin(RC_BIT_PRE!("rc", "probs"));
2416 if (sym >= kLenNumLowSymbols)
2418 mixin(RC_BIT_1!("rc", "probs"));
2419 probs += kLenNumLowSymbols;
2420 mixin(RC_BIT_PRE!("rc", "probs"));
2421 if (sym >= kLenNumLowSymbols * 2)
2423 mixin(RC_BIT_1!("rc", "probs"));
2424 rc.range = range;
2425 // RcTree_Encode(rc, p->high, kLenNumHighBits, sym - kLenNumLowSymbols * 2);
2426 LitEnc_Encode(rc, p.high.ptr, sym - kLenNumLowSymbols * 2);
2427 return;
2429 sym -= kLenNumLowSymbols;
2432 // RcTree_Encode(rc, probs + (posState << kLenNumLowBits), kLenNumLowBits, sym);
2434 uint m;
2435 uint bit;
2436 mixin(RC_BIT_0!("rc", "probs"));
2437 probs += (posState << (1 + kLenNumLowBits));
2438 bit = (sym >> 2) ; mixin(RC_BIT!("rc", "probs + 1", "bit")); m = (1 << 1) + bit;
2439 bit = (sym >> 1) & 1; mixin(RC_BIT!("rc", "probs + m", "bit")); m = (m << 1) + bit;
2440 bit = sym & 1; mixin(RC_BIT!("rc", "probs + m", "bit"));
2441 rc.range = range;
2445 private void SetPrices_3 (const(CLzmaProb)* probs, uint startPrice, uint* prices, const(CProbPrice)* ProbPrices) @nogc {
2446 uint i;
2447 for (i = 0; i < 8; i += 2)
2449 uint price = startPrice;
2450 uint prob;
2451 price += mixin(GET_PRICEa!("probs[1 ]", "(i >> 2)"));
2452 price += mixin(GET_PRICEa!("probs[2 + (i >> 2)]", "(i >> 1) & 1"));
2453 prob = probs[4 + (i >> 1)];
2454 prices[i ] = price + mixin(GET_PRICEa_0!"prob");
2455 prices[i + 1] = price + mixin(GET_PRICEa_1!"prob");
2460 //MY_NO_INLINE
2461 private void LenPriceEnc_UpdateTables(
2462 CLenPriceEnc *p,
2463 uint numPosStates,
2464 const(CLenEnc)* enc,
2465 const(CProbPrice)* ProbPrices)
2467 uint b;
2470 uint prob = enc.low[0];
2471 uint a, c;
2472 uint posState;
2473 b = mixin(GET_PRICEa_1!"prob");
2474 a = mixin(GET_PRICEa_0!"prob");
2475 c = b + mixin(GET_PRICEa_0!"enc.low[kLenNumLowSymbols]");
2476 for (posState = 0; posState < numPosStates; posState++)
2478 uint *prices = p.prices[posState].ptr;
2479 const(CLzmaProb)* probs = enc.low.ptr + (posState << (1 + kLenNumLowBits));
2480 SetPrices_3(probs, a, prices, ProbPrices);
2481 SetPrices_3(probs + kLenNumLowSymbols, c, prices + kLenNumLowSymbols, ProbPrices);
2487 uint i;
2488 uint b;
2489 a = GET_PRICEa_0(enc->low[0]);
2490 for (i = 0; i < kLenNumLowSymbols; i++)
2491 p->prices2[i] = a;
2492 a = GET_PRICEa_1(enc->low[0]);
2493 b = a + GET_PRICEa_0(enc->low[kLenNumLowSymbols]);
2494 for (i = kLenNumLowSymbols; i < kLenNumLowSymbols * 2; i++)
2495 p->prices2[i] = b;
2496 a += GET_PRICEa_1(enc->low[kLenNumLowSymbols]);
2500 // p->counter = numSymbols;
2501 // p->counter = 64;
2504 uint i = p.tableSize;
2506 if (i > kLenNumLowSymbols * 2)
2508 const(CLzmaProb)* probs = enc.high.ptr;
2509 uint *prices = p.prices[0].ptr + kLenNumLowSymbols * 2;
2510 i -= kLenNumLowSymbols * 2 - 1;
2511 i >>= 1;
2512 b += mixin(GET_PRICEa_1!"enc.low[kLenNumLowSymbols]");
2516 p->prices2[i] = a +
2517 // RcTree_GetPrice(enc->high, kLenNumHighBits, i - kLenNumLowSymbols * 2, ProbPrices);
2518 LitEnc_GetPrice(probs, i - kLenNumLowSymbols * 2, ProbPrices);
2520 // uint price = a + RcTree_GetPrice(probs, kLenNumHighBits - 1, sym, ProbPrices);
2521 uint sym = --i + (1 << (kLenNumHighBits - 1));
2522 uint price = b;
2525 uint bit = sym & 1;
2526 sym >>= 1;
2527 price += mixin(GET_PRICEa!("probs[sym]", "bit"));
2529 while (sym >= 2);
2532 uint prob = probs[cast(usize)i + (1 << (kLenNumHighBits - 1))];
2533 prices[cast(usize)i * 2 ] = price + mixin(GET_PRICEa_0!"prob");
2534 prices[cast(usize)i * 2 + 1] = price + mixin(GET_PRICEa_1!"prob");
2537 while (i);
2540 import core.stdc.string : memcpy;
2541 uint posState;
2542 usize num = (p.tableSize - kLenNumLowSymbols * 2) * (p.prices[0][0]).sizeof;
2543 for (posState = 1; posState < numPosStates; posState++)
2544 memcpy(p.prices[posState].ptr + kLenNumLowSymbols * 2, p.prices[0].ptr + kLenNumLowSymbols * 2, num);
2551 #ifdef SHOW_STAT
2552 g_STAT_OFFSET += num;
2553 printf("\n MovePos %u", num);
2554 #endif
2557 enum MOVE_POS1(string p, string num) = `{
2558 `~p~`.additionalOffset += (`~num~`);
2559 `~p~`.matchFinder.Skip(`~p~`.matchFinderObj, cast(uint)(`~num~`)); }
2563 private uint ReadMatchDistances(CLzmaEnc *p, uint *numPairsRes)
2565 uint numPairs;
2567 p.additionalOffset++;
2568 p.numAvail = p.matchFinder.GetNumAvailableBytes(p.matchFinderObj);
2570 const uint *d = p.matchFinder.GetMatches(p.matchFinderObj, p.matches.ptr);
2571 // if (!d) { p->mf_Failure = True; *numPairsRes = 0; return 0; }
2572 numPairs = cast(uint)(d - p.matches.ptr);
2574 *numPairsRes = numPairs;
2577 #ifdef SHOW_STAT
2578 printf("\n i = %u numPairs = %u ", g_STAT_OFFSET, numPairs / 2);
2579 g_STAT_OFFSET++;
2581 uint i;
2582 for (i = 0; i < numPairs; i += 2)
2583 printf("%2u %6u | ", p.matches[i], p.matches[i + 1]);
2585 #endif
2588 if (numPairs == 0)
2589 return 0;
2591 const uint len = p.matches[cast(usize)numPairs - 2];
2592 if (len != p.numFastBytes)
2593 return len;
2595 uint numAvail = p.numAvail;
2596 if (numAvail > LZMA_MATCH_LEN_MAX)
2597 numAvail = LZMA_MATCH_LEN_MAX;
2599 const(ubyte)* p1 = p.matchFinder.GetPointerToCurrentPos(p.matchFinderObj) - 1;
2600 const(ubyte)* p2 = p1 + len;
2601 const ptrdiff_t dif = cast(ptrdiff_t)-1 - cast(ptrdiff_t)p.matches[cast(usize)numPairs - 1];
2602 const(ubyte)* lim = p1 + numAvail;
2603 for (; p2 != lim && *p2 == p2[dif]; p2++)
2605 return cast(uint)(p2 - p1);
2611 enum MARK_LIT = (cast(uint)cast(int)-1);
2613 enum MakeAs_Lit(string p) = `{ (`~p~`).dist = MARK_LIT; (`~p~`).extra = 0; }`;
2614 enum MakeAs_ShortRep(string p) = `{ (`~p~`).dist = 0; (`~p~`).extra = 0; }`;
2615 enum IsShortRep(string p) = `((`~p~`).dist == 0)`;
2618 enum GetPrice_ShortRep(string p, string state, string posState) =
2619 `( `~GET_PRICE_0!(p~`.isRepG0[`~state~`]`)~` + `~GET_PRICE_0!(p~`.isRep0Long[`~state~`][`~posState~`]`)~`)`;
2621 enum GetPrice_Rep_0(string p, string state, string posState) = `(
2622 `~GET_PRICE_1!(p~`.isMatch[`~state~`][`~posState~`]`)~`
2623 + `~GET_PRICE_1!(p~`.isRep0Long[`~state~`][`~posState~`]`)~`)
2624 + `~GET_PRICE_1!(p~`.isRep[`~state~`]`)~`
2625 + `~GET_PRICE_0!(p~`.isRepG0[`~state~`]`);
2627 //MY_FORCE_INLINE
2628 private uint GetPrice_PureRep(const(CLzmaEnc)* p, uint repIndex, usize state, usize posState)
2630 uint price;
2631 uint prob = p.isRepG0[state];
2632 if (repIndex == 0)
2634 price = mixin(GET_PRICE_0!"prob");
2635 price += mixin(GET_PRICE_1!"p.isRep0Long[state][posState]");
2637 else
2639 price = mixin(GET_PRICE_1!"prob");
2640 prob = p.isRepG1[state];
2641 if (repIndex == 1)
2642 price += mixin(GET_PRICE_0!"prob");
2643 else
2645 price += mixin(GET_PRICE_1!"prob");
2646 price += mixin(GET_PRICE!("p.isRepG2[state]", "repIndex - 2"));
2649 return price;
2653 private uint Backward(CLzmaEnc *p, uint cur)
2655 uint wr = cur + 1;
2656 p.optEnd = wr;
2658 for (;;)
2660 uint dist = p.opt[cur].dist;
2661 uint len = cast(uint)p.opt[cur].len;
2662 uint extra = cast(uint)p.opt[cur].extra;
2663 cur -= len;
2665 if (extra)
2667 wr--;
2668 p.opt[wr].len = cast(uint)len;
2669 cur -= extra;
2670 len = extra;
2671 if (extra == 1)
2673 p.opt[wr].dist = dist;
2674 dist = MARK_LIT;
2676 else
2678 p.opt[wr].dist = 0;
2679 len--;
2680 wr--;
2681 p.opt[wr].dist = MARK_LIT;
2682 p.opt[wr].len = 1;
2686 if (cur == 0)
2688 p.backRes = dist;
2689 p.optCur = wr;
2690 return len;
2693 wr--;
2694 p.opt[wr].dist = dist;
2695 p.opt[wr].len = cast(uint)len;
2701 enum LIT_PROBS(string pos, string prevByte) =
2702 `(p.litProbs + cast(uint)3 * (((((`~pos~`) << 8) + (`~prevByte~`)) & p.lpMask) << p.lc))`;
2705 private uint GetOptimum(CLzmaEnc *p, uint position)
2707 uint last, cur;
2708 uint[LZMA_NUM_REPS] reps;
2709 uint[LZMA_NUM_REPS] repLens;
2710 uint *matches;
2713 uint numAvail;
2714 uint numPairs, mainLen, repMaxIndex, i, posState;
2715 uint matchPrice, repMatchPrice;
2716 const(ubyte)* data;
2717 ubyte curByte, matchByte;
2719 p.optCur = p.optEnd = 0;
2721 if (p.additionalOffset == 0)
2722 mainLen = ReadMatchDistances(p, &numPairs);
2723 else
2725 mainLen = p.longestMatchLen;
2726 numPairs = p.numPairs;
2729 numAvail = p.numAvail;
2730 if (numAvail < 2)
2732 p.backRes = MARK_LIT;
2733 return 1;
2735 if (numAvail > LZMA_MATCH_LEN_MAX)
2736 numAvail = LZMA_MATCH_LEN_MAX;
2738 data = p.matchFinder.GetPointerToCurrentPos(p.matchFinderObj) - 1;
2739 repMaxIndex = 0;
2741 for (i = 0; i < LZMA_NUM_REPS; i++)
2743 uint len;
2744 const(ubyte)* data2;
2745 reps[i] = p.reps[i];
2746 data2 = data - reps[i];
2747 if (data[0] != data2[0] || data[1] != data2[1])
2749 repLens[i] = 0;
2750 continue;
2752 for (len = 2; len < numAvail && data[len] == data2[len]; len++)
2754 repLens[i] = len;
2755 if (len > repLens[repMaxIndex])
2756 repMaxIndex = i;
2757 if (len == LZMA_MATCH_LEN_MAX) // 21.03 : optimization
2758 break;
2761 if (repLens[repMaxIndex] >= p.numFastBytes)
2763 uint len;
2764 p.backRes = cast(uint)repMaxIndex;
2765 len = repLens[repMaxIndex];
2766 mixin(MOVE_POS1!("p", "len - 1"));
2767 return len;
2770 matches = p.matches.ptr;
2771 //!#define MATCHES matches
2772 // #define MATCHES p->matches
2774 if (mainLen >= p.numFastBytes)
2776 p.backRes = p.matches[cast(usize)numPairs - 1] + LZMA_NUM_REPS;
2777 mixin(MOVE_POS1!("p", "mainLen - 1"));
2778 return mainLen;
2781 curByte = *data;
2782 matchByte = *(data - reps[0]);
2784 last = repLens[repMaxIndex];
2785 if (last <= mainLen)
2786 last = mainLen;
2788 if (last < 2 && curByte != matchByte)
2790 p.backRes = MARK_LIT;
2791 return 1;
2794 p.opt[0].state = cast(CState)p.state;
2796 posState = (position & p.pbMask);
2799 const(CLzmaProb)* probs = mixin(LIT_PROBS!("position", "*(data - 1)"));
2800 p.opt[1].price = mixin(GET_PRICE_0!"p.isMatch[p.state][posState]") +
2801 (!mixin(IsLitState!"p.state") ?
2802 LitEnc_Matched_GetPrice(probs, curByte, matchByte, p.ProbPrices.ptr) :
2803 LitEnc_GetPrice(probs, curByte, p.ProbPrices.ptr));
2806 mixin(MakeAs_Lit!"&p.opt[1]");
2808 matchPrice = mixin(GET_PRICE_1!"p.isMatch[p.state][posState]");
2809 repMatchPrice = matchPrice + mixin(GET_PRICE_1!"p.isRep[p.state]");
2811 // 18.06
2812 if (matchByte == curByte && repLens[0] == 0)
2814 uint shortRepPrice = repMatchPrice + mixin(GetPrice_ShortRep!("p", "p.state", "posState"));
2815 if (shortRepPrice < p.opt[1].price)
2817 p.opt[1].price = shortRepPrice;
2818 mixin(MakeAs_ShortRep!"&p.opt[1]");
2820 if (last < 2)
2822 p.backRes = p.opt[1].dist;
2823 return 1;
2827 p.opt[1].len = 1;
2829 p.opt[0].reps[0] = reps[0];
2830 p.opt[0].reps[1] = reps[1];
2831 p.opt[0].reps[2] = reps[2];
2832 p.opt[0].reps[3] = reps[3];
2834 // ---------- REP ----------
2836 for (i = 0; i < LZMA_NUM_REPS; i++)
2838 uint repLen = repLens[i];
2839 uint price;
2840 if (repLen < 2)
2841 continue;
2842 price = repMatchPrice + GetPrice_PureRep(p, i, p.state, posState);
2845 uint price2 = price + mixin(GET_PRICE_LEN!("&p.repLenEnc", "posState", "repLen"));
2846 COptimal *opt = &p.opt[repLen];
2847 if (price2 < opt.price)
2849 opt.price = price2;
2850 opt.len = cast(uint)repLen;
2851 opt.dist = cast(uint)i;
2852 opt.extra = 0;
2855 while (--repLen >= 2);
2859 // ---------- MATCH ----------
2861 uint len = repLens[0] + 1;
2862 if (len <= mainLen)
2864 uint offs = 0;
2865 uint normalMatchPrice = matchPrice + mixin(GET_PRICE_0!"p.isRep[p.state]");
2867 if (len < 2)
2868 len = 2;
2869 else
2870 while (len > p.matches[offs])
2871 offs += 2;
2873 for (; ; len++)
2875 COptimal *opt;
2876 uint dist = p.matches[cast(usize)offs + 1];
2877 uint price = normalMatchPrice + mixin(GET_PRICE_LEN!("&p.lenEnc", "posState", "len"));
2878 uint lenToPosState = mixin(GetLenToPosState!"len");
2880 if (dist < kNumFullDistances)
2881 price += p.distancesPrices[lenToPosState][dist & (kNumFullDistances - 1)];
2882 else
2884 uint slot;
2885 mixin(GetPosSlot2!("dist", "slot"));
2886 price += p.alignPrices[dist & kAlignMask];
2887 price += p.posSlotPrices[lenToPosState][slot];
2890 opt = &p.opt[len];
2892 if (price < opt.price)
2894 opt.price = price;
2895 opt.len = cast(uint)len;
2896 opt.dist = dist + LZMA_NUM_REPS;
2897 opt.extra = 0;
2900 if (len == p.matches[offs])
2902 offs += 2;
2903 if (offs == numPairs)
2904 break;
2911 cur = 0;
2914 #ifdef SHOW_STAT2
2915 /* if (position >= 0) */
2917 uint i;
2918 printf("\n pos = %4X", position);
2919 for (i = cur; i <= last; i++)
2920 printf("\nprice[%4X] = %u", position - cur + i, p.opt[i].price);
2922 #endif
2928 // ---------- Optimal Parsing ----------
2930 for (;;)
2932 uint numAvail;
2933 uint numAvailFull;
2934 uint newLen, numPairs, prev, state, posState, startLen;
2935 uint litPrice, matchPrice, repMatchPrice;
2936 BoolInt nextIsLit;
2937 ubyte curByte, matchByte;
2938 const(ubyte)* data;
2939 COptimal *curOpt;
2940 COptimal *nextOpt;
2942 if (++cur == last)
2943 break;
2945 // 18.06
2946 if (cur >= kNumOpts - 64)
2948 uint j, best;
2949 uint price = p.opt[cur].price;
2950 best = cur;
2951 for (j = cur + 1; j <= last; j++)
2953 uint price2 = p.opt[j].price;
2954 if (price >= price2)
2956 price = price2;
2957 best = j;
2961 uint delta = best - cur;
2962 if (delta != 0)
2964 mixin(MOVE_POS1!("p", "delta"));
2967 cur = best;
2968 break;
2971 newLen = ReadMatchDistances(p, &numPairs);
2973 if (newLen >= p.numFastBytes)
2975 p.numPairs = numPairs;
2976 p.longestMatchLen = newLen;
2977 break;
2980 curOpt = &p.opt[cur];
2982 position++;
2984 // we need that check here, if skip_items in p->opt are possible
2986 if (curOpt->price >= kInfinityPrice)
2987 continue;
2990 prev = cur - curOpt.len;
2992 if (curOpt.len == 1)
2994 state = cast(uint)p.opt[prev].state;
2995 if (mixin(IsShortRep!"curOpt"))
2996 state = kShortRepNextStates[state];
2997 else
2998 state = kLiteralNextStates[state];
3000 else
3002 const(COptimal)* prevOpt;
3003 uint b0;
3004 uint dist = curOpt.dist;
3006 if (curOpt.extra)
3008 prev -= cast(uint)curOpt.extra;
3009 state = kState_RepAfterLit;
3010 if (curOpt.extra == 1)
3011 state = (dist < LZMA_NUM_REPS ? kState_RepAfterLit : kState_MatchAfterLit);
3013 else
3015 state = cast(uint)p.opt[prev].state;
3016 if (dist < LZMA_NUM_REPS)
3017 state = kRepNextStates[state];
3018 else
3019 state = kMatchNextStates[state];
3022 prevOpt = &p.opt[prev];
3023 b0 = prevOpt.reps[0];
3025 if (dist < LZMA_NUM_REPS)
3027 if (dist == 0)
3029 reps[0] = b0;
3030 reps[1] = prevOpt.reps[1];
3031 reps[2] = prevOpt.reps[2];
3032 reps[3] = prevOpt.reps[3];
3034 else
3036 reps[1] = b0;
3037 b0 = prevOpt.reps[1];
3038 if (dist == 1)
3040 reps[0] = b0;
3041 reps[2] = prevOpt.reps[2];
3042 reps[3] = prevOpt.reps[3];
3044 else
3046 reps[2] = b0;
3047 reps[0] = prevOpt.reps[dist];
3048 reps[3] = prevOpt.reps[dist ^ 1];
3052 else
3054 reps[0] = (dist - LZMA_NUM_REPS + 1);
3055 reps[1] = b0;
3056 reps[2] = prevOpt.reps[1];
3057 reps[3] = prevOpt.reps[2];
3061 curOpt.state = cast(CState)state;
3062 curOpt.reps[0] = reps[0];
3063 curOpt.reps[1] = reps[1];
3064 curOpt.reps[2] = reps[2];
3065 curOpt.reps[3] = reps[3];
3067 data = p.matchFinder.GetPointerToCurrentPos(p.matchFinderObj) - 1;
3068 curByte = *data;
3069 matchByte = *(data - reps[0]);
3071 posState = (position & p.pbMask);
3074 The order of Price checks:
3075 < LIT
3076 <= SHORT_REP
3077 < LIT : REP_0
3078 < REP [ : LIT : REP_0 ]
3079 < MATCH [ : LIT : REP_0 ]
3083 uint curPrice = curOpt.price;
3084 uint prob = p.isMatch[state][posState];
3085 matchPrice = curPrice + mixin(GET_PRICE_1!"prob");
3086 litPrice = curPrice + mixin(GET_PRICE_0!"prob");
3089 nextOpt = &p.opt[cast(usize)cur + 1];
3090 nextIsLit = 0/*False*/;
3092 // here we can allow skip_items in p->opt, if we don't check (nextOpt->price < kInfinityPrice)
3093 // 18.new.06
3094 if ((nextOpt.price < kInfinityPrice
3095 // && !mixin(IsLitState!"state")
3096 && matchByte == curByte)
3097 || litPrice > nextOpt.price
3099 litPrice = 0;
3100 else
3102 const(CLzmaProb)* probs = mixin(LIT_PROBS!("position", "*(data - 1)"));
3103 litPrice += (!mixin(IsLitState!"state") ?
3104 LitEnc_Matched_GetPrice(probs, curByte, matchByte, p.ProbPrices.ptr) :
3105 LitEnc_GetPrice(probs, curByte, p.ProbPrices.ptr));
3107 if (litPrice < nextOpt.price)
3109 nextOpt.price = litPrice;
3110 nextOpt.len = 1;
3111 mixin(MakeAs_Lit!"nextOpt");
3112 nextIsLit = 1/*True*/;
3116 repMatchPrice = matchPrice + mixin(GET_PRICE_1!"p.isRep[state]");
3118 numAvailFull = p.numAvail;
3120 uint temp = kNumOpts - 1 - cur;
3121 if (numAvailFull > temp)
3122 numAvailFull = cast(uint)temp;
3125 // 18.06
3126 // ---------- SHORT_REP ----------
3127 if (mixin(IsLitState!"state")) // 18.new
3128 if (matchByte == curByte)
3129 if (repMatchPrice < nextOpt.price) // 18.new
3130 // if (numAvailFull < 2 || data[1] != *(data - reps[0] + 1))
3131 if (
3132 // nextOpt->price >= kInfinityPrice ||
3133 nextOpt.len < 2 // we can check nextOpt->len, if skip items are not allowed in p->opt
3134 || (nextOpt.dist != 0
3135 // && nextOpt->extra <= 1 // 17.old
3139 uint shortRepPrice = repMatchPrice + mixin(GetPrice_ShortRep!("p", "state", "posState"));
3140 // if (shortRepPrice <= nextOpt->price) // 17.old
3141 if (shortRepPrice < nextOpt.price) // 18.new
3143 nextOpt.price = shortRepPrice;
3144 nextOpt.len = 1;
3145 mixin(MakeAs_ShortRep!"nextOpt");
3146 nextIsLit = 0/*False*/;
3150 if (numAvailFull < 2)
3151 continue;
3152 numAvail = (numAvailFull <= p.numFastBytes ? numAvailFull : p.numFastBytes);
3154 // numAvail <= p->numFastBytes
3156 // ---------- LIT : REP_0 ----------
3158 if (!nextIsLit
3159 && litPrice != 0 // 18.new
3160 && matchByte != curByte
3161 && numAvailFull > 2)
3163 const ubyte *data2 = data - reps[0];
3164 if (data[1] == data2[1] && data[2] == data2[2])
3166 uint len;
3167 uint limit = p.numFastBytes + 1;
3168 if (limit > numAvailFull)
3169 limit = numAvailFull;
3170 for (len = 3; len < limit && data[len] == data2[len]; len++)
3174 uint state2 = kLiteralNextStates[state];
3175 uint posState2 = (position + 1) & p.pbMask;
3176 uint price = litPrice + mixin(GetPrice_Rep_0!("p", "state2", "posState2"));
3178 uint offset = cur + len;
3180 if (last < offset)
3181 last = offset;
3183 // do
3185 uint price2;
3186 COptimal *opt;
3187 len--;
3188 // price2 = price + GetPrice_Len_Rep_0(p, len, state2, posState2);
3189 price2 = price + mixin(GET_PRICE_LEN!("&p.repLenEnc", "posState2", "len"));
3191 opt = &p.opt[offset];
3192 // offset--;
3193 if (price2 < opt.price)
3195 opt.price = price2;
3196 opt.len = cast(uint)len;
3197 opt.dist = 0;
3198 opt.extra = 1;
3201 // while (len >= 3);
3207 startLen = 2; /* speed optimization */
3210 // ---------- REP ----------
3211 uint repIndex = 0; // 17.old
3212 // uint repIndex = mixin(IsLitState!"state") ? 0 : 1; // 18.notused
3213 for (; repIndex < LZMA_NUM_REPS; repIndex++)
3215 uint len;
3216 uint price;
3217 const ubyte *data2 = data - reps[repIndex];
3218 if (data[0] != data2[0] || data[1] != data2[1])
3219 continue;
3221 for (len = 2; len < numAvail && data[len] == data2[len]; len++)
3224 // if (len < startLen) continue; // 18.new: speed optimization
3227 uint offset = cur + len;
3228 if (last < offset)
3229 last = offset;
3232 uint len2 = len;
3233 price = repMatchPrice + GetPrice_PureRep(p, repIndex, state, posState);
3236 uint price2 = price + mixin(GET_PRICE_LEN!("&p.repLenEnc", "posState", "len2"));
3237 COptimal *opt = &p.opt[cur + len2];
3238 if (price2 < opt.price)
3240 opt.price = price2;
3241 opt.len = cast(uint)len2;
3242 opt.dist = cast(uint)repIndex;
3243 opt.extra = 0;
3246 while (--len2 >= 2);
3249 if (repIndex == 0) startLen = len + 1; // 17.old
3250 // startLen = len + 1; // 18.new
3252 /* if (_maxMode) */
3254 // ---------- REP : LIT : REP_0 ----------
3255 // numFastBytes + 1 + numFastBytes
3257 uint len2 = len + 1;
3258 uint limit = len2 + p.numFastBytes;
3259 if (limit > numAvailFull)
3260 limit = numAvailFull;
3262 len2 += 2;
3263 if (len2 <= limit)
3264 if (data[len2 - 2] == data2[len2 - 2])
3265 if (data[len2 - 1] == data2[len2 - 1])
3267 uint state2 = kRepNextStates[state];
3268 uint posState2 = (position + len) & p.pbMask;
3269 price += mixin(GET_PRICE_LEN!("&p.repLenEnc", "posState", "len"))
3270 + mixin(GET_PRICE_0!"p.isMatch[state2][posState2]")
3271 + LitEnc_Matched_GetPrice(mixin(LIT_PROBS!("position + len", "data[cast(usize)len - 1]")),
3272 data[len], data2[len], p.ProbPrices.ptr);
3274 // state2 = kLiteralNextStates[state2];
3275 state2 = kState_LitAfterRep;
3276 posState2 = (posState2 + 1) & p.pbMask;
3279 price += mixin(GetPrice_Rep_0!("p", "state2", "posState2"));
3281 for (; len2 < limit && data[len2] == data2[len2]; len2++)
3284 len2 -= len;
3285 // if (len2 >= 3)
3288 uint offset = cur + len + len2;
3290 if (last < offset)
3291 last = offset;
3292 // do
3294 uint price2;
3295 COptimal *opt;
3296 len2--;
3297 // price2 = price + GetPrice_Len_Rep_0(p, len2, state2, posState2);
3298 price2 = price + mixin(GET_PRICE_LEN!("&p.repLenEnc", "posState2", "len2"));
3300 opt = &p.opt[offset];
3301 // offset--;
3302 if (price2 < opt.price)
3304 opt.price = price2;
3305 opt.len = cast(uint)len2;
3306 opt.extra = cast(CExtra)(len + 1);
3307 opt.dist = cast(uint)repIndex;
3310 // while (len2 >= 3);
3319 // ---------- MATCH ----------
3320 /* for (uint len = 2; len <= newLen; len++) */
3321 if (newLen > numAvail)
3323 newLen = numAvail;
3324 for (numPairs = 0; newLen > p.matches[numPairs]; numPairs += 2) {}
3325 p.matches[numPairs] = cast(uint)newLen;
3326 numPairs += 2;
3329 // startLen = 2; /* speed optimization */
3331 if (newLen >= startLen)
3333 uint normalMatchPrice = matchPrice + mixin(GET_PRICE_0!"p.isRep[state]");
3334 uint dist;
3335 uint offs, posSlot, len;
3338 uint offset = cur + newLen;
3339 if (last < offset)
3340 last = offset;
3343 offs = 0;
3344 while (startLen > p.matches[offs])
3345 offs += 2;
3346 dist = p.matches[cast(usize)offs + 1];
3348 // if (dist >= kNumFullDistances)
3349 mixin(GetPosSlot2!("dist", "posSlot"));
3351 for (len = /*2*/ startLen; ; len++)
3353 uint price = normalMatchPrice + mixin(GET_PRICE_LEN!("&p.lenEnc", "posState", "len"));
3355 COptimal *opt;
3356 uint lenNorm = len - 2;
3357 lenNorm = mixin(GetLenToPosState2!"lenNorm");
3358 if (dist < kNumFullDistances)
3359 price += p.distancesPrices[lenNorm][dist & (kNumFullDistances - 1)];
3360 else
3361 price += p.posSlotPrices[lenNorm][posSlot] + p.alignPrices[dist & kAlignMask];
3363 opt = &p.opt[cur + len];
3364 if (price < opt.price)
3366 opt.price = price;
3367 opt.len = cast(uint)len;
3368 opt.dist = dist + LZMA_NUM_REPS;
3369 opt.extra = 0;
3373 if (len == p.matches[offs])
3375 // if (p->_maxMode) {
3376 // MATCH : LIT : REP_0
3378 const ubyte *data2 = data - dist - 1;
3379 uint len2 = len + 1;
3380 uint limit = len2 + p.numFastBytes;
3381 if (limit > numAvailFull)
3382 limit = numAvailFull;
3384 len2 += 2;
3385 if (len2 <= limit)
3386 if (data[len2 - 2] == data2[len2 - 2])
3387 if (data[len2 - 1] == data2[len2 - 1])
3389 for (; len2 < limit && data[len2] == data2[len2]; len2++)
3392 len2 -= len;
3394 // if (len2 >= 3)
3396 uint state2 = kMatchNextStates[state];
3397 uint posState2 = (position + len) & p.pbMask;
3398 uint offset;
3399 price += mixin(GET_PRICE_0!"p.isMatch[state2][posState2]");
3400 price += LitEnc_Matched_GetPrice(mixin(LIT_PROBS!("position + len", "data[cast(usize)len - 1]")),
3401 data[len], data2[len], p.ProbPrices.ptr);
3403 // state2 = kLiteralNextStates[state2];
3404 state2 = kState_LitAfterMatch;
3406 posState2 = (posState2 + 1) & p.pbMask;
3407 price += mixin(GetPrice_Rep_0!("p", "state2", "posState2"));
3409 offset = cur + len + len2;
3411 if (last < offset)
3412 last = offset;
3413 // do
3415 uint price2;
3416 COptimal *opt;
3417 len2--;
3418 // price2 = price + GetPrice_Len_Rep_0(p, len2, state2, posState2);
3419 price2 = price + mixin(GET_PRICE_LEN!("&p.repLenEnc", "posState2", "len2"));
3420 opt = &p.opt[offset];
3421 // offset--;
3422 if (price2 < opt.price)
3424 opt.price = price2;
3425 opt.len = cast(uint)len2;
3426 opt.extra = cast(CExtra)(len + 1);
3427 opt.dist = dist + LZMA_NUM_REPS;
3430 // while (len2 >= 3);
3435 offs += 2;
3436 if (offs == numPairs)
3437 break;
3438 dist = p.matches[cast(usize)offs + 1];
3439 // if (dist >= kNumFullDistances) {
3440 mixin(GetPosSlot2!("dist", "posSlot"));
3441 // }
3448 p.opt[last].price = kInfinityPrice;
3449 while (--last);
3451 return Backward(p, cur);
3456 enum ChangePair(string smallDist, string bigDist) = `(((`~bigDist~`) >> 7) > (`~smallDist~`))`;
3460 private uint GetOptimumFast(CLzmaEnc *p)
3462 uint numAvail, mainDist;
3463 uint mainLen, numPairs, repIndex, repLen, i;
3464 const(ubyte)* data;
3466 if (p.additionalOffset == 0)
3467 mainLen = ReadMatchDistances(p, &numPairs);
3468 else
3470 mainLen = p.longestMatchLen;
3471 numPairs = p.numPairs;
3474 numAvail = p.numAvail;
3475 p.backRes = MARK_LIT;
3476 if (numAvail < 2)
3477 return 1;
3478 // if (mainLen < 2 && p->state == 0) return 1; // 18.06.notused
3479 if (numAvail > LZMA_MATCH_LEN_MAX)
3480 numAvail = LZMA_MATCH_LEN_MAX;
3481 data = p.matchFinder.GetPointerToCurrentPos(p.matchFinderObj) - 1;
3482 repLen = repIndex = 0;
3484 for (i = 0; i < LZMA_NUM_REPS; i++)
3486 uint len;
3487 const ubyte *data2 = data - p.reps[i];
3488 if (data[0] != data2[0] || data[1] != data2[1])
3489 continue;
3490 for (len = 2; len < numAvail && data[len] == data2[len]; len++)
3492 if (len >= p.numFastBytes)
3494 p.backRes = cast(uint)i;
3495 mixin(MOVE_POS1!("p", "len - 1"));
3496 return len;
3498 if (len > repLen)
3500 repIndex = i;
3501 repLen = len;
3505 if (mainLen >= p.numFastBytes)
3507 p.backRes = p.matches[cast(usize)numPairs - 1] + LZMA_NUM_REPS;
3508 mixin(MOVE_POS1!("p", "mainLen - 1"));
3509 return mainLen;
3512 mainDist = 0; /* for GCC */
3514 if (mainLen >= 2)
3516 mainDist = p.matches[cast(usize)numPairs - 1];
3517 while (numPairs > 2)
3519 uint dist2;
3520 if (mainLen != p.matches[cast(usize)numPairs - 4] + 1)
3521 break;
3522 dist2 = p.matches[cast(usize)numPairs - 3];
3523 if (!mixin(ChangePair!("dist2", "mainDist")))
3524 break;
3525 numPairs -= 2;
3526 mainLen--;
3527 mainDist = dist2;
3529 if (mainLen == 2 && mainDist >= 0x80)
3530 mainLen = 1;
3533 if (repLen >= 2)
3534 if ( repLen + 1 >= mainLen
3535 || (repLen + 2 >= mainLen && mainDist >= (1 << 9))
3536 || (repLen + 3 >= mainLen && mainDist >= (1 << 15)))
3538 p.backRes = cast(uint)repIndex;
3539 mixin(MOVE_POS1!("p", "repLen - 1"));
3540 return repLen;
3543 if (mainLen < 2 || numAvail <= 2)
3544 return 1;
3547 uint len1 = ReadMatchDistances(p, &p.numPairs);
3548 p.longestMatchLen = len1;
3550 if (len1 >= 2)
3552 uint newDist = p.matches[cast(usize)p.numPairs - 1];
3553 if ( (len1 >= mainLen && newDist < mainDist)
3554 || (len1 == mainLen + 1 && !mixin(ChangePair!("mainDist", "newDist")))
3555 || (len1 > mainLen + 1)
3556 || (len1 + 1 >= mainLen && mainLen >= 3 && mixin(ChangePair!("newDist", "mainDist"))))
3557 return 1;
3561 data = p.matchFinder.GetPointerToCurrentPos(p.matchFinderObj) - 1;
3563 for (i = 0; i < LZMA_NUM_REPS; i++)
3565 uint len, limit;
3566 const ubyte *data2 = data - p.reps[i];
3567 if (data[0] != data2[0] || data[1] != data2[1])
3568 continue;
3569 limit = mainLen - 1;
3570 for (len = 2;; len++)
3572 if (len >= limit)
3573 return 1;
3574 if (data[len] != data2[len])
3575 break;
3579 p.backRes = mainDist + LZMA_NUM_REPS;
3580 if (mainLen != 2)
3582 mixin(MOVE_POS1!("p", "mainLen - 2"));
3584 return mainLen;
3590 private void WriteEndMarker(CLzmaEnc *p, uint posState)
3592 uint range;
3593 range = p.rc.range;
3595 uint ttt, newBound;
3596 CLzmaProb *prob = &p.isMatch[p.state][posState];
3597 mixin(RC_BIT_PRE!("&p.rc", "prob"));
3598 mixin(RC_BIT_1!("&p.rc", "prob"));
3599 prob = &p.isRep[p.state];
3600 mixin(RC_BIT_PRE!("&p.rc", "prob"));
3601 mixin(RC_BIT_0!("&p.rc", "prob"));
3603 p.state = kMatchNextStates[p.state];
3605 p.rc.range = range;
3606 LenEnc_Encode(&p.lenProbs, &p.rc, 0, posState);
3607 range = p.rc.range;
3610 // RcTree_Encode_PosSlot(&p->rc, p->posSlotEncoder[0], (1 << kNumPosSlotBits) - 1);
3611 CLzmaProb *probs = p.posSlotEncoder[0].ptr;
3612 uint m = 1;
3615 uint ttt, newBound;
3616 mixin(RC_BIT_PRE!("p", "probs + m"));
3617 mixin(RC_BIT_1!("&p.rc", "probs + m"));
3618 m = (m << 1) + 1;
3620 while (m < (1 << kNumPosSlotBits));
3623 // RangeEnc_EncodeDirectBits(&p->rc, ((uint)1 << (30 - kNumAlignBits)) - 1, 30 - kNumAlignBits); uint range = p->range;
3624 uint numBits = 30 - kNumAlignBits;
3627 range >>= 1;
3628 p.rc.low += range;
3629 mixin(RC_NORM!"&p.rc");
3631 while (--numBits);
3635 // RcTree_ReverseEncode(&p->rc, p->posAlignEncoder, kNumAlignBits, kAlignMask);
3636 CLzmaProb *probs = p.posAlignEncoder.ptr;
3637 uint m = 1;
3640 uint ttt, newBound;
3641 mixin(RC_BIT_PRE!("p", "probs + m"));
3642 mixin(RC_BIT_1!("&p.rc", "probs + m"));
3643 m = (m << 1) + 1;
3645 while (m < kAlignTableSize);
3647 p.rc.range = range;
3651 private SRes CheckErrors(CLzmaEnc *p)
3653 if (p.result != SZ_OK)
3654 return p.result;
3655 if (p.rc.res != SZ_OK)
3656 p.result = SZ_ERROR_WRITE;
3658 if ((p.matchFinderBase).result != SZ_OK)
3659 p.result = SZ_ERROR_READ;
3661 if (p.result != SZ_OK)
3662 p.finished = 1/*True*/;
3663 return p.result;
3667 //MY_NO_INLINE
3668 private SRes Flush(CLzmaEnc *p, uint nowPos)
3670 /* ReleaseMFStream(); */
3671 p.finished = 1/*True*/;
3672 if (p.writeEndMark)
3673 WriteEndMarker(p, nowPos & p.pbMask);
3674 RangeEnc_FlushData(&p.rc);
3675 RangeEnc_FlushStream(&p.rc);
3676 return CheckErrors(p);
3680 //MY_NO_INLINE
3681 private void FillAlignPrices(CLzmaEnc *p)
3683 uint i;
3684 const CProbPrice *ProbPrices = p.ProbPrices.ptr;
3685 const CLzmaProb *probs = p.posAlignEncoder.ptr;
3686 // p->alignPriceCount = 0;
3687 for (i = 0; i < kAlignTableSize / 2; i++)
3689 uint price = 0;
3690 uint sym = i;
3691 uint m = 1;
3692 uint bit;
3693 uint prob;
3694 bit = sym & 1; sym >>= 1; price += mixin(GET_PRICEa!("probs[m]", "bit")); m = (m << 1) + bit;
3695 bit = sym & 1; sym >>= 1; price += mixin(GET_PRICEa!("probs[m]", "bit")); m = (m << 1) + bit;
3696 bit = sym & 1; sym >>= 1; price += mixin(GET_PRICEa!("probs[m]", "bit")); m = (m << 1) + bit;
3697 prob = probs[m];
3698 p.alignPrices[i ] = price + mixin(GET_PRICEa_0!"prob");
3699 p.alignPrices[i + 8] = price + mixin(GET_PRICEa_1!"prob");
3700 // p->alignPrices[i] = RcTree_ReverseGetPrice(p->posAlignEncoder, kNumAlignBits, i, p->ProbPrices);
3705 //MY_NO_INLINE
3706 private void FillDistancesPrices(CLzmaEnc *p)
3708 // int y; for (y = 0; y < 100; y++) {
3710 uint[kNumFullDistances] tempPrices;
3711 uint i, lps;
3713 const CProbPrice *ProbPrices = p.ProbPrices.ptr;
3714 p.matchPriceCount = 0;
3716 for (i = kStartPosModelIndex / 2; i < kNumFullDistances / 2; i++)
3718 uint posSlot = mixin(GetPosSlot1!"i");
3719 uint footerBits = (posSlot >> 1) - 1;
3720 uint base = ((2 | (posSlot & 1)) << footerBits);
3721 const(CLzmaProb)* probs = p.posEncoders.ptr + cast(usize)base * 2;
3722 // tempPrices[i] = RcTree_ReverseGetPrice(p->posEncoders + base, footerBits, i - base, p->ProbPrices);
3723 uint price = 0;
3724 uint m = 1;
3725 uint sym = i;
3726 uint offset = cast(uint)1 << footerBits;
3727 base += i;
3729 if (footerBits)
3732 uint bit = sym & 1;
3733 sym >>= 1;
3734 price += mixin(GET_PRICEa!("probs[m]", "bit"));
3735 m = (m << 1) + bit;
3737 while (--footerBits);
3740 uint prob = probs[m];
3741 tempPrices[base ] = price + mixin(GET_PRICEa_0!"prob");
3742 tempPrices[base + offset] = price + mixin(GET_PRICEa_1!"prob");
3746 for (lps = 0; lps < kNumLenToPosStates; lps++)
3748 uint slot;
3749 uint distTableSize2 = (p.distTableSize + 1) >> 1;
3750 uint *posSlotPrices = p.posSlotPrices[lps].ptr;
3751 const CLzmaProb *probs = p.posSlotEncoder[lps].ptr;
3753 for (slot = 0; slot < distTableSize2; slot++)
3755 // posSlotPrices[slot] = RcTree_GetPrice(encoder, kNumPosSlotBits, slot, p->ProbPrices);
3756 uint price;
3757 uint bit;
3758 uint sym = slot + (1 << (kNumPosSlotBits - 1));
3759 uint prob;
3760 bit = sym & 1; sym >>= 1; price = mixin(GET_PRICEa!("probs[sym]", "bit"));
3761 bit = sym & 1; sym >>= 1; price += mixin(GET_PRICEa!("probs[sym]", "bit"));
3762 bit = sym & 1; sym >>= 1; price += mixin(GET_PRICEa!("probs[sym]", "bit"));
3763 bit = sym & 1; sym >>= 1; price += mixin(GET_PRICEa!("probs[sym]", "bit"));
3764 bit = sym & 1; sym >>= 1; price += mixin(GET_PRICEa!("probs[sym]", "bit"));
3765 prob = probs[cast(usize)slot + (1 << (kNumPosSlotBits - 1))];
3766 posSlotPrices[cast(usize)slot * 2 ] = price + mixin(GET_PRICEa_0!"prob");
3767 posSlotPrices[cast(usize)slot * 2 + 1] = price + mixin(GET_PRICEa_1!"prob");
3771 uint delta = (cast(uint)((kEndPosModelIndex / 2 - 1) - kNumAlignBits) << kNumBitPriceShiftBits);
3772 for (slot = kEndPosModelIndex / 2; slot < distTableSize2; slot++)
3774 posSlotPrices[cast(usize)slot * 2 ] += delta;
3775 posSlotPrices[cast(usize)slot * 2 + 1] += delta;
3776 delta += (cast(uint)1 << kNumBitPriceShiftBits);
3781 uint *dp = p.distancesPrices[lps].ptr;
3783 dp[0] = posSlotPrices[0];
3784 dp[1] = posSlotPrices[1];
3785 dp[2] = posSlotPrices[2];
3786 dp[3] = posSlotPrices[3];
3788 for (i = 4; i < kNumFullDistances; i += 2)
3790 uint slotPrice = posSlotPrices[mixin(GetPosSlot1!"i")];
3791 dp[i ] = slotPrice + tempPrices[i];
3792 dp[i + 1] = slotPrice + tempPrices[i + 1];
3796 // }
3801 private void LzmaEnc_Construct(CLzmaEnc *p)
3803 RangeEnc_Construct(&p.rc);
3804 MatchFinder_Construct(&(p.matchFinderBase));
3807 CLzmaEncProps props;
3808 LzmaEncProps_Init(&props);
3809 LzmaEnc_SetProps(p, &props);
3812 //#ifndef LZMA_LOG_BSR
3813 LzmaEnc_FastPosInit(p.g_FastPos.ptr);
3814 //#endif
3816 LzmaEnc_InitPriceTables(p.ProbPrices.ptr);
3817 p.litProbs = null;
3818 p.saveState.litProbs = null;
3822 //==========================================================================
3824 // LzmaEnc_Create
3826 //==========================================================================
3827 public CLzmaEncHandle LzmaEnc_Create (ISzAllocPtr alloc) {
3828 void *p = ISzAlloc_Alloc(alloc, CLzmaEnc.sizeof);
3829 if (p) LzmaEnc_Construct(cast(CLzmaEnc *)p);
3830 return p;
3834 private void LzmaEnc_FreeLits(CLzmaEnc *p, ISzAllocPtr alloc)
3836 ISzAlloc_Free(alloc, p.litProbs);
3837 ISzAlloc_Free(alloc, p.saveState.litProbs);
3838 p.litProbs = null;
3839 p.saveState.litProbs = null;
3842 private void LzmaEnc_Destruct(CLzmaEnc *p, ISzAllocPtr alloc, ISzAllocPtr allocBig)
3844 MatchFinder_Free(&(p.matchFinderBase), allocBig);
3845 LzmaEnc_FreeLits(p, alloc);
3846 RangeEnc_Free(&p.rc, alloc);
3850 //==========================================================================
3852 // LzmaEnc_Destroy
3854 //==========================================================================
3855 public void LzmaEnc_Destroy (CLzmaEncHandle p, ISzAllocPtr alloc, ISzAllocPtr allocBig) {
3856 if (p !is null) {
3857 LzmaEnc_Destruct(cast(CLzmaEnc *)p, alloc, allocBig);
3858 ISzAlloc_Free(alloc, p);
3863 //MY_NO_INLINE
3864 private SRes LzmaEnc_CodeOneBlock(CLzmaEnc *p, uint maxPackSize, uint maxUnpackSize)
3866 uint nowPos32, startPos32;
3867 if (p.needInit)
3869 p.matchFinder.Init(p.matchFinderObj);
3870 p.needInit = 0;
3873 if (p.finished)
3874 return p.result;
3875 int rinres = CheckErrors(p);
3876 if (rinres != 0) return rinres;
3878 nowPos32 = cast(uint)p.nowPos64;
3879 startPos32 = nowPos32;
3881 if (p.nowPos64 == 0)
3883 uint numPairs;
3884 ubyte curByte;
3885 if (p.matchFinder.GetNumAvailableBytes(p.matchFinderObj) == 0)
3886 return Flush(p, nowPos32);
3887 ReadMatchDistances(p, &numPairs);
3888 RangeEnc_EncodeBit_0(&p.rc, &p.isMatch[kState_Start][0]);
3889 // p->state = kLiteralNextStates[p->state];
3890 curByte = *(p.matchFinder.GetPointerToCurrentPos(p.matchFinderObj) - p.additionalOffset);
3891 LitEnc_Encode(&p.rc, p.litProbs, curByte);
3892 p.additionalOffset--;
3893 nowPos32++;
3896 if (p.matchFinder.GetNumAvailableBytes(p.matchFinderObj) != 0)
3898 for (;;)
3900 uint dist;
3901 uint len, posState;
3902 uint range, ttt, newBound;
3903 CLzmaProb *probs;
3905 if (p.fastMode)
3906 len = GetOptimumFast(p);
3907 else
3909 uint oci = p.optCur;
3910 if (p.optEnd == oci)
3911 len = GetOptimum(p, nowPos32);
3912 else
3914 const COptimal *opt = &p.opt[oci];
3915 len = opt.len;
3916 p.backRes = opt.dist;
3917 p.optCur = oci + 1;
3921 posState = cast(uint)nowPos32 & p.pbMask;
3922 range = p.rc.range;
3923 probs = &p.isMatch[p.state][posState];
3925 mixin(RC_BIT_PRE!("&p.rc", "probs"));
3927 dist = p.backRes;
3930 #ifdef SHOW_STAT2
3931 printf("\n pos = %6X, len = %3u pos = %6u", nowPos32, len, dist);
3932 #endif
3935 if (dist == MARK_LIT)
3937 ubyte curByte;
3938 const(ubyte)* data;
3939 uint state;
3941 mixin(RC_BIT_0!("&p.rc", "probs"));
3942 p.rc.range = range;
3943 data = p.matchFinder.GetPointerToCurrentPos(p.matchFinderObj) - p.additionalOffset;
3944 probs = mixin(LIT_PROBS!("nowPos32", "*(data - 1)"));
3945 curByte = *data;
3946 state = p.state;
3947 p.state = kLiteralNextStates[state];
3948 if (mixin(IsLitState!"state"))
3949 LitEnc_Encode(&p.rc, probs, curByte);
3950 else
3951 LitEnc_EncodeMatched(&p.rc, probs, curByte, *(data - p.reps[0]));
3953 else
3955 mixin(RC_BIT_1!("&p.rc", "probs"));
3956 probs = &p.isRep[p.state];
3957 mixin(RC_BIT_PRE!("&p.rc", "probs"));
3959 if (dist < LZMA_NUM_REPS)
3961 mixin(RC_BIT_1!("&p.rc", "probs"));
3962 probs = &p.isRepG0[p.state];
3963 mixin(RC_BIT_PRE!("&p.rc", "probs"));
3964 if (dist == 0)
3966 mixin(RC_BIT_0!("&p.rc", "probs"));
3967 probs = &p.isRep0Long[p.state][posState];
3968 mixin(RC_BIT_PRE!("&p.rc", "probs"));
3969 if (len != 1)
3971 mixin(RC_BIT_1_BASE!("&p.rc", "probs"));
3973 else
3975 mixin(RC_BIT_0_BASE!("&p.rc", "probs"));
3976 p.state = kShortRepNextStates[p.state];
3979 else
3981 mixin(RC_BIT_1!("&p.rc", "probs"));
3982 probs = &p.isRepG1[p.state];
3983 mixin(RC_BIT_PRE!("&p.rc", "probs"));
3984 if (dist == 1)
3986 mixin(RC_BIT_0_BASE!("&p.rc", "probs"));
3987 dist = p.reps[1];
3989 else
3991 mixin(RC_BIT_1!("&p.rc", "probs"));
3992 probs = &p.isRepG2[p.state];
3993 mixin(RC_BIT_PRE!("&p.rc", "probs"));
3994 if (dist == 2)
3996 mixin(RC_BIT_0_BASE!("&p.rc", "probs"));
3997 dist = p.reps[2];
3999 else
4001 mixin(RC_BIT_1_BASE!("&p.rc", "probs"));
4002 dist = p.reps[3];
4003 p.reps[3] = p.reps[2];
4005 p.reps[2] = p.reps[1];
4007 p.reps[1] = p.reps[0];
4008 p.reps[0] = dist;
4011 mixin(RC_NORM!"&p.rc");
4013 p.rc.range = range;
4015 if (len != 1)
4017 LenEnc_Encode(&p.repLenProbs, &p.rc, len - LZMA_MATCH_LEN_MIN, posState);
4018 --p.repLenEncCounter;
4019 p.state = kRepNextStates[p.state];
4022 else
4024 uint posSlot;
4025 mixin(RC_BIT_0!("&p.rc", "probs"));
4026 p.rc.range = range;
4027 p.state = kMatchNextStates[p.state];
4029 LenEnc_Encode(&p.lenProbs, &p.rc, len - LZMA_MATCH_LEN_MIN, posState);
4030 // --p->lenEnc.counter;
4032 dist -= LZMA_NUM_REPS;
4033 p.reps[3] = p.reps[2];
4034 p.reps[2] = p.reps[1];
4035 p.reps[1] = p.reps[0];
4036 p.reps[0] = dist + 1;
4038 p.matchPriceCount++;
4039 mixin(GetPosSlot!("dist", "posSlot"));
4040 // RcTree_Encode_PosSlot(&p->rc, p->posSlotEncoder[mixin(GetLenToPosState!"len")], posSlot);
4042 uint sym = cast(uint)posSlot + (1 << kNumPosSlotBits);
4043 range = p.rc.range;
4044 probs = p.posSlotEncoder[mixin(GetLenToPosState!"len")].ptr;
4047 CLzmaProb *prob = probs + (sym >> kNumPosSlotBits);
4048 uint bit = (sym >> (kNumPosSlotBits - 1)) & 1;
4049 sym <<= 1;
4050 mixin(RC_BIT!("&p.rc", "prob", "bit"));
4052 while (sym < (1 << kNumPosSlotBits * 2));
4053 p.rc.range = range;
4056 if (dist >= kStartPosModelIndex)
4058 uint footerBits = ((posSlot >> 1) - 1);
4060 if (dist < kNumFullDistances)
4062 uint base = ((2 | (posSlot & 1)) << footerBits);
4063 RcTree_ReverseEncode(&p.rc, p.posEncoders.ptr + base, footerBits, cast(uint)(dist /* - base */));
4065 else
4067 uint pos2 = (dist | 0xF) << (32 - footerBits);
4068 range = p.rc.range;
4069 // RangeEnc_EncodeDirectBits(&p->rc, posReduced >> kNumAlignBits, footerBits - kNumAlignBits);
4073 range >>= 1;
4074 p->rc.low += range & (0 - ((dist >> --footerBits) & 1));
4075 RC_NORM(&p->rc)
4077 while (footerBits > kNumAlignBits);
4081 range >>= 1;
4082 p.rc.low += range & (0 - (pos2 >> 31));
4083 pos2 += pos2;
4084 mixin(RC_NORM!"&p.rc");
4086 while (pos2 != 0xF0000000);
4089 // RcTree_ReverseEncode(&p->rc, p->posAlignEncoder, kNumAlignBits, posReduced & kAlignMask);
4092 uint m = 1;
4093 uint bit;
4094 bit = dist & 1; dist >>= 1; mixin(RC_BIT!("&p.rc", "p.posAlignEncoder.ptr + m", "bit")); m = (m << 1) + bit;
4095 bit = dist & 1; dist >>= 1; mixin(RC_BIT!("&p.rc", "p.posAlignEncoder.ptr + m", "bit")); m = (m << 1) + bit;
4096 bit = dist & 1; dist >>= 1; mixin(RC_BIT!("&p.rc", "p.posAlignEncoder.ptr + m", "bit")); m = (m << 1) + bit;
4097 bit = dist & 1; mixin(RC_BIT!("&p.rc", "p.posAlignEncoder.ptr + m", "bit"));
4098 p.rc.range = range;
4099 // p->alignPriceCount++;
4106 nowPos32 += cast(uint)len;
4107 p.additionalOffset -= len;
4109 if (p.additionalOffset == 0)
4111 uint processed;
4113 if (!p.fastMode)
4116 if (p->alignPriceCount >= 16) // kAlignTableSize
4117 FillAlignPrices(p);
4118 if (p->matchPriceCount >= 128)
4119 FillDistancesPrices(p);
4120 if (p->lenEnc.counter <= 0)
4121 LenPriceEnc_UpdateTables(&p->lenEnc, 1 << p->pb, &p->lenProbs, p->ProbPrices);
4123 if (p.matchPriceCount >= 64)
4125 FillAlignPrices(p);
4126 // { int y; for (y = 0; y < 100; y++) {
4127 FillDistancesPrices(p);
4128 // }}
4129 LenPriceEnc_UpdateTables(&p.lenEnc, cast(uint)1 << p.pb, &p.lenProbs, p.ProbPrices.ptr);
4131 if (p.repLenEncCounter <= 0)
4133 p.repLenEncCounter = REP_LEN_COUNT;
4134 LenPriceEnc_UpdateTables(&p.repLenEnc, cast(uint)1 << p.pb, &p.repLenProbs, p.ProbPrices.ptr);
4138 if (p.matchFinder.GetNumAvailableBytes(p.matchFinderObj) == 0)
4139 break;
4140 processed = nowPos32 - startPos32;
4142 if (maxPackSize)
4144 if (processed + kNumOpts + 300 >= maxUnpackSize
4145 || mixin(RangeEnc_GetProcessed_sizet!"&p.rc") + kPackReserve >= maxPackSize)
4146 break;
4148 else if (processed >= (1 << 17))
4150 p.nowPos64 += nowPos32 - startPos32;
4151 return CheckErrors(p);
4156 p.nowPos64 += nowPos32 - startPos32;
4157 return Flush(p, nowPos32);
4162 enum kBigHashDicLimit = (cast(uint)1 << 24);
4164 private SRes LzmaEnc_Alloc(CLzmaEnc *p, uint keepWindowSize, ISzAllocPtr alloc, ISzAllocPtr allocBig)
4166 uint beforeSize = kNumOpts;
4167 uint dictSize;
4169 if (!RangeEnc_Alloc(&p.rc, alloc))
4170 return SZ_ERROR_MEM;
4173 uint lclp = p.lc + p.lp;
4174 if (!p.litProbs || !p.saveState.litProbs || p.lclp != lclp)
4176 LzmaEnc_FreeLits(p, alloc);
4177 p.litProbs = cast(CLzmaProb *)ISzAlloc_Alloc(alloc, (cast(uint)0x300 << lclp) * CLzmaProb.sizeof);
4178 p.saveState.litProbs = cast(CLzmaProb *)ISzAlloc_Alloc(alloc, (cast(uint)0x300 << lclp) * CLzmaProb.sizeof);
4179 if (!p.litProbs || !p.saveState.litProbs)
4181 LzmaEnc_FreeLits(p, alloc);
4182 return SZ_ERROR_MEM;
4184 p.lclp = lclp;
4188 (p.matchFinderBase).bigHash = cast(ubyte)(p.dictSize > kBigHashDicLimit ? 1 : 0);
4191 dictSize = p.dictSize;
4192 if (dictSize == (cast(uint)2 << 30) ||
4193 dictSize == (cast(uint)3 << 30))
4195 /* 21.03 : here we reduce the dictionary for 2 reasons:
4196 1) we don't want 32-bit back_distance matches in decoder for 2 GB dictionary.
4197 2) we want to elimate useless last MatchFinder_Normalize3() for corner cases,
4198 where data size is aligned for 1 GB: 5/6/8 GB.
4199 That reducing must be >= 1 for such corner cases. */
4200 dictSize -= 1;
4203 if (beforeSize + dictSize < keepWindowSize)
4204 beforeSize = keepWindowSize - dictSize;
4206 /* in worst case we can look ahead for
4207 max(LZMA_MATCH_LEN_MAX, numFastBytes + 1 + numFastBytes) bytes.
4208 we send larger value for (keepAfter) to MantchFinder_Create():
4209 (numFastBytes + LZMA_MATCH_LEN_MAX + 1)
4212 if (!MatchFinder_Create(&(p.matchFinderBase), dictSize, beforeSize,
4213 p.numFastBytes, LZMA_MATCH_LEN_MAX + 1 /* 21.03 */
4214 , allocBig))
4215 return SZ_ERROR_MEM;
4216 p.matchFinderObj = &(p.matchFinderBase);
4217 MatchFinder_CreateVTable(&(p.matchFinderBase), &p.matchFinder);
4219 return SZ_OK;
4222 private void LzmaEnc_Init(CLzmaEnc *p)
4224 uint i;
4225 p.state = 0;
4226 p.reps[0] =
4227 p.reps[1] =
4228 p.reps[2] =
4229 p.reps[3] = 1;
4231 RangeEnc_Init(&p.rc);
4233 for (i = 0; i < (1 << kNumAlignBits); i++)
4234 p.posAlignEncoder[i] = kProbInitValue;
4236 for (i = 0; i < kNumStates; i++)
4238 uint j;
4239 for (j = 0; j < LZMA_NUM_PB_STATES_MAX; j++)
4241 p.isMatch[i][j] = kProbInitValue;
4242 p.isRep0Long[i][j] = kProbInitValue;
4244 p.isRep[i] = kProbInitValue;
4245 p.isRepG0[i] = kProbInitValue;
4246 p.isRepG1[i] = kProbInitValue;
4247 p.isRepG2[i] = kProbInitValue;
4251 for (i = 0; i < kNumLenToPosStates; i++)
4253 CLzmaProb *probs = p.posSlotEncoder[i].ptr;
4254 uint j;
4255 for (j = 0; j < (1 << kNumPosSlotBits); j++)
4256 probs[j] = kProbInitValue;
4260 for (i = 0; i < kNumFullDistances; i++)
4261 p.posEncoders[i] = kProbInitValue;
4265 uint num = cast(uint)0x300 << (p.lp + p.lc);
4266 uint k;
4267 CLzmaProb *probs = p.litProbs;
4268 for (k = 0; k < num; k++)
4269 probs[k] = kProbInitValue;
4273 LenEnc_Init(&p.lenProbs);
4274 LenEnc_Init(&p.repLenProbs);
4276 p.optEnd = 0;
4277 p.optCur = 0;
4280 for (i = 0; i < kNumOpts; i++)
4281 p.opt[i].price = kInfinityPrice;
4284 p.additionalOffset = 0;
4286 p.pbMask = (cast(uint)1 << p.pb) - 1;
4287 p.lpMask = (cast(uint)0x100 << p.lp) - (cast(uint)0x100 >> p.lc);
4289 // p->mf_Failure = False;
4293 private void LzmaEnc_InitPrices(CLzmaEnc *p)
4295 if (!p.fastMode)
4297 FillDistancesPrices(p);
4298 FillAlignPrices(p);
4301 p.lenEnc.tableSize =
4302 p.repLenEnc.tableSize =
4303 p.numFastBytes + 1 - LZMA_MATCH_LEN_MIN;
4305 p.repLenEncCounter = REP_LEN_COUNT;
4307 LenPriceEnc_UpdateTables(&p.lenEnc, cast(uint)1 << p.pb, &p.lenProbs, p.ProbPrices.ptr);
4308 LenPriceEnc_UpdateTables(&p.repLenEnc, cast(uint)1 << p.pb, &p.repLenProbs, p.ProbPrices.ptr);
4311 private SRes LzmaEnc_AllocAndInit(CLzmaEnc *p, uint keepWindowSize, ISzAllocPtr alloc, ISzAllocPtr allocBig)
4313 uint i;
4314 for (i = kEndPosModelIndex / 2; i < kDicLogSizeMax; i++)
4315 if (p.dictSize <= (cast(uint)1 << i))
4316 break;
4317 p.distTableSize = i * 2;
4319 p.finished = 0/*False*/;
4320 p.result = SZ_OK;
4321 int rinres = LzmaEnc_Alloc(p, keepWindowSize, alloc, allocBig);
4322 if (rinres != 0) return rinres;
4323 LzmaEnc_Init(p);
4324 LzmaEnc_InitPrices(p);
4325 p.nowPos64 = 0;
4326 return SZ_OK;
4329 private SRes LzmaEnc_Prepare(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream,
4330 ISzAllocPtr alloc, ISzAllocPtr allocBig)
4332 CLzmaEnc *p = cast(CLzmaEnc *)pp;
4333 (p.matchFinderBase).stream = inStream;
4334 p.needInit = 1;
4335 p.rc.outStream = outStream;
4336 return LzmaEnc_AllocAndInit(p, 0, alloc, allocBig);
4339 private void LzmaEnc_SetInputBuf(CLzmaEnc *p, const ubyte *src, usize srcLen)
4341 (p.matchFinderBase).directInput = 1;
4342 (p.matchFinderBase).bufferBase = cast(ubyte *)src;
4343 (p.matchFinderBase).directInputRem = srcLen;
4346 private SRes LzmaEnc_MemPrepare(CLzmaEncHandle pp, const ubyte *src, usize srcLen,
4347 uint keepWindowSize, ISzAllocPtr alloc, ISzAllocPtr allocBig)
4349 CLzmaEnc *p = cast(CLzmaEnc *)pp;
4350 LzmaEnc_SetInputBuf(p, src, srcLen);
4351 p.needInit = 1;
4353 LzmaEnc_SetDataSize(pp, srcLen);
4354 return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig);
4357 private void LzmaEnc_Finish(CLzmaEncHandle pp)
4359 //(void)pp;
4363 struct CLzmaEnc_SeqOutStreamBuf {
4364 ISeqOutStream vt;
4365 ubyte *data;
4366 usize rem;
4367 BoolInt overflow;
4372 #define MY_offsetof(type, m) ((size_t)&(((type *)0)->m))
4373 #define MY_container_of(ptr, type, m) ((type *)(void *)((char *)(void *)(1 ? (ptr) : &((type *)0)->m) - MY_offsetof(type, m)))
4374 #define CONTAINER_FROM_VTBL(ptr, type, m) MY_container_of(ptr, type, m)
4377 private usize SeqOutStreamBuf_Write(ISeqOutStream* pp, const(void)* data, usize size) nothrow
4379 //CLzmaEnc_SeqOutStreamBuf *p = CONTAINER_FROM_VTBL(pp, CLzmaEnc_SeqOutStreamBuf, vt);
4380 CLzmaEnc_SeqOutStreamBuf* p = cast(CLzmaEnc_SeqOutStreamBuf*)(cast(ubyte*)pp-CLzmaEnc_SeqOutStreamBuf.vt.offsetof);
4381 if (p.rem < size)
4383 size = p.rem;
4384 p.overflow = 1/*True*/;
4386 import core.stdc.string : memcpy;
4387 memcpy(p.data, data, size);
4388 p.rem -= size;
4389 p.data += size;
4390 return size;
4394 //MY_NO_INLINE
4395 private SRes LzmaEnc_Encode2(CLzmaEnc *p, ICompressProgress *progress)
4397 SRes res = SZ_OK;
4399 for (;;)
4401 res = LzmaEnc_CodeOneBlock(p, 0, 0);
4402 if (res != SZ_OK || p.finished)
4403 break;
4404 if (progress)
4406 //res = ICompressProgress_Progress(progress, p.nowPos64, mixin(RangeEnc_GetProcessed!"&p.rc"));
4407 res = progress.Progress(progress, p.nowPos64, mixin(RangeEnc_GetProcessed!"&p.rc"));
4408 if (res != SZ_OK)
4410 res = SZ_ERROR_PROGRESS;
4411 break;
4416 LzmaEnc_Finish(p);
4419 if (res == SZ_OK && !Inline_MatchFinder_IsFinishedOK(&(p.matchFinderBase)))
4420 res = SZ_ERROR_FAIL;
4424 return res;
4428 //==========================================================================
4430 // LzmaEnc_Encode
4432 //==========================================================================
4433 public SRes LzmaEnc_Encode (CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream,
4434 ICompressProgress *progress, ISzAllocPtr alloc, ISzAllocPtr allocBig)
4436 int rinres = LzmaEnc_Prepare(pp, outStream, inStream, alloc, allocBig);
4437 if (rinres != 0) return rinres;
4438 return LzmaEnc_Encode2(cast(CLzmaEnc *)pp, progress);
4442 //==========================================================================
4444 // LzmaEnc_WriteProperties
4446 //==========================================================================
4447 public SRes LzmaEnc_WriteProperties (CLzmaEncHandle pp, ubyte* props, uint* size) @nogc {
4448 if (*size < LZMA_PROPS_SIZE) return SZ_ERROR_PARAM;
4449 *size = LZMA_PROPS_SIZE;
4451 const(CLzmaEnc)* p = cast(const(CLzmaEnc)*)pp;
4452 immutable uint dictSize = p.dictSize;
4453 uint v;
4454 props[0] = cast(ubyte)((p.pb * 5 + p.lp) * 9 + p.lc);
4456 // we write aligned dictionary value to properties for lzma decoder
4457 if (dictSize >= (cast(uint)1 << 21)) {
4458 const uint kDictMask = (cast(uint)1 << 20) - 1;
4459 v = (dictSize + kDictMask) & ~kDictMask;
4460 if (v < dictSize) v = dictSize;
4461 } else {
4462 uint i = 11 * 2;
4463 do {
4464 v = cast(uint)(2 + (i & 1)) << (i >> 1);
4465 i++;
4466 } while (v < dictSize);
4469 SetUi32(props + 1, v);
4470 return SZ_OK;
4474 //==========================================================================
4476 // LzmaEnc_IsWriteEndMark
4478 //==========================================================================
4479 public uint LzmaEnc_IsWriteEndMark (CLzmaEncHandle pp) @nogc {
4480 return cast(uint)(cast(CLzmaEnc *)pp).writeEndMark;
4484 //==========================================================================
4486 // LzmaEnc_MemEncode
4488 //==========================================================================
4489 public SRes LzmaEnc_MemEncode (CLzmaEncHandle pp, ubyte* dest, usize* destLen, const(ubyte)* src, usize srcLen,
4490 int writeEndMark, ICompressProgress *progress, ISzAllocPtr alloc, ISzAllocPtr allocBig)
4492 SRes res;
4493 CLzmaEnc *p = cast(CLzmaEnc *)pp;
4495 CLzmaEnc_SeqOutStreamBuf outStream;
4497 //outStream.vt.Write = &SeqOutStreamBuf_Write;
4498 outStream.vt.Write = delegate usize (ISeqOutStream* pp, const(void)* data, usize size) nothrow {
4499 return SeqOutStreamBuf_Write(pp, data, size);
4502 outStream.data = dest;
4503 outStream.rem = *destLen;
4504 outStream.overflow = 0/*False*/;
4506 p.writeEndMark = writeEndMark;
4507 p.rc.outStream = &outStream.vt;
4509 res = LzmaEnc_MemPrepare(pp, src, srcLen, 0, alloc, allocBig);
4511 if (res == SZ_OK)
4513 res = LzmaEnc_Encode2(p, progress);
4514 if (res == SZ_OK && p.nowPos64 != srcLen)
4515 res = SZ_ERROR_FAIL;
4518 *destLen -= outStream.rem;
4519 if (outStream.overflow)
4520 return SZ_ERROR_OUTPUT_EOF;
4521 return res;
4525 //==========================================================================
4527 // LzmaEncode
4529 //==========================================================================
4530 public SRes LzmaEncode (ubyte* dest, usize* destLen, const(ubyte)* src, usize srcLen,
4531 const(CLzmaEncProps)* props, ubyte* propsEncoded, usize* propsSize,
4532 int writeEndMark, ICompressProgress *progress, ISzAllocPtr alloc, ISzAllocPtr allocBig)
4534 CLzmaEnc *p = cast(CLzmaEnc *)LzmaEnc_Create(alloc);
4535 SRes res;
4536 if (!p)
4537 return SZ_ERROR_MEM;
4539 res = LzmaEnc_SetProps(p, props);
4540 if (res == SZ_OK)
4542 res = LzmaEnc_WriteProperties(p, propsEncoded, propsSize);
4543 if (res == SZ_OK)
4544 res = LzmaEnc_MemEncode(p, dest, destLen, src, srcLen,
4545 writeEndMark, progress, alloc, allocBig);
4548 LzmaEnc_Destroy(p, alloc, allocBig);
4549 return res;