JavaのClassファイルを読み取りたかった

読み取りはできたけど、途中で飽きた別にこんなことやる必要なかったので、
名前の対応付けとかその辺はやってないです。あと、printデバッグも消してないです。
バイナリ操作をするためにbyte列を扱うためのユーティリティを書いた(これがメインだったりする)けど、
割と使いにくかったので、やる気になったら今後改善したい。
見所はClassFileの実装のゴリオシ感


参考(まんま。)

http://java.sun.com/docs/books/jvms/second_edition/html/ClassFile.doc.html

ClassFile.java

package my.loader;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

/**
 * とりあえずClassFileを読み出すサンプル
 * 
 * @author ryozi
 * 
 */
public class ClassFile {
	private File classFile = null;
	private MetaData metadata = new MetaData();
	
	/**
	 * ファイルを与えると読み込みます。
	 * 
	 * @param filepath
	 * @throws IOException
	 */
	public ClassFile(String filepath) throws IOException {
		classFile = new File(filepath);
		load();
	}
	
	/**
	 * 勝手に呼ばれます
	 * 
	 * @throws IOException
	 */
	public void load() throws IOException {
		InputStream is = new FileInputStream(classFile);
		MetaData meta = new MetaData();
		metadata = meta;
		
		// マジックナンバー読み取り & 判定
		is.read(meta.magic);
		if (meta.getMagic() != 0xCAFEBABE) {
			throw new RuntimeException("Javaファイルではありません");
		}
		System.out.println("MAGIC_NUMBER: " + ByteUtil.toHexString(metadata.magic, false));
		
		// マイナーバージョン読み取り
		is.read(meta.minor_version);
		is.read(meta.major_version);
		
		System.out.println("minor_version: " + ByteUtil.toHexString(metadata.minor_version, false));
		System.out.println("major_version: " + ByteUtil.toHexString(metadata.major_version, false));
		
		// constant_pool読み取り
		is.read(meta.constant_pool_count);
		meta.constant_pool = new cp_info[meta.getConstant_pool_count() - 1];
		System.out.println("constant_pool_count: " + ByteUtil.toHexString(metadata.constant_pool_count, false));
		
		byte[] constant_pool_tag = new byte[1];
		for (int i = 0; i < meta.getConstant_pool_count() - 1; ++i) {
			is.read(constant_pool_tag);
			meta.constant_pool[i] = newInstance(constant_pool_tag[0]);
			meta.constant_pool[i].load(is);
		}
		
		// access_flags/this_class/super_class読み取り
		is.read(meta.access_flags);
		is.read(meta.this_class);
		is.read(meta.super_class);
		
		// interface読み取り
		is.read(meta.interfaces_count);
		meta.interfaces = new byte[ByteUtil.toShort(meta.interfaces_count, true)][2];
		for (byte[] a : meta.interfaces) {
			is.read(a);
		}
		
		// field読み取り
		is.read(meta.fields_count);
		meta.fields = new field_info[ByteUtil.toShort(meta.fields_count, true)];
		System.out.println("fields_count: " + Integer.toHexString(meta.fields.length));
		
		for (int i = 0; i < meta.fields.length; ++i) {
			meta.fields[i] = new field_info();
			
			is.read(meta.fields[i].access_flags);
			is.read(meta.fields[i].name_index);
			is.read(meta.fields[i].descriptor_index);
			is.read(meta.fields[i].attributes_count);
			meta.fields[i].attributes = new attribute_info[ByteUtil.toShort(meta.fields[i].attributes_count, true)];
			
			load_attribute(is, meta.fields[i].attributes);
		}
		
		// method読み取り
		
		is.read(meta.methods_count);
		meta.methods = new method_info[ByteUtil.toShort(meta.methods_count, true)];
		
		for (int i = 0; i < meta.methods.length; ++i) {
			meta.methods[i] = new method_info();
			
			is.read(meta.methods[i].access_flags);
			is.read(meta.methods[i].name_index);
			is.read(meta.methods[i].descriptor_index);
			is.read(meta.methods[i].attributes_count);
			meta.methods[i].attributes = new attribute_info[ByteUtil.toShort(meta.methods[i].attributes_count, true)];
			
			load_attribute(is, meta.methods[i].attributes);
		}
		
		is.read(meta.attributes_count);
		meta.attributes = new attribute_info[ByteUtil.toShort(meta.attributes_count, true)];
		load_attribute(is, meta.attributes);
		
		long f = classFile.length();
		long s = 0;
		while (is.read() != -1) {
			s += 1;
		}
		;
		
		System.out.println("file size: " + f + " byte");
		System.out.println("skip: " + s + " byte");
		System.out.println("readed: " + (f - s) + " byte");
		
	}
	
