package x10.sncode;
public class ByteBuffer {
private byte[] buf;
private int offset;
private int buflen;
public ByteBuffer(byte[] buf) {
this.buf = buf;
this.offset = 0;
this.buflen = buf.length;
}
public ByteBuffer() {
this(64);
}
public ByteBuffer(int size) {
this.buf = new byte[size];
this.offset = 0;
this.buflen = 0;
}
public String toString() {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < buflen; i++) {
byte b = buf[i];
if (b == '\\')
sb.append("\\\\");
else if (Character.isWhitespace((char) b) || (b >= 33 && b <= 126))
sb.append((char) b);
else {
sb.append("\\x");
String x = Integer.toHexString(b & 0xff);
for (int j = x.length(); j < 2; j++)
sb.append("0");
sb.append(x);
}
}
return sb.toString();
}
public int offset() {
return offset;
}
void skip(int n) {
this.offset += n;
}
public void seek(int n) {
this.offset = n;
}
void reserve(int size) {
if (buf == null) {
buf = new byte[size];
} else if (size > buf.length) {
byte[] newBuf = new byte[Math.max(buf.length * 2, size)];
System.arraycopy(buf, 0, newBuf, 0, buf.length);
buf = newBuf;
}
}
/**
* Set the 4 bytes at offset 'offset' in 'buf' to the signed 32-bit value in
* v.
*/
public void addInt(int v) {
setInt(offset, v);
offset += 4;
}
/**
* Set the 4 bytes at offset 'offset' in 'buf' to the signed 32-bit value in
* v.
*/
void setInt(int offset, int v) {
reserve(offset + 4);
buf[offset++] = (byte) (v >> 24);
buf[offset++] = (byte) (v >> 16);
buf[offset++] = (byte) (v >> 8);
buf[offset++] = (byte) v;
buflen = Math.max(offset, buflen);
}
void setLong(int offset, long v) {
reserve(offset + 8);
setInt(offset, (int) (v >> 32));
setInt(offset + 4, (int) v);
}
/**
* Set the 8 bytes at offset 'offset' in 'buf' to the signed 64-bit value in
* v.
*/
public void addLong(long v) {
setLong(offset, v);
offset += 8;
}
/**
* Set the 4 bytes at offset 'offset' in 'buf' to the float value in v.
*/
public void addFloat(float v) {
addInt(Float.floatToIntBits(v));
}
/**
* Set the 4 bytes at offset 'offset' in 'buf' to the float value in v.
*/
public void setFloat(int offset, float v) {
setInt(offset, Float.floatToIntBits(v));
}
/**
* Set the 8 bytes at offset 'offset' in 'buf' to the double value in v.
*/
public void addDouble(double v) throws IllegalArgumentException {
addLong(Double.doubleToRawLongBits(v));
}
/**
* Set the 8 bytes at offset 'offset' in 'buf' to the double value in v.
*/
public void setDouble(int offset, double v) throws IllegalArgumentException {
setLong(offset, Double.doubleToRawLongBits(v));
}
/**
* Set the 2 bytes at offset 'offset' in 'buf' to the unsigned 16-bit value
* in v.
*
* @throws IllegalArgumentException
* if buf is null
*/
public void setUShort(int offset, int v) throws IllegalArgumentException {
reserve(offset + 2);
buf[offset++] = (byte) (v >> 8);
buf[offset++] = (byte) v;
buflen = Math.max(offset, buflen);
}
/**
* Set the 2 bytes at offset 'offset' in 'buf' to the unsigned 16-bit value
* in v.
*
* @throws IllegalArgumentException
* if buf is null
*/
public void addUShort(int v) throws IllegalArgumentException {
setUShort(offset, v);
offset += 2;
}
/**
* Set the 2 bytes at offset 'offset' in 'buf' to the unsigned 16-bit value
* in v.
*
* @throws IllegalArgumentException
* if buf is null
*/
public void setUByte(int offset, int v) throws IllegalArgumentException {
reserve(offset + 1);
buf[offset++] = (byte) v;
buflen = Math.max(offset, buflen);
}
/**
* Set the 2 bytes at offset 'offset' in 'buf' to the unsigned 16-bit value
* in v.
*
* @throws IllegalArgumentException
* if buf is null
*/
public void addUByte(int v) {
setUByte(offset, v);
offset++;
}
public byte[] getBytes() {
if (buf.length == buflen) {
return buf;
} else {
byte[] b = new byte[buflen];
System.arraycopy(buf, 0, b, 0, buflen);
return b;
}
}
public byte[] getBytes(int i, int len) throws InvalidClassFileException {
if (i < 0 || i + len > buflen)
throw new InvalidClassFileException(i, "cannot get raw bytes");
byte[] b = new byte[len];
System.arraycopy(buf, i, b, 0, len);
return b;
}
public void addBytes(byte[] bytes) {
reserve(offset + bytes.length);
System.arraycopy(bytes, 0, buf, offset, bytes.length);
offset += bytes.length;
buflen = Math.max(offset, buflen);
}
public void setBytes(int offset, byte[] bytes) {
reserve(offset + bytes.length);
System.arraycopy(bytes, 0, buf, offset, bytes.length);
buflen = Math.max(offset, buflen);
}
public void addBytes(byte[] bytes, int boff, int blen) {
reserve(offset + blen);
System.arraycopy(bytes, boff, buf, offset, blen);
offset += blen;
buflen = Math.max(offset, buflen);
}
public void setBytes(int offset, byte[] bytes, int boff, int blen) {
reserve(offset + blen);
System.arraycopy(bytes, boff, buf, offset, blen);
buflen = Math.max(offset, buflen);
}
/**
* Set the 2 bytes at offset 'offset' in 'buf' to the unsigned 16-bit value
* in v.
*
* @throws IllegalArgumentException
* if buf is null
*/
public void setByte(int offset, int v) throws IllegalArgumentException {
setUByte(offset, v);
}
/**
* Set the 2 bytes at offset 'offset' in 'buf' to the unsigned 16-bit value
* in v.
*
* @throws IllegalArgumentException
* if buf is null
*/
public void addByte(int v) {
addUByte(v);
}
public void checkLength(int size) throws InvalidClassFileException {
if (size > buflen || size > buf.length)
throw new InvalidClassFileException(size, "Out of range.");
}
public long getLong() throws InvalidClassFileException {
long result = getLong(offset);
offset += 8;
return result;
}
public int getInt() throws InvalidClassFileException {
int result = getInt(offset);
offset += 4;
return result;
}
public float getFloat() throws InvalidClassFileException {
int result = getInt();
return Float.intBitsToFloat(result);
}
public float getFloat(int offset) throws InvalidClassFileException {
int result = getInt(offset);
return Float.intBitsToFloat(result);
}
public double getDouble() throws InvalidClassFileException {
long result = getLong();
return Double.longBitsToDouble(result);
}
public double getDouble(int offset) throws InvalidClassFileException {
long result = getLong(offset);
return Double.longBitsToDouble(result);
}
/**
* @return the signed 32-bit value at offset i in the class data
* @throws InvalidClassFileException
*/
public int getInt(int offset) throws InvalidClassFileException {
checkLength(offset + 4);
return (buf[offset] << 24) + ((buf[offset + 1] & 0xFF) << 16)
+ ((buf[offset + 2] & 0xFF) << 8) + (buf[offset + 3] & 0xFF);
}
/**
* @return the signed 64-bit value at offset i in the class data
* @throws InvalidClassFileException
*/
public long getLong(int offset) throws InvalidClassFileException {
checkLength(offset + 8);
int r1 = getInt(offset);
int r2 = getInt(offset + 4);
return ((long) r1 << 32) | (r2 & 0xFFFFFFFFL);
}
public String getUtf8() throws InvalidClassFileException {
int count = getInt(offset);
String s = getUtf8(offset + 4, count);
offset += 4;
offset += count;
return s;
}
public String getUtf8(int offset) throws InvalidClassFileException {
int count = getInt(offset);
return getUtf8(offset + 4, count);
}
private InvalidClassFileException invalidUtf8(int offset) {
return new InvalidClassFileException(offset,
"Invalid Java Utf8 string.");
}
/**
* @return the value of the Utf8 string at constant pool item i
*/
private String getUtf8(int offset, int count)
throws InvalidClassFileException {
int end = count + offset;
StringBuilder buf = new StringBuilder(count);
offset += 4;
while (offset < end) {
byte x = getByte(offset);
if ((x & 0x80) == 0) {
if (x == 0) {
throw invalidUtf8(offset);
}
buf.append((char) x);
offset++;
} else if ((x & 0xE0) == 0xC0) {
if (offset + 1 >= end) {
throw invalidUtf8(offset);
}
byte y = getByte(offset + 1);
if ((y & 0xC0) != 0x80) {
throw invalidUtf8(offset);
}
buf.append((char) (((x & 0x1F) << 6) + (y & 0x3F)));
offset += 2;
} else if ((x & 0xF0) == 0xE0) {
if (offset + 2 >= end) {
throw invalidUtf8(offset);
}
byte y = getByte(offset + 1);
byte z = getByte(offset + 2);
if ((y & 0xC0) != 0x80 || (z & 0xC0) != 0x80) {
throw invalidUtf8(offset);
}
buf
.append((char) (((x & 0x0F) << 12) + ((y & 0x3F) << 6) + (z & 0x3F)));
offset += 3;
} else {
throw invalidUtf8(offset);
}
}
return buf.toString();
}
public String getUtf8ToDelimiter(int offset, String delims)
throws InvalidClassFileException {
int i = offset();
String s = getUtf8ToDelimiter(delims);
seek(i);
return s;
}
public String getUtf8ToDelimiter(String delims)
throws InvalidClassFileException {
StringBuilder buf = new StringBuilder();
while (offset < buflen && offset < this.buf.length) {
byte x = getByte(offset);
if ((x & 0x80) == 0) {
if (x == 0) {
throw invalidUtf8(offset);
}
buf.append((char) x);
offset++;
} else if ((x & 0xE0) == 0xC0) {
byte y = getByte(offset + 1);
if ((y & 0xC0) != 0x80) {
throw invalidUtf8(offset);
}
buf.append((char) (((x & 0x1F) << 6) + (y & 0x3F)));
offset += 2;
} else if ((x & 0xF0) == 0xE0) {
byte y = getByte(offset + 1);
byte z = getByte(offset + 2);
if ((y & 0xC0) != 0x80 || (z & 0xC0) != 0x80) {
throw invalidUtf8(offset);
}
buf
.append((char) (((x & 0x0F) << 12) + ((y & 0x3F) << 6) + (z & 0x3F)));
offset += 3;
} else {
throw invalidUtf8(offset);
}
char c = buf.charAt(buf.length() - 1);
if (delims.indexOf(c) >= 0)
break;
}
return buf.toString();
}
public int getUShort() throws InvalidClassFileException {
int result = getUShort(offset);
offset += 2;
return result;
}
/**
* @return the unsigned 16-bit value at offset i in the class data
* @throws InvalidClassFileException
*/
public int getUShort(int offset) throws InvalidClassFileException {
checkLength(offset + 2);
return ((buf[offset] & 0xFF) << 8) + (buf[offset + 1] & 0xFF);
}
/**
* @return the signed 16-bit value at offset i in the class data
* @throws InvalidClassFileException
*/
public short getShort(int i) throws InvalidClassFileException {
checkLength(i + 2);
return (short) ((buf[i] << 8) + (buf[i + 1] & 0xFF));
}
/**
* @return the signed 8-bit value at offset i in the class data
* @throws InvalidClassFileException
*/
public byte getByte(int i) throws InvalidClassFileException {
checkLength(i + 1);
return buf[i];
}
/**
* @return the signed 8-bit value at offset i in the class data
* @throws InvalidClassFileException
*/
public byte getByte() throws InvalidClassFileException {
byte result = getByte(offset);
offset++;
return result;
}
/**
* @return the unsigned 8-bit value at offset i in the class data
* @throws InvalidClassFileException
*/
public int getUByte(int i) throws InvalidClassFileException {
checkLength(i + 1);
return buf[i] & 0xFF;
}
public void setCPIndex(int offset, int i) {
setInt(offset, i);
}
public void addCPIndex(int i) {
addInt(i);
}
public int getCPIndex(int i) throws InvalidClassFileException {
return getInt(i);
}
public int getCPIndex() throws InvalidClassFileException {
return getInt();
}
public void setLength(int offset, int i) {
setInt(offset, i);
}
public void addLength(int i) {
addInt(i);
}
public int getLength(int i) throws InvalidClassFileException {
return getInt(i);
}
public int getLength() throws InvalidClassFileException {
return getInt();
}
public void setCount(int offset, int i) {
setInt(offset, i);
}
public void addCount(int i) {
addInt(i);
}
public int getCount(int i) throws InvalidClassFileException {
return getInt(i);
}
public int getCount() throws InvalidClassFileException {
return getInt();
}
public void getAttributeOffsets(int[] offsets)
throws InvalidClassFileException {
int count = offsets.length - 1;
for (int i = 0; i < count; i++) {
offsets[i] = offset();
int nameIndex = getCPIndex(); // unused
int payloadLen = getLength();
if (payloadLen < 0) {
throw new InvalidClassFileException(offset(),
"negative attribute length: " + payloadLen);
}
skip(payloadLen);
}
offsets[count] = offset();
}
}