1 // LZ.BinTree 2 3 package SevenZip.Compression.LZ; 4 import java.io.IOException; 5 6 7 public class BinTree extends InWindow 8 { 9 int _cyclicBufferPos; 10 int _cyclicBufferSize = 0; 11 int _matchMaxLen; 12 13 int[] _son; 14 int[] _hash; 15 16 int _cutValue = 0xFF; 17 int _hashMask; 18 int _hashSizeSum = 0; 19 20 boolean HASH_ARRAY = true; 21 22 static final int kHash2Size = 1 << 10; 23 static final int kHash3Size = 1 << 16; 24 static final int kBT2HashSize = 1 << 16; 25 static final int kStartMaxLen = 1; 26 static final int kHash3Offset = kHash2Size; 27 static final int kEmptyHashValue = 0; 28 static final int kMaxValForNormalize = (1 << 30) - 1; 29 30 int kNumHashDirectBytes = 0; 31 int kMinMatchCheck = 4; 32 int kFixHashSize = kHash2Size + kHash3Size; 33 SetType(int numHashBytes)34 public void SetType(int numHashBytes) 35 { 36 HASH_ARRAY = (numHashBytes > 2); 37 if (HASH_ARRAY) 38 { 39 kNumHashDirectBytes = 0; 40 kMinMatchCheck = 4; 41 kFixHashSize = kHash2Size + kHash3Size; 42 } 43 else 44 { 45 kNumHashDirectBytes = 2; 46 kMinMatchCheck = 2 + 1; 47 kFixHashSize = 0; 48 } 49 } 50 51 52 53 Init()54 public void Init() throws IOException 55 { 56 super.Init(); 57 for (int i = 0; i < _hashSizeSum; i++) 58 _hash[i] = kEmptyHashValue; 59 _cyclicBufferPos = 0; 60 ReduceOffsets(-1); 61 } 62 MovePos()63 public void MovePos() throws IOException 64 { 65 if (++_cyclicBufferPos >= _cyclicBufferSize) 66 _cyclicBufferPos = 0; 67 super.MovePos(); 68 if (_pos == kMaxValForNormalize) 69 Normalize(); 70 } 71 72 73 74 75 76 77 78 Create(int historySize, int keepAddBufferBefore, int matchMaxLen, int keepAddBufferAfter)79 public boolean Create(int historySize, int keepAddBufferBefore, 80 int matchMaxLen, int keepAddBufferAfter) 81 { 82 if (historySize > kMaxValForNormalize - 256) 83 return false; 84 _cutValue = 16 + (matchMaxLen >> 1); 85 86 int windowReservSize = (historySize + keepAddBufferBefore + 87 matchMaxLen + keepAddBufferAfter) / 2 + 256; 88 89 super.Create(historySize + keepAddBufferBefore, matchMaxLen + keepAddBufferAfter, windowReservSize); 90 91 _matchMaxLen = matchMaxLen; 92 93 int cyclicBufferSize = historySize + 1; 94 if (_cyclicBufferSize != cyclicBufferSize) 95 _son = new int[(_cyclicBufferSize = cyclicBufferSize) * 2]; 96 97 int hs = kBT2HashSize; 98 99 if (HASH_ARRAY) 100 { 101 hs = historySize - 1; 102 hs |= (hs >> 1); 103 hs |= (hs >> 2); 104 hs |= (hs >> 4); 105 hs |= (hs >> 8); 106 hs >>= 1; 107 hs |= 0xFFFF; 108 if (hs > (1 << 24)) 109 hs >>= 1; 110 _hashMask = hs; 111 hs++; 112 hs += kFixHashSize; 113 } 114 if (hs != _hashSizeSum) 115 _hash = new int [_hashSizeSum = hs]; 116 return true; 117 } GetMatches(int[] distances)118 public int GetMatches(int[] distances) throws IOException 119 { 120 int lenLimit; 121 if (_pos + _matchMaxLen <= _streamPos) 122 lenLimit = _matchMaxLen; 123 else 124 { 125 lenLimit = _streamPos - _pos; 126 if (lenLimit < kMinMatchCheck) 127 { 128 MovePos(); 129 return 0; 130 } 131 } 132 133 int offset = 0; 134 int matchMinPos = (_pos > _cyclicBufferSize) ? (_pos - _cyclicBufferSize) : 0; 135 int cur = _bufferOffset + _pos; 136 int maxLen = kStartMaxLen; // to avoid items for len < hashSize; 137 int hashValue, hash2Value = 0, hash3Value = 0; 138 139 if (HASH_ARRAY) 140 { 141 int temp = CrcTable[_bufferBase[cur] & 0xFF] ^ (_bufferBase[cur + 1] & 0xFF); 142 hash2Value = temp & (kHash2Size - 1); 143 temp ^= ((int)(_bufferBase[cur + 2] & 0xFF) << 8); 144 hash3Value = temp & (kHash3Size - 1); 145 hashValue = (temp ^ (CrcTable[_bufferBase[cur + 3] & 0xFF] << 5)) & _hashMask; 146 } 147 else 148 hashValue = ((_bufferBase[cur] & 0xFF) ^ ((int)(_bufferBase[cur + 1] & 0xFF) << 8)); 149 150 int curMatch = _hash[kFixHashSize + hashValue]; 151 if (HASH_ARRAY) 152 { 153 int curMatch2 = _hash[hash2Value]; 154 int curMatch3 = _hash[kHash3Offset + hash3Value]; 155 _hash[hash2Value] = _pos; 156 _hash[kHash3Offset + hash3Value] = _pos; 157 if (curMatch2 > matchMinPos) 158 if (_bufferBase[_bufferOffset + curMatch2] == _bufferBase[cur]) 159 { 160 distances[offset++] = maxLen = 2; 161 distances[offset++] = _pos - curMatch2 - 1; 162 } 163 if (curMatch3 > matchMinPos) 164 if (_bufferBase[_bufferOffset + curMatch3] == _bufferBase[cur]) 165 { 166 if (curMatch3 == curMatch2) 167 offset -= 2; 168 distances[offset++] = maxLen = 3; 169 distances[offset++] = _pos - curMatch3 - 1; 170 curMatch2 = curMatch3; 171 } 172 if (offset != 0 && curMatch2 == curMatch) 173 { 174 offset -= 2; 175 maxLen = kStartMaxLen; 176 } 177 } 178 179 _hash[kFixHashSize + hashValue] = _pos; 180 181 int ptr0 = (_cyclicBufferPos << 1) + 1; 182 int ptr1 = (_cyclicBufferPos << 1); 183 184 int len0, len1; 185 len0 = len1 = kNumHashDirectBytes; 186 187 if (kNumHashDirectBytes != 0) 188 { 189 if (curMatch > matchMinPos) 190 { 191 if (_bufferBase[_bufferOffset + curMatch + kNumHashDirectBytes] != 192 _bufferBase[cur + kNumHashDirectBytes]) 193 { 194 distances[offset++] = maxLen = kNumHashDirectBytes; 195 distances[offset++] = _pos - curMatch - 1; 196 } 197 } 198 } 199 200 int count = _cutValue; 201 202 while (true) 203 { 204 if (curMatch <= matchMinPos || count-- == 0) 205 { 206 _son[ptr0] = _son[ptr1] = kEmptyHashValue; 207 break; 208 } 209 int delta = _pos - curMatch; 210 int cyclicPos = ((delta <= _cyclicBufferPos) ? 211 (_cyclicBufferPos - delta) : 212 (_cyclicBufferPos - delta + _cyclicBufferSize)) << 1; 213 214 int pby1 = _bufferOffset + curMatch; 215 int len = Math.min(len0, len1); 216 if (_bufferBase[pby1 + len] == _bufferBase[cur + len]) 217 { 218 while(++len != lenLimit) 219 if (_bufferBase[pby1 + len] != _bufferBase[cur + len]) 220 break; 221 if (maxLen < len) 222 { 223 distances[offset++] = maxLen = len; 224 distances[offset++] = delta - 1; 225 if (len == lenLimit) 226 { 227 _son[ptr1] = _son[cyclicPos]; 228 _son[ptr0] = _son[cyclicPos + 1]; 229 break; 230 } 231 } 232 } 233 if ((_bufferBase[pby1 + len] & 0xFF) < (_bufferBase[cur + len] & 0xFF)) 234 { 235 _son[ptr1] = curMatch; 236 ptr1 = cyclicPos + 1; 237 curMatch = _son[ptr1]; 238 len1 = len; 239 } 240 else 241 { 242 _son[ptr0] = curMatch; 243 ptr0 = cyclicPos; 244 curMatch = _son[ptr0]; 245 len0 = len; 246 } 247 } 248 MovePos(); 249 return offset; 250 } 251 Skip(int num)252 public void Skip(int num) throws IOException 253 { 254 do 255 { 256 int lenLimit; 257 if (_pos + _matchMaxLen <= _streamPos) 258 lenLimit = _matchMaxLen; 259 else 260 { 261 lenLimit = _streamPos - _pos; 262 if (lenLimit < kMinMatchCheck) 263 { 264 MovePos(); 265 continue; 266 } 267 } 268 269 int matchMinPos = (_pos > _cyclicBufferSize) ? (_pos - _cyclicBufferSize) : 0; 270 int cur = _bufferOffset + _pos; 271 272 int hashValue; 273 274 if (HASH_ARRAY) 275 { 276 int temp = CrcTable[_bufferBase[cur] & 0xFF] ^ (_bufferBase[cur + 1] & 0xFF); 277 int hash2Value = temp & (kHash2Size - 1); 278 _hash[hash2Value] = _pos; 279 temp ^= ((int)(_bufferBase[cur + 2] & 0xFF) << 8); 280 int hash3Value = temp & (kHash3Size - 1); 281 _hash[kHash3Offset + hash3Value] = _pos; 282 hashValue = (temp ^ (CrcTable[_bufferBase[cur + 3] & 0xFF] << 5)) & _hashMask; 283 } 284 else 285 hashValue = ((_bufferBase[cur] & 0xFF) ^ ((int)(_bufferBase[cur + 1] & 0xFF) << 8)); 286 287 int curMatch = _hash[kFixHashSize + hashValue]; 288 _hash[kFixHashSize + hashValue] = _pos; 289 290 int ptr0 = (_cyclicBufferPos << 1) + 1; 291 int ptr1 = (_cyclicBufferPos << 1); 292 293 int len0, len1; 294 len0 = len1 = kNumHashDirectBytes; 295 296 int count = _cutValue; 297 while (true) 298 { 299 if (curMatch <= matchMinPos || count-- == 0) 300 { 301 _son[ptr0] = _son[ptr1] = kEmptyHashValue; 302 break; 303 } 304 305 int delta = _pos - curMatch; 306 int cyclicPos = ((delta <= _cyclicBufferPos) ? 307 (_cyclicBufferPos - delta) : 308 (_cyclicBufferPos - delta + _cyclicBufferSize)) << 1; 309 310 int pby1 = _bufferOffset + curMatch; 311 int len = Math.min(len0, len1); 312 if (_bufferBase[pby1 + len] == _bufferBase[cur + len]) 313 { 314 while (++len != lenLimit) 315 if (_bufferBase[pby1 + len] != _bufferBase[cur + len]) 316 break; 317 if (len == lenLimit) 318 { 319 _son[ptr1] = _son[cyclicPos]; 320 _son[ptr0] = _son[cyclicPos + 1]; 321 break; 322 } 323 } 324 if ((_bufferBase[pby1 + len] & 0xFF) < (_bufferBase[cur + len] & 0xFF)) 325 { 326 _son[ptr1] = curMatch; 327 ptr1 = cyclicPos + 1; 328 curMatch = _son[ptr1]; 329 len1 = len; 330 } 331 else 332 { 333 _son[ptr0] = curMatch; 334 ptr0 = cyclicPos; 335 curMatch = _son[ptr0]; 336 len0 = len; 337 } 338 } 339 MovePos(); 340 } 341 while (--num != 0); 342 } 343 NormalizeLinks(int[] items, int numItems, int subValue)344 void NormalizeLinks(int[] items, int numItems, int subValue) 345 { 346 for (int i = 0; i < numItems; i++) 347 { 348 int value = items[i]; 349 if (value <= subValue) 350 value = kEmptyHashValue; 351 else 352 value -= subValue; 353 items[i] = value; 354 } 355 } 356 Normalize()357 void Normalize() 358 { 359 int subValue = _pos - _cyclicBufferSize; 360 NormalizeLinks(_son, _cyclicBufferSize * 2, subValue); 361 NormalizeLinks(_hash, _hashSizeSum, subValue); 362 ReduceOffsets(subValue); 363 } 364 SetCutValue(int cutValue)365 public void SetCutValue(int cutValue) { _cutValue = cutValue; } 366 367 private static final int[] CrcTable = new int[256]; 368 369 static 370 { 371 for (int i = 0; i < 256; i++) 372 { 373 int r = i; 374 for (int j = 0; j < 8; j++) 375 if ((r & 1) != 0) 376 r = (r >>> 1) ^ 0xEDB88320; 377 else 378 r >>>= 1; 379 CrcTable[i] = r; 380 } 381 } 382 } 383