	private void load_attribute(InputStream is, attribute_info[] attr) throws IOException {
		for (int i = 0; i < attr.length; ++i) {
			attr[i] = new attribute_info();
			is.read(attr[i].attribute_name_index);
			is.read(attr[i].attribute_length);
			attr[i].info = new byte[ByteUtil.toInt(attr[i].attribute_length, true)][1];
			for (byte[] c : attr[i].info) {
				is.read(c);
			}
		}
	}
	
	private cp_info newInstance(byte tag) {
		switch (tag) {
			case 1:
				return new CONSTANT_Utf8_info();
			case 3:
				return new CONSTANT_Integer_info();
			case 4:
				return new CONSTANT_Float_info();
			case 5:
				return new CONSTANT_Long_info();
			case 6:
				return new CONSTANT_Double_info();
			case 7:
				return new CONSTANT_Class_info();
			case 8:
				return new CONSTANT_String_info();
			case 9:
				return new CONSTANT_Fieldref_info();
			case 10:
				return new CONSTANT_Methodref_info();
			case 11:
				return new CONSTANT_InterfaceMethodref_info();
			case 12:
				return new CONSTANT_NameAndType_info();
			default:
				throw new RuntimeException("サポートしないタグ:" + tag);
		}
	}
	
	class MetaData {
		byte[] magic = new byte[4];
		byte[] minor_version = new byte[2];
		byte[] major_version = new byte[2];
		byte[] constant_pool_count = new byte[2];
		cp_info constant_pool[] = null; // length = constant_pool_count - 1
		byte[] access_flags = new byte[2];
		byte[] this_class = new byte[2];
		byte[] super_class = new byte[2];
		byte[] interfaces_count = new byte[2];
		byte[] interfaces[] = null; // value u2, length = interfaces_count -
									// 1
		byte[] fields_count = new byte[2];
		field_info fields[] = null;
		byte[] methods_count = new byte[2];
		method_info methods[] = null;
		byte[] attributes_count = new byte[2];
		attribute_info attributes[] = null;
		
		public int getMagic() {
			return ByteUtil.toInt(magic, true);
		}
		
		public short getConstant_pool_count() {
			return ByteUtil.toShort(constant_pool_count, true);
		}
	}
	
	class field_info {
		byte[] access_flags = new byte[2];
		byte[] name_index = new byte[2];
		byte[] descriptor_index = new byte[2];
		byte[] attributes_count = new byte[2];
		attribute_info attributes[] = null; // length = attributes_count;
	}
	
	class method_info {
		byte[] access_flags = new byte[2];
		byte[] name_index = new byte[2];
		byte[] descriptor_index = new byte[2];
		byte[] attributes_count = new byte[2];
		attribute_info attributes[] = null; // length = attributes_count;
	}
	
	class attribute_info {
		byte[] attribute_name_index = new byte[2];
		byte[] attribute_length = new byte[4];
		byte[] info[] = null; // attribute_length
	};
	
	abstract class cp_info {
		protected abstract void load(InputStream is) throws IOException;
	}
	
