// Copyright 1997 The Open Group Research Institute.  All rights reserved.

package krb4.lib;

public class Krb4Encode {
	public byte[] data;
	public int offset;
	public boolean littleEndian;
	public boolean endianessSet;

	public Krb4Encode(byte[] new_data, int new_offset) throws Krb4Exception {
		if (new_data == null)
			throw new Krb4Exception(Krb4.REP_NO_DATA);
		if (new_offset >= new_data.length)
			throw new Krb4Exception(Krb4.REP_OVERRUN);
		data = new_data;
		offset = new_offset;
	}

	public Krb4Encode(byte[] new_data) throws Krb4Exception {
		this(new_data, 0);
	}

	public void setByteOrder(boolean isLittleEndian) {
		littleEndian = isLittleEndian;
		endianessSet = true;
	}

	public byte getByte() throws Krb4Exception {
		if (offset >= data.length)
			throw new Krb4Exception(Krb4.REP_OVERRUN);
		byte result = data[offset];
		offset++;
		return result;
	}

	public byte[] getBytes(int length) throws Krb4Exception {
		if (offset + length > data.length)
			throw new Krb4Exception(Krb4.REP_OVERRUN);
		byte[] result = new byte[length];
		System.arraycopy(data, offset, result, 0, length);
		offset += length;
		return result;
	}

	public static long octet2long(byte[] input, int offset) {
		long result = 0;
		for (int i = 0; i < 8; i++) {
			if (i + offset < input.length) {
				result |= (((long)input[i + offset]) & 0xffL) << ((7 - i) * 8);
			}
		}
		return result;
	}

	public static int quad2int(byte[] data, int offset,
		boolean littleEndian) {
		int result = 0;
		if (littleEndian) {
			result += (data[offset + 0] & 0xff);
			result += (data[offset + 1] & 0xff) << 8;
			result += (data[offset + 2] & 0xff) << 16;
			result += (data[offset + 3] & 0xff) << 24;
		}
		else {
			result += (data[offset + 3] & 0xff);
			result += (data[offset + 2] & 0xff) << 8;
			result += (data[offset + 1] & 0xff) << 16;
			result += (data[offset + 0] & 0xff) << 24;
		}
		return result;
	}

	public static short pair2short(byte[] data, int offset,
		boolean littleEndian) {
		short result = 0;
		if (littleEndian) {
			result += (data[offset + 0] & 0xff);
			result += (data[offset + 1] & 0xff) << 8;
		}
		else {
			result += (data[offset + 1] & 0xff);
			result += (data[offset + 0] & 0xff) << 8;
		}
		return result;
	}

	public int getInt() throws Krb4Exception {
		if (!endianessSet)
			throw new Krb4Exception(Krb4.REP_ORDER_UNKNOWN);
		byte[] temp = getBytes(4);
		return quad2int(temp, 0, littleEndian);
	}

	public int getShort() throws Krb4Exception {
		if (!endianessSet)
			throw new Krb4Exception(Krb4.REP_ORDER_UNKNOWN);
		byte[] temp = getBytes(2);
		return pair2short(temp, 0, littleEndian) & 0xffff;
	}

	public String getString() throws Krb4Exception {
		if (offset >= data.length)
			throw new Krb4Exception(Krb4.REP_OVERRUN);
		StringBuffer result = new StringBuffer();
		int len = 0;
		while (true) {
			if (offset >= data.length || len > Krb4.NAME_SZ)
				throw new Krb4Exception(Krb4.REP_OVERRUN);
			if (data[offset] == 0)
				break;
			result.append((char)data[offset]);
			offset++;
			len++;
		}
		offset++;
		return result.toString();
	}

	public int getUnsignedByte() throws Krb4Exception {
		if (offset >= data.length)
			throw new Krb4Exception(Krb4.REP_OVERRUN);
		int result = data[offset] & 0xff;
		offset++;
		return result;
	}

	public static byte[] toBytes(String str) throws Krb4Exception {
		if (str.length() > Krb4.NAME_SZ - 1)
			throw new Krb4Exception(Krb4.REP_OVERRUN);
		int len = 0;
		for (len = 0; len < str.length(); len++)
			if (str.charAt(len) == 0)
				break;
		byte[] temp = new byte[len + 1];
		str.getBytes(0, len, temp, 0);
		return temp;
	}

	public static byte[] toBytes(int data) {
		byte[] temp = new byte[4];
		temp[0] = (byte)(data & 0xff);
		temp[1] = (byte)((data >>> 8) & 0xff);
		temp[2] = (byte)((data >>> 16) & 0xff);
		temp[3] = (byte)((data >>> 24) & 0xff);
		return temp;
	}

	public static byte[] toBytes(int data, boolean littleEndian) {
		byte[] temp = new byte[4];
		if (littleEndian) {
			temp[0] = (byte)(data & 0xff);
			temp[1] = (byte)((data >>> 8) & 0xff);
			temp[2] = (byte)((data >>> 16) & 0xff);
			temp[3] = (byte)((data >>> 24) & 0xff);
		}
		else {
			temp[3] = (byte)(data & 0xff);
			temp[2] = (byte)((data >>> 8) & 0xff);
			temp[1] = (byte)((data >>> 16) & 0xff);
			temp[0] = (byte)((data >>> 24) & 0xff);
		}
		return temp;
	}

}



