package com.limegroup.gnutella;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/**
* Various static routines for solving endian problems.
*/
public class ByteOrder {
/**
* Returns the reverse of x.
*/
public static byte[] reverse(final byte[] x) {
int i, j;
final int n;
if ((n = x.length) > 0) {
final byte[] ret = new byte[n];
for (i = 0, j = n - 1; j >= 0;)
ret[i++] = x[j--];
return ret;
}
return x;
}
/**
* Little-endian bytes to short.
*
* @requires x.length - offset >= 2
* @effects returns the value of x[offset .. offset + 2] as a short,
* assuming x is interpreted as a signed little-endian number (i.e.,
* x[offset] is LSB). If you want to interpret it as an unsigned number,
* call ubytes2int() on the result.
*/
public static short leb2short(final byte[] x, final int offset) {
return (short)((x[offset ] & 0xFF) |
(x[offset + 1] << 8));
}
/**
* Big-endian bytes to short.
*
* @requires x.length - offset >= 2
* @effects returns the value of x[offset .. offset + 2] as a short,
* assuming x is interpreted as a signed big-endian number (i.e.,
* x[offset] is MSB). If you want to interpret it as an unsigned number,
* call ubytes2int() on the result.
*/
public static short beb2short(final byte[] x, final int offset) {
return (short)((x[offset ] << 8) |
(x[offset + 1] & 0xFF));
}
/**
* Little-endian bytes to short - stream version.
*/
public static short leb2short(final InputStream is) throws IOException {
return (short)((is.read() & 0xFF) |
(is.read() << 8));
}
/**
* Big-endian bytes to short - stream version.
*/
public static short beb2short(final InputStream is) throws IOException {
return (short)((is.read() << 8) |
(is.read() & 0xFF));
}
/**
* Little-endian bytes to int.
*
* @requires x.length - offset >= 4
* @effects returns the value of x[offset .. offset + 4] as an int,
* assuming x is interpreted as a signed little-endian number (i.e.,
* x[offset] is LSB) If you want to interpret it as an unsigned number,
* call ubytes2long() on the result.
*/
public static int leb2int(final byte[] x, final int offset) {
return ( x[offset ] & 0xFF ) |
((x[offset + 1] & 0xFF) << 8) |
((x[offset + 2] & 0xFF) << 16) |
( x[offset + 3] << 24);
}
/**
* Big-endian bytes to int.
*
* @requires x.length - offset >= 4
* @effects returns the value of x[offset .. offset + 4] as an int,
* assuming x is interpreted as a signed big-endian number (i.e.,
* x[offset] is MSB) If you want to interpret it as an unsigned number,
* call ubytes2long() on the result.
*/
public static int beb2int(final byte[] x, final int offset) {
return ( x[offset ] << 24) |
((x[offset + 1] & 0xFF) << 16) |
((x[offset + 2] & 0xFF) << 8) |
( x[offset + 3] & 0xFF );
}
/**
* Little-endian bytes to int - stream version.
*/
public static int leb2int(final InputStream is) throws IOException{
return ( is.read() & 0xFF ) |
((is.read() & 0xFF) << 8) |
((is.read() & 0xFF) << 16) |
( is.read() << 24);
}
/**
* Big-endian bytes to int - stream version.
*/
public static int beb2int(final InputStream is) throws IOException{
return ( is.read() << 24) |
((is.read() & 0xFF) << 16) |
((is.read() & 0xFF) << 8) |
( is.read() & 0xFF );
}
/**
* Little-endian bytes to int. Unlike leb2int(x, offset), this version can
* read fewer than 4 bytes. If n < 4, the returned value is never negative.
*
* @param x the source of the bytes
* @param offset the index to start reading bytes
* @param n the number of bytes to read, which must be between 1 and 4,
* inclusive
* @return the value of x[offset .. offset + N] as an int, assuming x is
* interpreted as an unsigned little-endian number (i.e., x[offset] is LSB).
* @exception IllegalArgumentException if n is less than 1 or greater than 4
* @exception IndexOutOfBoundsException if offset < 0 or
* offset + n > x.length
*/
public static int leb2int(final byte[] x, final int offset, final int n)
throws IndexOutOfBoundsException, IllegalArgumentException {
switch (n) {
case 1:
return x[offset ] & 0xFF ;
case 2:
return ( x[offset ] & 0xFF ) |
((x[offset + 1] & 0xFF) << 8);
case 3:
return ( x[offset ] & 0xFF ) |
((x[offset + 1] & 0xFF) << 8) |
((x[offset + 2] & 0xFF) << 16);
case 4:
return ( x[offset ] & 0xFF ) |
((x[offset + 1] & 0xFF) << 8) |
((x[offset + 2] & 0xFF) << 16) |
( x[offset + 3] << 24);
default:
throw new IllegalArgumentException("No bytes specified");
}
}
/**
* Little-endian bytes to long. This version can
* read fewer than 8 bytes. If n < 8, the returned value is never negative.
*
* @param x the source of the bytes
* @param offset the index to start reading bytes
* @param n the number of bytes to read, which must be between 1 and 8,
* inclusive
* @return the value of x[offset .. offset + N] as an int, assuming x is
* interpreted as an unsigned little-endian number (i.e., x[offset] is LSB).
* @exception IllegalArgumentException if n is less than 1 or greater than 8
* @exception IndexOutOfBoundsException if offset < 0 or
* offset + n > x.length
*/
public static long leb2long(final byte[] x, final int offset, final int n)
throws IndexOutOfBoundsException, IllegalArgumentException {
switch (n) {
case 1:
return x[offset ] & 0xFFL ;
case 2:
return ( x[offset ] & 0xFFL ) |
((x[offset + 1] & 0xFFL) << 8);
case 3:
return ( x[offset ] & 0xFFL ) |
((x[offset + 1] & 0xFFL) << 8) |
((x[offset + 2] & 0xFFL) << 16);
case 4:
return ( x[offset ] & 0xFFL ) |
((x[offset + 1] & 0xFFL) << 8) |
((x[offset + 2] & 0xFFL) << 16) |
((x[offset + 3] & 0xFFL) << 24);
case 5:
return ( x[offset ] & 0xFFL ) |
((x[offset + 1] & 0xFFL) << 8) |
((x[offset + 2] & 0xFFL) << 16) |
((x[offset + 3] & 0xFFL) << 24) |
((x[offset + 4] & 0xFFL) << 32);
case 6:
return ( x[offset ] & 0xFFL ) |
((x[offset + 1] & 0xFFL) << 8) |
((x[offset + 2] & 0xFFL) << 16) |
((x[offset + 3] & 0xFFL) << 24) |
((x[offset + 4] & 0xFFL) << 32) |
((x[offset + 5] & 0xFFL) << 40);
case 7:
return ( x[offset ] & 0xFFL ) |
((x[offset + 1] & 0xFFL) << 8) |
((x[offset + 2] & 0xFFL) << 16) |
((x[offset + 3] & 0xFFL) << 24) |
((x[offset + 4] & 0xFFL) << 32) |
((x[offset + 5] & 0xFFL) << 40) |
((x[offset + 6] & 0xFFL) << 48);
case 8:
return ( x[offset ] & 0xFFL ) |
((x[offset + 1] & 0xFFL) << 8) |
((x[offset + 2] & 0xFFL) << 16) |
((x[offset + 3] & 0xFFL) << 24) |
((x[offset + 4] & 0xFFL) << 32) |
((x[offset + 5] & 0xFFL) << 40) |
((x[offset + 6] & 0xFFL) << 48) |
( (long)x[offset + 7] << 56);
default:
throw new IllegalArgumentException("No bytes specified");
}
}
/**
* Little-endian bytes to long. Stream version.
*/
public static long leb2long(InputStream is) throws IOException {
return ( is.read() & 0xFFL ) |
((is.read() & 0xFFL) << 8) |
((is.read() & 0xFFL) << 16) |
((is.read() & 0xFFL) << 24) |
((is.read() & 0xFFL) << 32) |
((is.read() & 0xFFL) << 40) |
((is.read() & 0xFFL) << 48) |
( is.read() << 56);
}
/**
* Big-endian bytes to long. Unlike beb2long(x, offset), this version can
* read fewer than 4 bytes. If n < 4, the returned value is never negative.
*
* @param x the source of the bytes
* @param offset the index to start reading bytes
* @param n the number of bytes to read, which must be between 1 and 4,
* inclusive
* @return the value of x[offset .. offset + N] as an int, assuming x is
* interpreted as an unsigned big-endian number (i.e., x[offset] is MSB).
* @exception IllegalArgumentException if n is less than 1 or greater than 4
* @exception IndexOutOfBoundsException if offset < 0 or
* offset + n > x.length
*/
public static int beb2int(final byte[] x, final int offset, final int n)
throws IndexOutOfBoundsException, IllegalArgumentException {
switch (n) {
case 1:
return x[offset ] & 0xFF ;
case 2:
return ((x[offset ] & 0xFF) << 8) |
( x[offset + 1] & 0xFF );
case 3:
return ((x[offset ] & 0xFF) << 16) |
((x[offset + 1] & 0xFF) << 8) |
( x[offset + 2] & 0xFF );
case 4:
return ( x[offset ] << 24) |
((x[offset + 1] & 0xFF) << 16) |
((x[offset + 2] & 0xFF) << 8) |
( x[offset + 3] & 0xFF );
default:
throw new IllegalArgumentException("No bytes specified");
}
}
/**
* Short to little-endian bytes: writes x to buf[offset .. ].
*/
public static void short2leb(final short x,
final byte[] buf, final int offset) {
buf[offset ] = (byte) x ;
buf[offset + 1] = (byte)(x >> 8);
}
/**
* Short to big-endian bytes: writes x to buf[offset .. ].
*/
public static void short2beb(final short x,
final byte[] buf, final int offset) {
buf[offset ] = (byte)(x >> 8);
buf[offset + 1] = (byte) x ;
}
/**
* Short to little-endian bytes: writes x to given stream.
*/
public static void short2leb(final short x, final OutputStream os)
throws IOException {
os.write((byte) x );
os.write((byte)(x >> 8));
}
/**
* Short to big-endian bytes: writes x to given stream.
*/
public static void short2beb(final short x, final OutputStream os)
throws IOException {
os.write((byte)(x >> 8));
os.write((byte) x );
}
/**
* Int to little-endian bytes: writes x to buf[offset ..].
*/
public static void int2leb(final int x,
final byte[] buf, final int offset) {
buf[offset ] = (byte) x ;
buf[offset + 1] = (byte)(x >> 8);
buf[offset + 2] = (byte)(x >> 16);
buf[offset + 3] = (byte)(x >> 24);
}
/**
* Long to big-endian bytes: writes x to buf[offset ..].
*/
public static void long2beb(final long x,
final byte[] buf, final int offset) {
buf[offset ] = (byte)(x >> 56);
buf[offset + 1] = (byte)(x >> 48);
buf[offset + 2] = (byte)(x >> 40);
buf[offset + 3] = (byte)(x >> 32);
buf[offset + 4] = (byte)(x >> 24);
buf[offset + 5] = (byte)(x >> 16);
buf[offset + 6] = (byte)(x >> 8);
buf[offset + 7] = (byte) x ;
}
/**
* Int to big-endian bytes: writes x to buf[offset ..].
*/
public static void int2beb(final int x,
final byte[] buf, final int offset) {
buf[offset ] = (byte)(x >> 24);
buf[offset + 1] = (byte)(x >> 16);
buf[offset + 2] = (byte)(x >> 8);
buf[offset + 3] = (byte) x ;
}
/**
* Int to big-endian bytes: writing only the up to n bytes.
*
* @requires x fits in n bytes, else the stored value will be incorrect.
* n may be larger than the value required
* to store x, in which case this will pad with 0.
*
* @param x the little-endian int to convert
* @param out the outputstream to write to.
* @param n the number of bytes to write, which must be between 1 and 4,
* inclusive
* @exception IllegalArgumentException if n is less than 1 or greater than 4
*/
public static void int2beb(final int x, OutputStream out, final int n)
throws IOException {
switch(n) {
case 1:
out.write((byte) x );
break;
case 2:
out.write((byte)(x >> 8));
out.write((byte) x );
break;
case 3:
out.write((byte)(x >> 16));
out.write((byte)(x >> 8));
out.write((byte) x );
break;
case 4:
out.write((byte)(x >> 24));
out.write((byte)(x >> 16));
out.write((byte)(x >> 8));
out.write((byte) x );
break;
default:
throw new IllegalArgumentException("invalid n: " + n);
}
}
/**
* Int to little-endian bytes: writes x to given stream.
*/
public static void int2leb(final int x, final OutputStream os)
throws IOException {
os.write((byte) x );
os.write((byte)(x >> 8));
os.write((byte)(x >> 16));
os.write((byte)(x >> 24));
}
/**
* Int to big-endian bytes: writes x to given stream.
*/
public static void int2beb(final int x, final OutputStream os)
throws IOException {
os.write((byte)(x >> 24));
os.write((byte)(x >> 16));
os.write((byte)(x >> 8));
os.write((byte) x );
}
/**
* Returns the minimum number of bytes needed to encode x in little-endian
* format, assuming x is non-negative. Note that leb2int(int2leb(x)) == x.
* @param x a non-negative integer
* @exception IllegalArgumentException x is negative
*/
public static byte[] int2minLeb(final int x)
throws IllegalArgumentException {
if (x <= 0xFFFF) {
if (x <= 0xFF) {
if (x < 0)
throw new IllegalArgumentException();
return new byte[] {(byte)x};
}
return new byte[] {(byte)x, (byte)(x >> 8)};
}
if (x <= 0xFFFFFF)
return new byte[] {(byte)x, (byte)(x >> 8), (byte)(x >> 16)};
return new byte[] {
(byte)x, (byte)(x >> 8), (byte)(x >> 16), (byte)(x >> 24)};
}
/**
* Returns the minimum number of bytes needed to encode x in little-endian
* format, assuming x is non-negative.
* @param x a non-negative integer
* @exception IllegalArgumentException x is negative
*/
public static byte[] long2minLeb(final long x)
throws IllegalArgumentException {
if(x <= 0xFFFFFFFFFFFFFFL) {
if(x <= 0xFFFFFFFFFFFFL) {
if(x <= 0xFFFFFFFFFFL) {
if(x <= 0xFFFFFFFFL) {
if(x <= 0xFFFFFFL) {
if (x <= 0xFFFFL) {
if (x <= 0xFFL) {
if (x < 0)
throw new IllegalArgumentException();
return new byte[] {(byte)x};
}
return new byte[] {(byte)x, (byte)(x >> 8)};
}
return new byte[] {(byte)x, (byte)(x >> 8),
(byte)(x >> 16)};
}
return new byte[] {
(byte)x, (byte)(x >> 8), (byte)(x >> 16),
(byte)(x >> 24)};
}
return new byte[] {
(byte)x, (byte)(x >> 8), (byte)(x >> 16),
(byte)(x >> 24), (byte)(x >> 32)};
}
return new byte[] {
(byte)x, (byte)(x >> 8), (byte)(x >> 16), (byte)(x >> 24),
(byte)(x >> 32), (byte)(x >> 40)};
}
return new byte[] {
(byte)x, (byte)(x >> 8), (byte)(x >> 16), (byte)(x >> 24),
(byte)(x >> 32), (byte)(x >> 40), (byte)(x >> 48)};
}
return new byte[] {
(byte)x, (byte)(x >> 8), (byte)(x >> 16), (byte)(x >> 24),
(byte)(x >> 32), (byte)(x >> 40), (byte)(x >> 48),
(byte)(x >> 56)};
}
/**
* Returns the minimum number of bytes needed to encode x in big-endian
* format, assuming x is non-negative. Note that beb2int(int2beb(x)) == x.
* @param x a non-negative integer
* @exception IllegalArgumentException x is negative
*/
public static byte[] int2minBeb(final int x)
throws IllegalArgumentException {
if (x <= 0xFFFF) {
if (x <= 0xFF) {
if (x < 0)
throw new IllegalArgumentException();
return new byte[] {(byte)x};
}
return new byte[] {(byte)(x >> 8), (byte)x};
}
if (x <= 0xFFFFFF)
return new byte[] {(byte)(x >> 16), (byte)(x >> 8), (byte)x};
return new byte[] {
(byte)(x >> 24), (byte)(x >> 16), (byte)(x >> 8), (byte)x};
}
/**
* Interprets the value of x as an unsigned byte, and returns
* it as integer. For example, ubyte2int(0xFF) == 255, not -1.
*/
public static int ubyte2int(final byte x) {
return x & 0xFF;
}
/**
* Interprets the value of x as an unsigned two-byte number.
*/
public static int ushort2int(final short x) {
return x & 0xFFFF;
}
/**
* Interprets the value of x as an unsigned four-byte number.
*/
public static long uint2long(final int x) {
return x & 0xFFFFFFFFL;
}
/**
* Returns the int value that is closest to l. That is, if l can fit into a
* 32-bit unsigned number, returns (int)l. Otherwise, returns either
* Integer.MAX_VALUE or Integer.MIN_VALUE as appropriate.
*/
public static int long2int(final long l) {
int m;
if (l < (m = Integer.MAX_VALUE) &&
l > (m = Integer.MIN_VALUE))
return (int)l;
return m;
}
/**
* Big-endian bytes to long. Unlike beb2long(x, offset), this version can
* read fewer than 4 bytes. If n < 4, the returned value is never negative.
*
* @param x the source of the bytes
* @param offset the index to start reading bytes
* @param n the number of bytes to read, which must be between 1 and 4,
* inclusive
* @return the value of x[offset .. offset + N] as an int, assuming x is
* interpreted as an unsigned big-endian number (i.e., x[offset] is MSB).
* @exception IllegalArgumentException if n is less than 1 or greater than 4
* @exception IndexOutOfBoundsException if offset < 0 or
* offset + n > x.length
*/
public static long beb2long(final byte[] x, final int offset, final int n)
throws IndexOutOfBoundsException, IllegalArgumentException {
switch (n) {
case 1:
return (long) x[offset] & 0xFFL;
case 2:
return ((long) x[offset + 1] & 0xFFL)
| (((long) x[offset] & 0xFFL) << 8);
case 3:
return ((long) x[offset + 2] & 0xFFL)
| (((long) x[offset + 1] & 0xFFL) << 8)
| (((long) x[offset] & 0xFFL) << 16);
case 4:
return ((long) x[offset + 3] & 0xFFL)
| (((long) x[offset + 2] & 0xFFL) << 8)
| (((long) x[offset + 1] & 0xFFL) << 16)
| (((long) x[offset] & 0xFFL) << 24);
case 5:
return ((long) x[offset + 4] & 0xFFL)
| (((long) x[offset + 3] & 0xFFL) << 8)
| (((long) x[offset + 2] & 0xFFL) << 16)
| (((long) x[offset + 1] & 0xFFL) << 24)
| (((long) x[offset] & 0xFFL) << 32);
case 6:
return ((long) x[offset + 5] & 0xFFL)
| (((long) x[offset + 4] & 0xFFL) << 8)
| (((long) x[offset + 3] & 0xFFL) << 16)
| (((long) x[offset + 2] & 0xFFL) << 24)
| (((long) x[offset + 1] & 0xFFL) << 32)
| (((long) x[offset] & 0xFFL) << 40);
case 7:
return ((long) x[offset + 6] & 0xFFL)
| (((long) x[offset + 5] & 0xFFL) << 8)
| (((long) x[offset + 4] & 0xFFL) << 16)
| (((long) x[offset + 3] & 0xFFL) << 24)
| (((long) x[offset + 2] & 0xFFL) << 32)
| (((long) x[offset + 1] & 0xFFL) << 40)
| (((long) x[offset] & 0xFFL) << 48);
case 8:
return ((long) x[offset + 7] & 0xFFL)
| (((long) x[offset + 6] & 0xFFL) << 8)
| (((long) x[offset + 5] & 0xFFL) << 16)
| (((long) x[offset + 4] & 0xFFL) << 24)
| (((long) x[offset + 3] & 0xFFL) << 32)
| (((long) x[offset + 2] & 0xFFL) << 40)
| (((long) x[offset + 1] & 0xFFL) << 48)
| ((long) x[offset] << 56);
default:
throw new IllegalArgumentException("No bytes specified");
}
}
}