	class CONSTANT_Integer_info extends cp_info {
		byte[] tag = new byte[] { 3 };
		byte[] bytes = new byte[4];
		
		@Override
		public void load(InputStream is) throws IOException {
			is.read(bytes);
		}
	}
	
	// int s = ((bits >> 31) == 0) ? 1 : -1;
	// int e = ((bits >> 23) & 0xff);
	// int m = (e == 0) ?
	// (bits & 0x7fffff) << 1 :
	// (bits & 0x7fffff) | 0x800000;
	//
	// Then the float value equals the result of the mathematical expression
	// s&#183;m&#183;2(e-150).
	class CONSTANT_Float_info extends cp_info {
		byte[] tag = new byte[] { 4 };
		byte[] bytes = new byte[4];
		
		@Override
		public void load(InputStream is) throws IOException {
			is.read(bytes);
		}
	}
	
	class CONSTANT_Long_info extends cp_info {
		byte[] tag = new byte[] { 5 };
		byte[] high_bytes = new byte[4];
		byte[] low_bytes = new byte[4];
		
		@Override
		public void load(InputStream is) throws IOException {
			is.read(high_bytes);
			is.read(low_bytes);
		}
	}
	
	class CONSTANT_Double_info extends cp_info {
		byte[] tag = new byte[] { 6 };
		byte[] high_bytes = new byte[4];
		byte[] low_bytes = new byte[4];
		
		@Override
		public void load(InputStream is) throws IOException {
			is.read(high_bytes);
			is.read(low_bytes);
		}
	}
	
	class CONSTANT_Class_info extends cp_info {
		byte[] tag = new byte[] { 7 };
		byte[] name_index = new byte[2];
		
		@Override
		public void load(InputStream is) throws IOException {
			is.read(name_index);
		}
	}
	
	class CONSTANT_String_info extends cp_info {
		byte[] tag = new byte[] { 8 };
		byte[] string_index = new byte[2];
		
		@Override
		public void load(InputStream is) throws IOException {
			is.read(string_index);
		}
	}
	
	class CONSTANT_Fieldref_info extends cp_info {
		byte[] tag = new byte[] { 9 };
		byte[] class_index = new byte[2];
		byte[] name_and_type_index = new byte[2];
		
		@Override
		public void load(InputStream is) throws IOException {
			is.read(class_index);
			is.read(name_and_type_index);
		}
	}
	
	class CONSTANT_Methodref_info extends cp_info {
		byte[] tag = new byte[] { 10 };
		byte[] class_index = new byte[2];
		byte[] name_and_type_index = new byte[2];
		
		@Override
		public void load(InputStream is) throws IOException {
			is.read(class_index);
			is.read(name_and_type_index);
		}
	}
	
	class CONSTANT_InterfaceMethodref_info extends cp_info {
		byte[] tag = new byte[] { 11 };
		byte[] class_index = new byte[2];
		byte[] name_and_type_index = new byte[2];
		
		@Override
		public void load(InputStream is) throws IOException {
			is.read(class_index);
			is.read(name_and_type_index);
		}
	}
	
	class CONSTANT_NameAndType_info extends cp_info {
		byte[] tag = new byte[] { 12 };
		byte[] name_index = new byte[2];
		byte[] descriptor_index = new byte[2];
		
		@Override
		public void load(InputStream is) throws IOException {
			is.read(name_index);
			is.read(descriptor_index);
		}
	}
	
	class CONSTANT_Utf8_info extends cp_info {
		byte[] tag = new byte[] { 1 };
		byte[] length = new byte[2];
		byte[] bytes = null; // length
		
		@Override
		public void load(InputStream is) throws IOException {
			is.read(length);
			bytes = new byte[ByteUtil.toShort(length, true)];
			is.read(bytes);
			
			System.out.println(new String(bytes));
			
		}
	}
}

ByteUtil.java

