// (c) Copyright 2000 Justin F. Chapweske
// (c) Copyright 2000 Ry4an C. Brase
package com.onionnetworks.util;
import java.util.*;
import java.lang.reflect.*;
public class Util {
private static final int MAX_ZERO_COPY = 16384;
private static byte[] zeroBytes;
private static char[] zeroChars;
private static char[] hexDigit = new char[]
{'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
// Must be global for shuffle
public static final Random rand = new Random();
public static final byte[] getBytes(int i) {
byte[] b = new byte[4];
b[0] = (byte) ((i >>> 24) & 0xFF);
b[1] = (byte) ((i >>> 16) & 0xFF);
b[2] = (byte) ((i >>> 8) & 0xFF);
b[3] = (byte) ((i >>> 0) & 0xFF);
return b;
}
public static final int getInt(byte[] b) {
return (((b[0]&0xFF) << 24) | ((b[1]&0xFF) << 16)
| ((b[2]&0xFF) << 8) | (b[3]&0xFF));
}
/**
* Fills in a range of an array with 0's.
*
* This method is meant to be a clone of the functionality of the C
* bzero function.
*
* @param b The byte array to be 0'd
* @param off The offset within b to begin 0'ing
* @param len The number of bytes to be 0'd
*/
public static final void bzero(byte[] b, int off, int len) {
if (zeroBytes == null) {
zeroBytes = new byte[64];
}
if (len < zeroBytes.length) {
System.arraycopy(zeroBytes,0,b,off,len);
return;
} else {
System.arraycopy(zeroBytes,0,b,off,zeroBytes.length);
}
int zeroLength = zeroBytes.length;
do {
int delta = len-zeroLength;
int copyLength = zeroLength > delta ? delta : zeroLength;
if (copyLength > MAX_ZERO_COPY) {
copyLength = MAX_ZERO_COPY;
}
// We copy from close to the current position so we aren't
// thrashing mem for really large buffers.
System.arraycopy(b,off+zeroLength-copyLength,b,off+zeroLength,
copyLength);
zeroLength+=copyLength;
} while(zeroLength < len);
}
/**
* Fills in a range of an array with 0's.
*
* This method is meant to be a clone of the functionality of the C
* bzero function.
*
* @param b The char array to be 0'd
* @param off The offset within b to begin 0'ing
* @param len The number of chars to be 0'd
*/
public static final void bzero(char[] b, int off, int len) {
if (zeroChars == null) {
zeroChars = new char[64];
}
if (len < zeroChars.length) {
System.arraycopy(zeroChars,0,b,off,len);
return;
} else {
System.arraycopy(zeroChars,0,b,off,zeroChars.length);
}
int zeroLength = zeroChars.length;
do {
int delta = len-zeroLength;
int copyLength = zeroLength > delta ? delta : zeroLength;
if (copyLength > MAX_ZERO_COPY) {
copyLength = MAX_ZERO_COPY;
}
// We copy from close to the current position so we aren't
// thrashing mem for really large buffers.
System.arraycopy(b,off+zeroLength-copyLength,b,off+zeroLength,
copyLength);
zeroLength+=copyLength;
} while(zeroLength < len);
}
public static final String getSpaces(int num) {
StringBuffer sb = new StringBuffer();
for (int i=0;i<num;i++) {
sb.append(" ");
}
return sb.toString();
}
public static boolean arraysEqual(int[] arr1, int start1,
int[] arr2, int start2, int len) {
if (arr1 == arr2 && start1 == start2) {
return true;
}
for (int i=len-1;i>=0;i--) {
if (arr1[start1+i] != arr2[start2+i]) {
return false;
}
}
return true;
}
public static boolean arraysEqual(long[] arr1, int start1,
long[] arr2, int start2, int len) {
if (arr1 == arr2 && start1 == start2) {
return true;
}
for (int i=len-1;i>=0;i--) {
if (arr1[start1+i] != arr2[start2+i]) {
return false;
}
}
return true;
}
public static boolean arraysEqual(char[] arr1, int start1,
char[] arr2, int start2, int len) {
if (arr1 == arr2 && start1 == start2) {
return true;
}
for (int i=len-1;i>=0;i--) {
if (arr1[start1+i] != arr2[start2+i]) {
return false;
}
}
return true;
}
public static boolean arraysEqual(byte[] arr1, int start1,
byte[] arr2, int start2, int len) {
if (arr1 == arr2 && start1 == start2) {
return true;
}
for (int i=len-1;i>=0;i--) {
if (arr1[start1+i] != arr2[start2+i]) {
return false;
}
}
return true;
}
/**
* Fisher-Yates shuffle.
*/
public static final void shuffle(int[] list) {
for (int i = list.length-1; i >= 0; i--) {
int j = rand.nextInt(i+1);
if (i == j) {
continue;
}
int tmp = list[i];
list[i] = list[j];
list[j] = tmp;
}
}
public static final void shuffle(boolean[] list) {
for (int i = list.length-1; i >= 0; i--) {
int j = rand.nextInt(i+1);
if (i == j) {
continue;
}
boolean tmp = list[i];
list[i] = list[j];
list[j] = tmp;
}
}
public static final void shuffle(Object[] list) {
for (int i = list.length-1; i >= 0; i--) {
int j = rand.nextInt(i+1);
if (i == j) {
continue;
}
Object tmp = list[i];
list[i] = list[j];
list[j] = tmp;
}
}
public static final byte[] getBytes(char[] chars) {
byte[] retval = new byte[chars.length*2];
arraycopy(chars,0,retval,0,retval.length);
return retval;
}
public static final char[] getChars(byte[] bytes) {
int len = bytes.length;
if (len % 2 != 0) {
throw new IllegalArgumentException("Input array.length non-even.");
}
char[] retval = new char[len/2];
arraycopy(bytes,0,retval,0,len);
return retval;
}
public static final void arraycopy(char[] chars, int charOff,
byte[] bytes, int byteOff,
int numBytes) {
int indexCounter = byteOff;
int loopMax = numBytes/2+charOff;
for (int i=charOff; i<loopMax; i++) {
bytes[indexCounter++] = (byte)((chars[i] & 0xFF00) >> 8);
bytes[indexCounter++] = (byte)(chars[i] & 0xFF);
}
// copy the straggler, if any.
if (numBytes % 2 != 0) {
bytes[indexCounter] = (byte)((chars[loopMax] & 0xFF00) >> 8);
}
}
/** Dumps a byte array to an UNIX style hex dump. This isn't terribly
* efficient so you should probably try to limit it to debug code.
* @param byte[] the byte to dump
*/
public static String getHexDump(byte[] b) {
int pos = 0;
final int INDEX_WIDTH = 7;
final String ZEROS = "0000000"; // must be at least INDEX_WIDTH length
StringBuffer sb = new StringBuffer();
while (pos < b.length) {
if ((pos % 16) == 0) {
if (pos > 0) {
sb.append("\n");
}
String index = Integer.toOctalString(pos);
sb.append(ZEROS.substring(0,INDEX_WIDTH-index.length()));
sb.append(index).append(" ");
} else if ((pos % 4) == 0) {
sb.append(" ");
}
String val = Integer.toHexString(b[pos] & 0xFF);
if (val.length() == 1) {
sb.append("0");
}
sb.append(val);
pos++;
}
return sb.toString();
}
public static final void arraycopy(byte[] bytes, int byteOff,
char[] chars, int charOff,
int numBytes) {
int indexCounter = byteOff;
int loopMax = numBytes/2+charOff;
for (int i=charOff; i<loopMax; i++) {
chars[i] = (char)(((bytes[indexCounter++]&0xFF)<<8)
| (bytes[indexCounter++]&0xFF));
}
// copy the straggler, if any.
if (numBytes % 2 != 0) {
chars[loopMax] = (char)((bytes[indexCounter]&0xFF)<<8);
}
}
/**
* Divides and rounds up on remainder
*/
public static int divideCeil(int num, int denom) {
return num/denom + ((num%denom==0)?0:1);
}
public static int divideCeil(long num, long denom) {
return (int) (num/denom + ((num%denom==0)?0:1));
}
/**
* @param a The number take take the log base 2 of.
* @return the log base 2 of the supplied number.
*/
public static double log2(double a) {
return Math.log(a)/Math.log(2);
}
public static String bytesToHex(Buffer b) {
return bytesToHex(b.b,b.off,b.len);
}
public static String bytesToHex(byte[] in) {
return bytesToHex(in,0,in.length);
}
/** Turn a byte array into a lowercase hex string
*/
public static String bytesToHex(byte[] in, int off, int len) {
char[] out = new char[in.length * 2];
for (int i = 0; i < len; i++) {
out[i*2] = hexDigit[(0xF0 & in[i+off]) >> 4]; // high nybble
out[i*2+1] = hexDigit[0xF & in[i+off]]; // low nybble
}
return new String(out);
}
/** Create a byte array from a hex string
*/
public static byte[] hexToBytes(String in) {
int len = in.length();
if (len % 2 != 0) {
throw new IllegalArgumentException("Even length string expected.");
}
byte[] out = new byte[len/2];
try {
for (int i = 0; i < out.length; i++) {
out[i] = (byte)(Integer.parseInt(in.substring(i*2, i*2+2), 16));
}
} catch (NumberFormatException doh) {
doh.printStackTrace();
throw new IllegalArgumentException("ParseError");
}
return out;
}
/** Check if an IP address is probably inside a NAT. Data culled from
* RFC 790.
* @param byte[] the 4 byte long IP address to check
* @return true if the address is probably inside a NAT
*/
public static boolean isProbablyNat(byte[] addr) {
if (addr.length != 4) {
throw new IllegalArgumentException("Address must be 4 bytes long");
}
int a = 0xFF & addr[0];
int b = 0xFF & addr[1];
int c = 0xFF & addr[2];
int d = 0xFF & addr[3];
return ((a == 10)
|| (a==192 && b==168)
|| (a==192 && b==0 && c==1)
|| (a==223 && b==255 && c==255));
}
/**
* Class.getMethod requires exact parameters for the types. This
* method is more fuzzy and just finds the first one that works. This
* class will also prefer public classes/methods.
*/
public static final Method getPublicMethod(Class clazz, String name,
Class[] types)
throws NoSuchMethodException {
Class c = clazz;
while (c != null) {
if (Modifier.isPublic(c.getModifiers())) {
Method m = getMethod(c.getMethods(),name,types);
if (m != null) {
return m;
}
}
// check the interfaces.
Class[] interfs = clazz.getInterfaces();
for (int a=0;a<interfs.length;a++) {
if (!Modifier.isPublic(interfs[a].getModifiers())) {
continue;
}
Method m = getMethod(interfs[a].getMethods(),name,types);
if (m != null) {
return m;
}
}
// climb up the superclass chain.
c = c.getSuperclass();
}
throw new NoSuchMethodException();
}
/**
* @return a public method that matches the signature, null if none match.
*/
public static final Method getMethod(Method[] methods, String name,
Class[] types) {
for (int i=0;i<methods.length;i++) {
if (Modifier.isPublic(methods[i].getModifiers()) &&
name.equals(methods[i].getName()) &&
types.length == methods[i].getParameterTypes().length) {
if (types.length == 0) {
return methods[i];
}
for (int j=0;j<types.length;j++) {
if (!methods[i].getParameterTypes()[j].
isAssignableFrom(types[j])) {
break;
} else if (j == types.length-1) {
return methods[i];
}
}
}
}
return null;
}
/**
* Creates an IntIterator from an Iterator containing Integer objects.
*/
public static final IntIterator createIntIterator(final Iterator it) {
return new IntIterator() {
public boolean hasNextInt() {
return it.hasNext();
}
public int nextInt() {
return ((Integer) it.next()).intValue();
}
public void removeInt() {
it.remove();
}
};
}
}