package jp.sourceforge.nicoro;

public class BinUtil {

	/**
	 * 
	 * @param bytes 元となるbyte配列
	 * @param offset ビット単位のオフセット値
	 * @param length 取得するビット数
	 * @return ２進数表現のbyte配列
	 */
	public static byte[] toBinaryFromBytes(byte[] bytes, int offset, int length) {
    	assert offset >= 0;
    	assert (offset + length + 7) / 8 <= bytes.length;
    	byte[] binary = new byte[length];
    	for (int i = 0; i < length; ++i) {
    		byte b = bytes[(offset + i) / 8];
    		binary[i] = (byte) ((b >> (7 - (offset + i) % 8)) & 1);
    	}
    	return binary;
    }

	public static byte toByteFromBinary(byte[] binary, int offset, int bits) {
    	assert bits <= 8;
    	if (bits == 0) {
    		return 0;
    	}
    	byte retval = 0;
    	for (int i = 0; i < bits; ++i) {
//    		retval |= (binary[offset + i] << i);
    		retval |= (binary[offset + i] << (bits - 1 - i));
    	}
    	return retval;
    }

	public static short toShortFromBinary(byte[] binary, int offset, int bits) {
    	assert bits <= 16;
    	if (bits == 0) {
    		return 0;
    	}
    	short retval = 0;
    	for (int i = 0; i < bits; ++i) {
//    		retval |= (binary[offset + i] << i);
    		retval |= (binary[offset + i] << (bits - 1 - i));
    	}
    	return retval;
    }

	public static int toIntFromBinary(byte[] binary, int offset, int bits) {
    	assert bits <= 32;
    	if (bits == 0) {
    		return 0;
    	}
    	int retval = 0;
    	for (int i = 0; i < bits; ++i) {
//    		retval |= (binary[offset + i] << i);
    		retval |= (binary[offset + i] << (bits - 1 - i));
    	}
    	return retval;
    }

	public static int toSIntFromBinary(byte[] binary, int offset, int bits) {
    	assert bits <= 32;
    	if (bits == 0) {
    		return 0;
    	}
    	int retval;
    	if (binary[offset] != 0) {
    		retval = 0xffffffff ^ ((1 << bits) - 1);
    	} else {
    		retval = 0;
    	}
    	for (int i = 0; i < bits; ++i) {
//    		retval |= (binary[offset + i] << i);
    		retval |= (binary[offset + i] << (bits - 1 - i));
    	}
    	return retval;
    }

	public static long toLongFromBinary(byte[] binary, int offset, int bits) {
    	assert bits <= 64;
    	if (bits == 0) {
    		return 0;
    	}
    	long retval = 0;
    	for (int i = 0; i < bits; ++i) {
//    		retval |= (binary[offset + i] << i);
    		retval |= (binary[offset + i] << (bits - 1 - i));
    	}
    	return retval;
    }

	public static long toSLongFromBinary(byte[] binary, int offset, int bits) {
    	assert bits <= 64;
    	if (bits == 0) {
    		return 0;
    	}
    	long retval;
    	if (binary[offset] != 0) {
    		retval = 0xffffffffffffffffL ^ ((1L << bits) - 1L);
    	} else {
    		retval = 0;
    	}
    	for (int i = 0; i < bits; ++i) {
//    		retval |= (binary[offset + i] << i);
    		retval |= (binary[offset + i] << (bits - 1 - i));
    	}
    	return retval;
    }

	public static boolean getBitFlag(byte[] bytes, int offset) {
		final int indexBytes = offset / 8;
		final int indexBits = 7 - offset % 8;
		return (bytes[indexBytes] & (1 << indexBits)) != 0;
	}
}