package my.loader;

import java.util.Arrays;

/**
 * byte列を扱うためのなにか。
 * 
 * @author ryozi
 * 
 */
public class ByteUtil {
	
	private static final int[][] ENDIAN_SHORT = new int[][] { { 0, 1 },
			{ 1, 0 } };
	private static final int[][] ENDIAN_INT = new int[][] { { 0, 1, 2, 3 },
			{ 3, 2, 1, 0 } };
	private static final int[][] ENDIAN_LONG = new int[][] {
			{ 0, 1, 2, 3, 4, 5, 6, 7 }, { 7, 6, 5, 4, 3, 2, 1, 0 } };
	
	/**
	 * 符号なしbyteの値を取得します。
	 * 戻り値がlongであることに注意してください。
	 * 
	 * @param x
	 * @return
	 */
	public static long toUnsignedByte(long x) {
		return x & 0x00000000000000FFL;
	}
	
	/**
	 * 符号なしshortの値を取得します。
	 * 戻り値がlongであることに注意してください。
	 * 
	 * @param x
	 * @return
	 */
	public static long toUnsignedShort(long x) {
		return x & 0x000000000000FFFFL;
	}
	
	/**
	 * 符号なしintの値を取得します。
	 * 戻り値がlongであることに注意してください。
	 * 
	 * @param x
	 * @return
	 */
	public static long toUnsignedInt(long x) {
		return x & 0x00000000FFFFFFFFL;
	}
	
	/**
	 * byte列中の任意の場所から任意のサイズのbyte列をコピーして取得します。
	 * Arrays#copyOfRange の糖衣構文です。
	 * 
	 * @param bytes
	 * @param offset
	 * @param length
	 * @return
	 */
	public static byte[] copyOf(byte[] bytes, int offset, int length) {
		return Arrays.copyOfRange(bytes, offset, offset + length);
	}
	
	/**
	 * 与えられた値をByte列に変換します。
	 * longを引数に取りますが、考慮されるのは下位8bitのみです。
	 * 
	 * @param ls
	 * @return
	 */
	public static byte[] toByteArray(long... ls) {
		byte[] bs = new byte[ls.length];
		for (int i = 0; i < ls.length; ++i) {
			bs[i] = (byte) (toUnsignedByte(ls[i]));
		}
		return bs;
	}
	
	/**
	 * 2byteのbyte列からshortへ変換します
	 * 
	 * @param byte2
	 * @param isBigEndian
	 * @return
	 */
	public static short toShort(byte[] byte2, boolean isBigEndian) {
		if (byte2.length != 2) {
			throw new IllegalArgumentException("2byte only");
		}
		final int[] endian = ENDIAN_SHORT[isBigEndian ? 0 : 1];
		return (short) ((toUnsignedByte(byte2[endian[0]]) << 8
		| toUnsignedByte(byte2[endian[1]])));
	}
	
	/**
	 * 4byteのbyte列からintへ変換します
	 * 
	 * @param byte4
	 * @param isBigEndian
	 * @return
	 */
	public static int toInt(byte[] byte4, boolean isBigEndian) {
		if (byte4.length != 4) {
			throw new IllegalArgumentException("4byte only");
		}
		final int[] endian = ENDIAN_INT[isBigEndian ? 0 : 1];
		return (int) (toUnsignedByte(byte4[endian[0]]) << 24
				| toUnsignedByte(byte4[endian[1]]) << 16
				| toUnsignedByte(byte4[endian[2]]) << 8
				| toUnsignedByte(byte4[endian[3]]) << 0);
	}
	
	/**
	 * 4byteのbyte列からfloatへ変換します
	 * 
	 * @param byte4
	 * @param isBigEndian
	 * @return
	 */
	public static float toFloat(byte[] byte4, boolean isBigEndian) {
		return toFloat(toInt(byte4, isBigEndian));
	}
	
