blob: a05e08b75e40e4cc018f59f1468de443cf2c5262 [file] [log] [blame]
/*
* BCJ filter for x86 instructions
*
* Authors: Lasse Collin <lasse.collin@tukaani.org>
* Igor Pavlov <http://7-zip.org/>
*
* This file has been put into the public domain.
* You can do whatever you want with this file.
*/
package org.tukaani.xz.simple;
public final class X86 implements SimpleFilter {
private static final boolean[] MASK_TO_ALLOWED_STATUS
= {true, true, true, false, true, false, false, false};
private static final int[] MASK_TO_BIT_NUMBER = {0, 1, 2, 2, 3, 3, 3, 3};
private final boolean isEncoder;
private int pos;
private int prevMask = 0;
private static boolean test86MSByte(byte b) {
int i = b & 0xFF;
return i == 0x00 || i == 0xFF;
}
public X86(boolean isEncoder, int startPos) {
this.isEncoder = isEncoder;
pos = startPos + 5;
}
public int code(byte[] buf, int off, int len) {
int prevPos = off - 1;
int end = off + len - 5;
int i;
for (i = off; i <= end; ++i) {
if ((buf[i] & 0xFE) != 0xE8)
continue;
prevPos = i - prevPos;
if ((prevPos & ~3) != 0) { // (unsigned)prevPos > 3
prevMask = 0;
} else {
prevMask = (prevMask << (prevPos - 1)) & 7;
if (prevMask != 0) {
if (!MASK_TO_ALLOWED_STATUS[prevMask] || test86MSByte(
buf[i + 4 - MASK_TO_BIT_NUMBER[prevMask]])) {
prevPos = i;
prevMask = (prevMask << 1) | 1;
continue;
}
}
}
prevPos = i;
if (test86MSByte(buf[i + 4])) {
int src = (buf[i + 1] & 0xFF)
| ((buf[i + 2] & 0xFF) << 8)
| ((buf[i + 3] & 0xFF) << 16)
| ((buf[i + 4] & 0xFF) << 24);
int dest;
while (true) {
if (isEncoder)
dest = src + (pos + i - off);
else
dest = src - (pos + i - off);
if (prevMask == 0)
break;
int index = MASK_TO_BIT_NUMBER[prevMask] * 8;
if (!test86MSByte((byte)(dest >>> (24 - index))))
break;
src = dest ^ ((1 << (32 - index)) - 1);
}
buf[i + 1] = (byte)dest;
buf[i + 2] = (byte)(dest >>> 8);
buf[i + 3] = (byte)(dest >>> 16);
buf[i + 4] = (byte)(~(((dest >>> 24) & 1) - 1));
i += 4;
} else {
prevMask = (prevMask << 1) | 1;
}
}
prevPos = i - prevPos;
prevMask = ((prevPos & ~3) != 0) ? 0 : prevMask << (prevPos - 1);
i -= off;
pos += i;
return i;
}
}