5 namespace SevenZip
.Compression
.LZ
7 public class BinTree
: InWindow
, IMatchFinder
9 UInt32 _cyclicBufferPos
;
10 UInt32 _cyclicBufferSize
;
21 UInt32 _cutValue
= 0xFF;
23 bool HASH_ARRAY
= true;
24 bool HASH_BIG
= false;
26 const UInt32 kHash3Size
= 1 << 18;
28 const UInt32 kBT2HashSize
= 1 << 16;
29 const UInt32 kBT4Hash2Size
= 1 << 10;
30 const UInt32 kBT4Hash4Size
= 1 << 20;
31 const UInt32 kBT4bHash4Size
= 1 << 23;
32 const UInt32 kBT2NumHashDirectBytes
= 2;
33 const UInt32 kBT4NumHashDirectBytes
= 0;
35 UInt32 kHash2Size
= kBT4Hash2Size
;
36 UInt32 kNumHashDirectBytes
= kBT4NumHashDirectBytes
;
37 UInt32 kNumHashBytes
= 4;
38 UInt32 kHashSize
= kBT4Hash4Size
;
40 public void SetType(int numHashBytes
, bool big
)
42 HASH_ARRAY
= numHashBytes
> 2;
46 kHash2Size
= kBT4Hash2Size
;
47 kNumHashDirectBytes
= kBT4NumHashDirectBytes
;
49 kHashSize
= HASH_BIG
? kBT4bHash4Size
: kBT4Hash4Size
;
53 kNumHashDirectBytes
= kBT2NumHashDirectBytes
;
55 kHashSize
= kBT2HashSize
;
59 const UInt32 kEmptyHashValue
= 0;
61 const UInt32 kMaxValForNormalize
= ((UInt32
)1 << 31) - 1;
63 UInt32
Hash(UInt32 offset
, out UInt32 hash2Value
, out UInt32 hash3Value
)
65 UInt32 temp
= CRC
.Table
[_bufferBase
[offset
]] ^ _bufferBase
[offset
+ 1];
66 hash2Value
= temp
& (kHash2Size
- 1);
67 temp ^
= ((UInt32
)(_bufferBase
[offset
+ 2]) << 8);
68 hash3Value
= temp
& (kHash3Size
- 1);
69 return (temp ^
(CRC
.Table
[_bufferBase
[offset
+ 3]] << 5)) & (kHashSize
- 1);
72 UInt32
Hash(UInt32 offset
)
74 return _bufferBase
[offset
] ^
((UInt32
)(_bufferBase
[offset
+ 1]) << 8);
77 public new void Init(System
.IO
.Stream inStream
)
81 for (i
= 0; i
< kHashSize
; i
++)
82 _hash
[i
] = kEmptyHashValue
;
85 for (i
= 0; i
< kHash2Size
; i
++)
86 _hash2
[i
] = kEmptyHashValue
;
87 for (i
= 0; i
< kHash3Size
; i
++)
88 _hash3
[i
] = kEmptyHashValue
;
94 public new void ReleaseStream() { base.ReleaseStream(); }
96 public new void MovePos()
99 if (_cyclicBufferPos
>= _cyclicBufferSize
)
100 _cyclicBufferPos
= 0;
102 if (_pos
== kMaxValForNormalize
)
106 public new Byte
GetIndexByte(Int32 index
) { return base.GetIndexByte(index); }
108 public new UInt32
GetMatchLen(Int32 index
, UInt32 distance
, UInt32 limit
)
109 { return base.GetMatchLen(index, distance, limit); }
111 public new UInt32
GetNumAvailableBytes() { return base.GetNumAvailableBytes(); }
113 public void Create(UInt32 historySize
, UInt32 keepAddBufferBefore
,
114 UInt32 matchMaxLen
, UInt32 keepAddBufferAfter
)
116 // _dummy = new UInt32[matchMaxLen + 1];
117 UInt32 windowReservSize
= (historySize
+ keepAddBufferBefore
+
118 matchMaxLen
+ keepAddBufferAfter
) / 2 + 256;
125 base.Create(historySize
+ keepAddBufferBefore
, matchMaxLen
+ keepAddBufferAfter
, windowReservSize
);
127 if (_blockSize
+ 256 > kMaxValForNormalize
)
128 throw new Exception();
130 _historySize
= historySize
;
131 _matchMaxLen
= matchMaxLen
;
133 _cyclicBufferSize
= historySize
+ 1;
134 _son
= new UInt32
[_cyclicBufferSize
* 2];
136 _hash
= new UInt32
[kHashSize
];
139 _hash2
= new UInt32
[kHash2Size
];
140 _hash3
= new UInt32
[kHash3Size
];
144 public UInt32
GetLongestMatch(UInt32
[] distances
)
147 if (_pos
+ _matchMaxLen
<= _streamPos
)
148 lenLimit
= _matchMaxLen
;
151 lenLimit
= _streamPos
- _pos
;
152 if (lenLimit
< kNumHashBytes
)
156 UInt32 matchMinPos
= (_pos
> _historySize
) ? (_pos
- _historySize
) : 1;
158 UInt32 cur
= _bufferOffset
+ _pos
;
160 UInt32 matchHashLenMax
= 0;
162 UInt32 hashValue
, hash2Value
= 0, hash3Value
= 0;
165 hashValue
= Hash(cur
, out hash2Value
, out hash3Value
);
167 hashValue
= Hash(cur
);
169 UInt32 curMatch
= _hash
[hashValue
];
170 UInt32 curMatch2
= 0, curMatch3
= 0;
171 UInt32 len2Distance
= 0;
172 UInt32 len3Distance
= 0;
173 bool matchLen2Exist
= false;
174 bool matchLen3Exist
= false;
177 curMatch2
= _hash2
[hash2Value
];
178 curMatch3
= _hash3
[hash3Value
];
179 _hash2
[hash2Value
] = _pos
;
180 if (curMatch2
>= matchMinPos
)
182 if (_bufferBase
[_bufferOffset
+ curMatch2
] == _bufferBase
[cur
])
184 len2Distance
= _pos
- curMatch2
- 1;
186 matchLen2Exist
= true;
190 _hash3
[hash3Value
] = _pos
;
191 if (curMatch3
>= matchMinPos
)
193 if (_bufferBase
[_bufferOffset
+ curMatch3
] == _bufferBase
[cur
])
195 len3Distance
= _pos
- curMatch3
- 1;
197 matchLen3Exist
= true;
200 if (len3Distance
< len2Distance
)
201 len2Distance
= len3Distance
;
205 len2Distance
= len3Distance
;
206 matchLen2Exist
= true;
213 _hash
[hashValue
] = _pos
;
215 if (curMatch
< matchMinPos
)
217 _son
[(_cyclicBufferPos
<< 1)] = kEmptyHashValue
;
218 _son
[(_cyclicBufferPos
<< 1) + 1] = kEmptyHashValue
;
222 distances
[2] = len2Distance
;
223 distances
[3] = len3Distance
;
225 return matchHashLenMax
;
227 UInt32 ptrLeft
= (_cyclicBufferPos
<< 1) + 1;
228 UInt32 ptrRight
= (_cyclicBufferPos
<< 1);
230 UInt32 maxLen
, minLeft
, minRight
;
231 maxLen
= minLeft
= minRight
= kNumHashDirectBytes
;
233 distances
[maxLen
] = _pos
- curMatch
- 1;
235 for (UInt32 count
= _cutValue
; count
> 0; count
--)
237 UInt32 pby1
= _bufferOffset
+ curMatch
;
238 UInt32 currentLen
= Math
.Min(minLeft
, minRight
);
239 for (; currentLen
< lenLimit
; currentLen
++)
240 if (_bufferBase
[pby1
+ currentLen
] != _bufferBase
[cur
+ currentLen
])
242 UInt32 delta
= _pos
- curMatch
;
243 while (currentLen
> maxLen
)
244 distances
[++maxLen
] = delta
- 1;
246 UInt32 cyclicPos
= ((delta
<= _cyclicBufferPos
) ?
247 (_cyclicBufferPos
- delta
) :
248 (_cyclicBufferPos
- delta
+ _cyclicBufferSize
)) << 1;
250 if (currentLen
!= lenLimit
)
252 if (_bufferBase
[pby1
+ currentLen
] < _bufferBase
[cur
+ currentLen
])
254 _son
[ptrRight
] = curMatch
;
255 ptrRight
= cyclicPos
+ 1;
256 curMatch
= _son
[ptrRight
];
257 if (currentLen
> minLeft
)
258 minLeft
= currentLen
;
262 _son
[ptrLeft
] = curMatch
;
264 curMatch
= _son
[ptrLeft
];
265 if (currentLen
> minRight
)
266 minRight
= currentLen
;
271 if (currentLen
< _matchMaxLen
)
273 _son
[ptrLeft
] = curMatch
;
275 curMatch
= _son
[ptrLeft
];
276 if (currentLen
> minRight
)
277 minRight
= currentLen
;
281 _son
[ptrLeft
] = _son
[cyclicPos
+ 1];
282 _son
[ptrRight
] = _son
[cyclicPos
];
286 if (matchLen2Exist
&& len2Distance
< distances
[2])
287 distances
[2] = len2Distance
;
288 if (matchLen3Exist
&& len3Distance
< distances
[3])
289 distances
[3] = len3Distance
;
294 if (curMatch
< matchMinPos
)
297 _son
[ptrLeft
] = kEmptyHashValue
;
298 _son
[ptrRight
] = kEmptyHashValue
;
306 distances
[2] = len2Distance
;
309 else if (len2Distance
< distances
[2])
310 distances
[2] = len2Distance
;
317 distances
[3] = len3Distance
;
320 else if (len3Distance
< distances
[3])
321 distances
[3] = len3Distance
;
328 public void DummyLongestMatch()
330 // GetLongestMatch(_dummy);
333 if (_pos
+ _matchMaxLen
<= _streamPos
)
334 lenLimit
= _matchMaxLen
;
337 lenLimit
= _streamPos
- _pos
;
338 if (lenLimit
< kNumHashBytes
)
342 UInt32 matchMinPos
= (_pos
> _historySize
) ? (_pos
- _historySize
) : 1;
344 UInt32 cur
= _bufferOffset
+ _pos
;
346 UInt32 hashValue
, hash2Value
= 0, hash3Value
= 0;
349 hashValue
= Hash(cur
, out hash2Value
, out hash3Value
);
351 hashValue
= Hash(cur
);
353 UInt32 curMatch
= _hash
[hashValue
];
354 UInt32 curMatch2
= 0, curMatch3
= 0;
357 curMatch2
= _hash2
[hash2Value
];
358 curMatch3
= _hash3
[hash3Value
];
359 _hash2
[hash2Value
] = _pos
;
360 _hash3
[hash3Value
] = _pos
;
362 _hash
[hashValue
] = _pos
;
364 if (curMatch
< matchMinPos
)
366 _son
[(_cyclicBufferPos
<< 1)] = kEmptyHashValue
;
367 _son
[(_cyclicBufferPos
<< 1) + 1] = kEmptyHashValue
;
370 UInt32 ptrLeft
= (_cyclicBufferPos
<< 1) + 1;
371 UInt32 ptrRight
= (_cyclicBufferPos
<< 1);
373 UInt32 minLeft
, minRight
;
374 minLeft
= minRight
= kNumHashDirectBytes
;
376 for (UInt32 count
= _cutValue
; count
> 0; count
--)
378 UInt32 pby1
= _bufferOffset
+ curMatch
;
379 UInt32 currentLen
= Math
.Min(minLeft
, minRight
);
380 for (; currentLen
< lenLimit
; currentLen
++)
381 if (_bufferBase
[pby1
+ currentLen
] != _bufferBase
[cur
+ currentLen
])
383 UInt32 delta
= _pos
- curMatch
;
385 UInt32 cyclicPos
= ((delta
<= _cyclicBufferPos
) ?
386 (_cyclicBufferPos
- delta
) :
387 (_cyclicBufferPos
- delta
+ _cyclicBufferSize
)) << 1;
389 if (currentLen
!= lenLimit
)
391 if (_bufferBase
[pby1
+ currentLen
] < _bufferBase
[cur
+ currentLen
])
393 _son
[ptrRight
] = curMatch
;
394 ptrRight
= cyclicPos
+ 1;
395 curMatch
= _son
[ptrRight
];
396 if (currentLen
> minLeft
)
397 minLeft
= currentLen
;
401 _son
[ptrLeft
] = curMatch
;
403 curMatch
= _son
[ptrLeft
];
404 if (currentLen
> minRight
)
405 minRight
= currentLen
;
410 if (currentLen
< _matchMaxLen
)
412 _son
[ptrLeft
] = curMatch
;
414 curMatch
= _son
[ptrLeft
];
415 if (currentLen
> minRight
)
416 minRight
= currentLen
;
420 _son
[ptrLeft
] = _son
[cyclicPos
+ 1];
421 _son
[ptrRight
] = _son
[cyclicPos
];
425 if (curMatch
< matchMinPos
)
428 _son
[ptrLeft
] = kEmptyHashValue
;
429 _son
[ptrRight
] = kEmptyHashValue
;
432 void NormalizeLinks(UInt32
[] items
, UInt32 numItems
, UInt32 subValue
)
434 for (UInt32 i
= 0; i
< numItems
; i
++)
436 UInt32
value = items
[i
];
437 if (value <= subValue
)
438 value = kEmptyHashValue
;
447 UInt32 startItem
= _pos
- _historySize
;
448 UInt32 subValue
= startItem
- 1;
449 NormalizeLinks(_son
, _cyclicBufferSize
* 2, subValue
);
451 NormalizeLinks(_hash
, kHashSize
, subValue
);
455 NormalizeLinks(_hash2
, kHash2Size
, subValue
);
456 NormalizeLinks(_hash3
, kHash3Size
, subValue
);
458 ReduceOffsets((Int32
)subValue
);
461 public void SetCutValue(UInt32 cutValue
) { _cutValue = cutValue; }