	/**
	 * intのbit配列を考慮して、floatへ変換します。
	 * 無限や、扱えない値によるエラーは考慮されません。
	 * 
	 * int s = ((bits >> 31) == 0) ? 1 : -1;
	 * int e = ((bits >> 23) & 0xff);
	 * int m = (e == 0) ?
	 * (bits & 0x7fffff) << 1 :
	 * (bits & 0x7fffff) | 0x800000;
	 * Then the float value equals the result of the mathematical expression
	 * s&#183;m&#183;2^(e-150).
	 * 
	 * @param byte4
	 * @param isBigEndian
	 * @return
	 */
	public static float toFloat(int bits) {
		int s = (bits >> 31) == 0 ? 1 : -1;
		int e = (bits >> 23) & 0xFF;
		int m = (e == 0) ? ((bits & 0x7FFFFF) << 1) : ((bits & 0x7FFFFF) | 0x800000);
		return (float) (s * m * Math.pow(2, e - 150));
	}
	
	/**
	 * 8byteのbyte列をlongへ変換します。
	 * 
	 * @param byte8
	 * @param isBigEndian
	 * @return
	 */
	public static long toLong(byte[] byte8, boolean isBigEndian) {
		if (byte8.length != 8) {
			throw new IllegalArgumentException("8byte only");
		}
		final int[] endian = ENDIAN_LONG[isBigEndian ? 0 : 1];
		return toUnsignedByte(byte8[endian[0]]) << 56
				| toUnsignedByte(byte8[endian[1]]) << 48
				| toUnsignedByte(byte8[endian[2]]) << 40
				| toUnsignedByte(byte8[endian[3]]) << 32
				| toUnsignedByte(byte8[endian[4]]) << 24
				| toUnsignedByte(byte8[endian[5]]) << 16
				| toUnsignedByte(byte8[endian[6]]) << 8
				| toUnsignedByte(byte8[endian[7]]);
	}
	
	/**
	 * intを4byteに切り出し、byte列に変換します。
	 * 
	 * @param x
	 * @param isBigEndian
	 * @return
	 */
	public static byte[] toByteArray(int x, boolean isBigEndian) {
		byte[] bytes = new byte[4];
		final int[] endian = ENDIAN_INT[isBigEndian ? 0 : 1];
		bytes[endian[0]] = (byte) (x >> 24);
		bytes[endian[1]] = (byte) ((x >> 16) & 0xFF);
		bytes[endian[2]] = (byte) ((x >> 8) & 0xFF);
		bytes[endian[3]] = (byte) ((x >> 0) & 0xFF);
		return bytes;
	}
	
	/**
	 * byte列を16進数変換します。0xを勝手につけます。
	 * 
	 * @param bs
	 * @param isBigEndian
	 * @return
	 */
	public static String toHexString(byte[] bs, boolean isBigEndian) {
		int init = 0;
		int loop = bs.length;
		int add = 1;
		
		if (isBigEndian) {
			init = loop - 1;
			loop = -1;
			add = -1;
		}
		
		String ret = "0x";
		for (int i = init; i != loop; i += add) {
			ret += String.format("%02X", toUnsignedByte(bs[i]));
		}
		return ret;
	}
	
	/**
	 * バイト列からビットを読み取り、0/1の文字になおして書き出します。
	 * エンディアンは考慮しません。(めんどくさくなったから)
	 * 
	 * @param bs
	 * @return
	 */
	public static String toBitString(byte[] bs) {
		String ret = "";
		for (int i = 0; i < bs.length; i++) {
			ret += (bs[i] >> 7) & 1;
			ret += (bs[i] >> 6) & 1;
			ret += (bs[i] >> 5) & 1;
			ret += (bs[i] >> 4) & 1;
			ret += (bs[i] >> 3) & 1;
			ret += (bs[i] >> 2) & 1;
			ret += (bs[i] >> 1) & 1;
			ret += (bs[i] >> 0) & 1;
		}
		return ret;
	}
}

