Home | History | Annotate | Download | only in LZ
      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 
     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 
     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 
     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 
     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 	}
    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 
    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 
    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 
    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 
    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