ByteUtilTest.java

テストの書き方とかわかりませんですし

package my.loader.test;

import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import my.loader.ByteUtil;

import org.junit.Test;

public class ByteUtilTest {

	@Test
	public void copyOfTest() {
		assertArrayEquals(ByteUtil.toByteArray(0x00,0x20,0x40,0x80,0xFF), ByteUtil.copyOf(ByteUtil.toByteArray(0x00,0x20,0x40,0x80,0xFF), 0, 5));
		assertArrayEquals(ByteUtil.toByteArray(0x00,0x20,0x40,0x80), ByteUtil.copyOf(ByteUtil.toByteArray(0x00,0x20,0x40,0x80,0xFF), 0, 4));
		assertArrayEquals(ByteUtil.toByteArray(0x20,0x40,0x80), ByteUtil.copyOf(ByteUtil.toByteArray(0x00,0x20,0x40,0x80,0xFF), 1, 3));
	}
	

	@Test
	public void toUnsignedByteTest() {
		assertEquals(0x00, ByteUtil.toUnsignedByte(0x00));
		assertEquals(0x40, ByteUtil.toUnsignedByte(0x40));
		assertEquals(0x80, ByteUtil.toUnsignedByte(0x80));
		assertEquals(0xFFL, ByteUtil.toUnsignedByte(0xFF));
		assertEquals(0xFFL, ByteUtil.toUnsignedByte(0xFFFFFFFF));
	}
	
	@Test
	public void toUnsignedIntTest() {
		assertEquals(0x00, ByteUtil.toUnsignedInt(0x00));
		assertEquals(0x40, ByteUtil.toUnsignedInt(0x40));
		assertEquals(0x80, ByteUtil.toUnsignedInt(0x80));
		assertEquals(0x000000FFL, ByteUtil.toUnsignedInt(0xFF));
		assertEquals(0x0000FF00L, ByteUtil.toUnsignedInt(0xFF) << 8);
		assertEquals(0xFF000000L, ByteUtil.toUnsignedInt(0xFF) << 24);
		assertEquals(0x000000FFL, ByteUtil.toUnsignedInt(0xFF));
		assertEquals(0x0000FF00L, ByteUtil.toUnsignedInt(0xFF) << 8);
		
		assertEquals(0x800000L, ByteUtil.toUnsignedInt(0x800000));
		assertEquals(0x7FFFFFFFL, ByteUtil.toUnsignedInt(0x7FFFFFFF));
		assertEquals(0x80000000L, ByteUtil.toUnsignedInt(0x80000000));
		assertEquals(0xFFFFFFFFL, ByteUtil.toUnsignedInt(0xFFFFFFFF));
	}
	
	@Test
	public void toByteArrayTest() {
		assertArrayEquals(new byte[] { (byte) (0xFF & 0xFF),
				(byte) (0x80 & 0xFF) }, ByteUtil.toByteArray(0xFF, 0x80));
		assertArrayEquals(new byte[] { (byte) (0xFF & 0xFF),
				(byte) (0x80 & 0xFF), 0x40, 0x20 },
				ByteUtil.toByteArray(0xFF, 0x80, 0x40, 0x20));
	}
	
	@Test
	public void toInt4byteTest() {
		assertEquals(0x10203040,
				ByteUtil.toInt(new byte[] { 0x10, 0x20, 0x30, 0x40 }, true));
		assertEquals(0x40302010,
				ByteUtil.toInt(new byte[] { 0x10, 0x20, 0x30, 0x40 }, false));
		assertEquals(
				0xFF804020,
				ByteUtil.toInt(ByteUtil.toByteArray(0xFF, 0x80, 0x40, 0x20),
						true));
		assertEquals(
				0x204080FF,
				ByteUtil.toInt(ByteUtil.toByteArray(0xFF, 0x80, 0x40, 0x20),
						false));
	}
	
	@Test(expected = AssertionError.class)
	public void toIntTestNG1() {
		assertEquals(0x10203041,
				ByteUtil.toInt(new byte[] { 0x10, 0x20, 0x30, 0x40 }, true));
	}
	
	@Test(expected = AssertionError.class)
	public void toIntTestNG2() {
		assertEquals(40302010,
				ByteUtil.toInt(new byte[] { 0x10, 0x20, 0x30, 0x40 }, false));
	}
	
	
	@Test
	public void toFloatTest() {
		assertTrue(Float.valueOf(0.15625F).equals(ByteUtil.toFloat(ByteUtil.toByteArray(0x3E, 0x20, 0x00, 0x00), true)));
		assertTrue(Float.valueOf(1.5F).equals(ByteUtil.toFloat(ByteUtil.toByteArray(0x3F, 0xC0, 0x00, 0x00), true)));
		assertTrue(Float.valueOf(-4.9F).equals(ByteUtil.toFloat(ByteUtil.toByteArray(0xC0, 0x9C, 0xCC, 0xCD), true)));
	}

	@Test
	public void toBitStringTest() {
		assertEquals("00111110001000000000000000000000", ByteUtil.toBitString(ByteUtil.toByteArray(0x3E, 0x20, 0x00, 0x00)));
	}
	
	@Test
	public void toByteArrayByteTest() {
		assertEquals("11111111111111111111111111111111", ByteUtil.toBitString(ByteUtil.toByteArray(0xFFFFFFFF, true)));
		assertEquals("11111111111111111111111111111111", ByteUtil.toBitString(ByteUtil.toByteArray(0xFFFFFFFF, false)));
		assertEquals("00001111111111111111111111111111", ByteUtil.toBitString(ByteUtil.toByteArray(0x0FFFFFFF, true)));
		assertEquals("11111111111111111111111100001111", ByteUtil.toBitString(ByteUtil.toByteArray(0x0FFFFFFF, false)));
		assertEquals("00001111111111111111111111110000", ByteUtil.toBitString(ByteUtil.toByteArray(0x0FFFFFF0, true)));
		assertEquals("11110000111111111111111100001111", ByteUtil.toBitString(ByteUtil.toByteArray(0x0FFFFFF0, false)));
	}
	
	@Test
	public void toShortTest() {
		
		assertEquals(0x1020,
				ByteUtil.toShort(new byte[] { 0x10, 0x20 }, true));
		assertEquals(0x2010,
				ByteUtil.toShort(new byte[] { 0x10, 0x20 }, false));
		
		assertEquals(
				(short)0xFF80,
				ByteUtil.toShort(new byte[] {
						(byte) (0x000000FF & 0xFF),
						(byte) (0x00000080 & 0xFF) }, true));
		assertEquals(
				(short) 0x80FF,
				ByteUtil.toShort(new byte[] {
						(byte) (((int) 0xFF) & 0xFF),
						(byte) (((int) 0x80) & 0xFF) }, false));
	}
	
	@Test
	public void toLongTest() {

		assertEquals(0x1020304050607080L,
				ByteUtil.toLong(ByteUtil.toByteArray(0x10,0x20,0x30,0x40,0x50,0x60,0x70,0x80), true));
		assertEquals(0x8070605040302010L,
				ByteUtil.toLong(ByteUtil.toByteArray(0x10,0x20,0x30,0x40,0x50,0x60,0x70,0x80), false));
		assertEquals(0x10203040506070FFL,
				ByteUtil.toLong(ByteUtil.toByteArray(0x10,0x20,0x30,0x40,0x50,0x60,0x70,0xFF), true));
		assertEquals(0xFF70605040302010L,
				ByteUtil.toLong(ByteUtil.toByteArray(0x10,0x20,0x30,0x40,0x50,0x60,0x70,0xFF), false));
		
	}
}