package org.ripple.power;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.URL;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Pattern;
import javax.swing.ImageIcon;
import org.ripple.power.blockchain.list.RP;
import org.ripple.power.collection.ByteArrayWrapper;
import org.ripple.power.collection.LRUMap;
import org.ripple.power.utils.ByteUtils;
import org.ripple.bouncycastle.crypto.Digest;
import org.ripple.bouncycastle.crypto.digests.RIPEMD160Digest;
import org.ripple.bouncycastle.util.encoders.Hex;
@SuppressWarnings({ "rawtypes", "unchecked" })
public class Helper {
private static final Map<Class<?>, Boolean> _customEquals = new ConcurrentHashMap<Class<?>, Boolean>();
private static final Map<Class<?>, Boolean> _customHash = new ConcurrentHashMap<Class<?>, Boolean>();
private static final Map<Class<?>, Collection<Field>> _reflectedFields = new ConcurrentHashMap<Class<?>, Collection<Field>>();
private static final int MAX_ENTRIES = 100;
private static LRUMap<ByteArrayWrapper, byte[]> sha3Cache = new LRUMap<>(0,
MAX_ENTRIES);
public static final byte[] EMPTY_DATA_HASH = sha3(ByteUtils.EMPTY_BYTE_ARRAY);
public static final byte[] EMPTY_LIST_HASH = sha3(RP.encodeList());
public static final byte[] EMPTY_TRIE_HASH = sha3(RP
.encodeElement(ByteUtils.EMPTY_BYTE_ARRAY));
private static final MessageDigest sha256digest;
private static SecureRandom random = new SecureRandom();
private static BigInteger _1000_ = new BigInteger("1000");
static {
try {
sha256digest = MessageDigest.getInstance("SHA-256");
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
private static final int KEY_SIZE_BYTES = 32;
private static final String SHA_256 = "SHA-256";
private static final String UTF8 = "UTF-8";
private static final String STATIC_SALT = "{'[R^*&843HGihp3p5l3e%g!o@t@o!mono$ ^f442Axs092aBGJZawW ]\"}";
/** Constant -1 */
public static final BigInteger NEGATIVE_ONE = BigInteger.valueOf(-1);
/** Constant 1,000 */
private static final BigInteger DISPLAY_1K = new BigInteger("1000");
/** Constant 1,000,000 */
private static final BigInteger DISPLAY_1M = new BigInteger("1000000");
/** Constant 1,000,000,000 */
private static final BigInteger DISPLAY_1G = new BigInteger("1000000000");
/** Constant 1,000,000,000,000 */
private static final BigInteger DISPLAY_1T = new BigInteger("1000000000000");
/** Constant 1,000,000,000,000,000 */
private static final BigInteger DISPLAY_1P = new BigInteger("1000000000000000");
/** Bit masks (Low-order bit is bit 0 and high-order bit is bit 7) */
private static final int bitMask[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};
/** Instance of a SHA-256 digest which we will use as needed */
private static final MessageDigest digest;
static {
try {
digest = MessageDigest.getInstance("SHA-256");
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e); // Can't happen.
}
}
public static final BigInteger COIN = new BigInteger("100000000", 10);
public static final BigInteger CENT = new BigInteger("1000000", 10);
public static byte[] singleDigest(byte[] input) {
return singleDigest(input, 0, input.length);
}
public static byte[] singleDigest(byte[] input, int offset, int length) {
byte[] bytes;
synchronized (digest) {
digest.reset();
digest.update(input, offset, length);
bytes = digest.digest();
}
return bytes;
}
public static byte[] singleDigest(List<byte[]> inputList) {
byte[] bytes;
synchronized(digest) {
digest.reset();
for(byte[] input:inputList){
digest.update(input, 0, input.length);
}
bytes = digest.digest();
}
return bytes;
}
public static byte[] doubleDigest(List<byte[]> inputList) {
byte[] bytes;
synchronized(digest) {
digest.reset();
for(byte[] input:inputList){
digest.update(input, 0, input.length);
}
byte[] first = digest.digest();
bytes = digest.digest(first);
}
return bytes;
}
public static byte[] doubleDigestTwoBuffers(byte[]input1, int offset1, int length1,
byte[]input2, int offset2, int length2) {
byte[] bytes;
synchronized (digest) {
digest.reset();
digest.update(input1, offset1, length1);
digest.update(input2, offset2, length2);
byte[]first = digest.digest();
bytes = digest.digest(first);
}
return bytes;
}
public static byte[] sha1Hash(byte[] input) {
byte[] out;
try {
MessageDigest sDigest = MessageDigest.getInstance("SHA-1");
out = sDigest.digest(input);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
return out;
}
public static byte[] hash160(byte[] input) {
byte[] out = new byte[20];
RIPEMD160Digest rDigest = new RIPEMD160Digest();
rDigest.update(input, 0, input.length);
rDigest.doFinal(out, 0);
return out;
}
public static byte[] sha256Hash160(byte[] input) {
byte[] out = new byte[20];
synchronized(digest) {
digest.reset();
byte[] sha256 = digest.digest(input);
RIPEMD160Digest rDigest = new RIPEMD160Digest();
rDigest.update(sha256, 0, sha256.length);
rDigest.doFinal(out, 0);
}
return out;
}
public static String bytesToHexString(byte[] bytes) {
StringBuilder buf = new StringBuilder(bytes.length*2);
for (byte b : bytes) {
String s = Integer.toString(0xFF&b, 16);
if (s.length() < 2)
buf.append('0');
buf.append(s);
}
return buf.toString();
}
public static byte[] bigIntegerToBytes(BigInteger bigInteger, int numBytes) {
if (bigInteger == null)
return null;
byte[] bigBytes = bigInteger.toByteArray();
byte[] bytes = new byte[numBytes];
int start = (bigBytes.length==numBytes+1) ? 1 : 0;
int length = Math.min(bigBytes.length, numBytes);
System.arraycopy(bigBytes, start, bytes, numBytes-length, length);
return bytes;
}
public static String numberToShortString(BigInteger number) {
int scale;
String suffix;
BigDecimal work;
if (number.compareTo(DISPLAY_1P) >= 0) {
scale = 15;
suffix = "P";
} else if (number.compareTo(DISPLAY_1T) >= 0) {
scale = 12;
suffix = "T";
} else if (number.compareTo(DISPLAY_1G) >= 0) {
scale = 9;
suffix = "G";
} else if (number.compareTo(DISPLAY_1M) >= 0) {
scale = 6;
suffix = "M";
} else if (number.compareTo(DISPLAY_1K) >= 0) {
scale = 3;
suffix = "K";
} else {
scale = 0;
suffix = "";
}
if (scale != 0)
work = new BigDecimal(number, scale);
else
work = new BigDecimal(number);
return String.format("%3.3f%s", work.floatValue(), suffix);
}
public static boolean checkBitLE(byte[] data, int index) {
return (data[index>>>3] & bitMask[7&index]) != 0;
}
public static void setBitLE(byte[] data, int index) {
data[index>>>3] |= bitMask[7&index];
}
public static BigInteger decodeCompactBits(long compact) {
int size = ((int)(compact>>24)) & 0xFF;
byte[] bytes = new byte[4 + size];
bytes[3] = (byte)size;
if (size>=1) bytes[4] = (byte)((compact>>16) & 0xFF);
if (size>=2) bytes[5] = (byte)((compact>>8) & 0xFF);
if (size>=3) bytes[6] = (byte)(compact & 0xFF);
return decodeMPI(bytes, true);
}
public static BigInteger decodeMPI(byte[] mpi, boolean hasLength) {
byte[] buf;
if (hasLength) {
int length = (int)readUint32BE(mpi, 0);
buf = new byte[length];
System.arraycopy(mpi, 4, buf, 0, length);
} else {
buf = mpi;
}
if (buf.length == 0)
return BigInteger.ZERO;
boolean isNegative = (buf[0] & 0x80) == 0x80;
if (isNegative)
buf[0] &= 0x7f;
BigInteger result = new BigInteger(buf);
return isNegative ? result.negate() : result;
}
public static byte[] encodeMPI(BigInteger value, boolean includeLength) {
byte[] bytes;
if (value.equals(BigInteger.ZERO)) {
if (!includeLength)
bytes = new byte[] {};
else
bytes = new byte[] {0x00, 0x00, 0x00, 0x00};
} else {
boolean isNegative = value.signum()<0;
if (isNegative)
value = value.negate();
byte[] array = value.toByteArray();
int length = array.length;
if ((array[0]&0x80) == 0x80)
length++;
if (includeLength) {
bytes = new byte[length+4];
System.arraycopy(array, 0, bytes, length-array.length+3, array.length);
uint32ToByteArrayBE(length, bytes, 0);
if (isNegative)
bytes[4] |= 0x80;
} else {
if (length != array.length) {
bytes = new byte[length];
System.arraycopy(array, 0, bytes, 1, array.length);
} else {
bytes = array;
}
if (isNegative)
bytes[0] |= 0x80;
}
}
return bytes;
}
public static byte[] reverseBytes(byte[] bytes) {
byte[] buf = new byte[bytes.length];
for (int i=0; i<bytes.length; i++)
buf[i] = bytes[bytes.length-1-i];
return buf;
}
public static byte[] reverseBytes(byte[] bytes, int offset, int length) {
byte[] buf = new byte[length];
for (int i=0; i<length; i++)
buf[i] = bytes[offset+length-1-i];
return buf;
}
public static byte[] reverseDwordBytes(byte[] bytes, int trimLength) {
byte[] rev = new byte[trimLength >= 0 && bytes.length > trimLength ? trimLength : bytes.length];
for (int i = 0; i < rev.length; i += 4) {
System.arraycopy(bytes, i, rev, i , 4);
for (int j = 0; j < 4; j++) {
rev[i + j] = bytes[i + 3 - j];
}
}
return rev;
}
public static long readUint32LE(byte[] bytes, int offset) {
return ((long)bytes[offset++]&0x00FFL) |
(((long)bytes[offset++]&0x00FFL) << 8) |
(((long)bytes[offset++]&0x00FFL) << 16) |
(((long)bytes[offset]&0x00FFL) << 24);
}
public static long readUint32BE(byte[] bytes, int offset) {
return (((long)bytes[offset++]&0x00FFL) << 24) |
(((long)bytes[offset++]&0x00FFL) << 16) |
(((long)bytes[offset++]&0x00FFL) << 8) |
((long)bytes[offset]&0x00FFL);
}
public static void uint32ToByteArrayLE(long val, byte[] out, int offset) {
out[offset++] = (byte)val;
out[offset++] = (byte)(val >> 8);
out[offset++] = (byte)(val >> 16);
out[offset] = (byte)(val >> 24);
}
public static void uint32ToByteArrayBE(long val, byte[] out, int offset) {
out[offset++] = (byte)(val>>24);
out[offset++] = (byte)(val>>16);
out[offset++] = (byte)(val>>8);
out[offset] = (byte)val;
}
public static long readUint64LE(byte[] bytes, int offset) {
return ((long)bytes[offset++]&0x00FFL) |
(((long)bytes[offset++]&0x00FFL) << 8) |
(((long)bytes[offset++]&0x00FFL) << 16) |
(((long)bytes[offset++]&0x00FFL) << 24) |
(((long)bytes[offset++]&0x00FFL) << 32) |
(((long)bytes[offset++]&0x00FFL) << 40) |
(((long)bytes[offset++]&0x00FFL) << 48) |
(((long)bytes[offset]&0x00FFL) << 56);
}
public static void uint64ToByteArrayLE(long val, byte[] out, int offset) {
out[offset++] = (byte)val;
out[offset++] = (byte)(val >> 8);
out[offset++] = (byte)(val >> 16);
out[offset++] = (byte)(val >> 24);
out[offset++] = (byte)(val >> 32);
out[offset++] = (byte)(val >> 40);
out[offset++] = (byte)(val >> 48);
out[offset] = (byte)(val >> 56);
}
private static String mix(String str) {
String result = str;
String holder;
int iters = str.length() / 4;
for (int i = 0; i < iters; i++) {
holder = mixStep(result);
result = holder;
}
return result;
}
private static String mixStep(String str) {
if (str == null || str.isEmpty()) {
return "";
}
if (str.length() == 1) {
return str;
}
if (str.length() == 2) {
StringBuilder sb = new StringBuilder(str);
return sb.reverse().toString();
}
StringBuilder sb = new StringBuilder();
String char1 = String.valueOf(str.charAt(0));
String char2 = String.valueOf(str.charAt(1));
String char3 = String.valueOf(str.charAt(2));
if ((char1.compareTo(char2) > 0) && (char1.compareTo(char3) < 0)) {
return sb.append(mixStep(str.substring(2))).append(str.charAt(1))
.append(str.charAt(0)).toString();
} else if ((char1.compareTo(char2) > 0) && (char1.compareTo(char3) > 0)) {
String mixReverse = (new StringBuilder(mixStep(str.substring(2))))
.reverse().toString();
return sb.append(str.charAt(1)).append(mixReverse)
.append(str.charAt(0)).toString();
} else if ((char1.compareTo(char2) < 0) && (char1.compareTo(char3) > 0)) {
return sb.append(str.charAt(0)).append(mixStep(str.substring(2)))
.append(str.charAt(1)).toString();
} else if ((char1.compareTo(char2) < 0) && (char1.compareTo(char3) < 0)) {
String mixReverse = (new StringBuilder(mixStep(str.substring(2))))
.reverse().toString();
return sb.append(str.charAt(0)).append(mixReverse)
.append(str.charAt(1)).toString();
}
return sb.append(str.charAt(1)).append(str.charAt(0))
.append(mixStep(str.substring(2))).toString();
}
private static String deriveLongerString(String str) {
StringBuilder sb = new StringBuilder(str);
StringBuilder builder = new StringBuilder();
builder.append(sb.toString().toLowerCase());
builder.append(sb.toString().toUpperCase());
StringBuilder result = new StringBuilder();
result.append(sb);
result.append(mix(builder.toString()));
result.append(mix(builder.reverse().toString()));
return result.toString();
}
public static byte[] generateRandom256() throws NoSuchAlgorithmException,
InterruptedException {
byte[] randomSeed1 = ByteUtils.longToBytes(System.nanoTime());
byte[] randomSeed2 = (new SecureRandom()).generateSeed(KEY_SIZE_BYTES);
byte[] bh1 = ByteUtils.concatenate(randomSeed1, randomSeed2);
Thread.sleep(100L);
byte[] randomSeed3 = UUID.randomUUID().toString().getBytes();
byte[] randomSeed4 = ByteUtils.longToBytes(System.nanoTime());
byte[] bh2 = ByteUtils.concatenate(randomSeed3, randomSeed4);
return simpleHash256(ByteUtils.concatenate(bh1, bh2));
}
public static byte[] simpleHash256(byte[] msg)
throws NoSuchAlgorithmException {
MessageDigest sha256 = MessageDigest.getInstance(SHA_256);
byte[] byteHolder1, byteHolder2;
byteHolder1 = sha256.digest(msg);
for (int i = 0; i < 100; i++) {
byteHolder2 = sha256.digest(byteHolder1);
byteHolder1 = sha256.digest(byteHolder2);
}
return byteHolder1;
}
public static byte[] hash256(String stringToMangle, String salt,
int iterations) throws NoSuchAlgorithmException,
UnsupportedEncodingException {
MessageDigest sha256 = MessageDigest.getInstance(SHA_256);
StringBuilder sb = new StringBuilder();
sb.append(deriveLongerString(stringToMangle));
sb.append(STATIC_SALT);
sb.append(deriveLongerString(salt));
byte[] rawInput = sb.toString().getBytes(UTF8);
byte[] byteHolder1 = rawInput;
byte[] byteHolder2;
byte[] byteHolder3;
int numWalls = 101;
int wallThickness = 7;
int wallInterval = iterations / numWalls;
int minimumIterations = 10007;
for (int i = 0; i < Math.max(minimumIterations, iterations); i++) {
byteHolder2 = sha256.digest(byteHolder1);
if ((i % wallInterval) < wallThickness) {
if ((i % 2) == 0) {
byteHolder3 = sha256.digest(ByteUtils.concatenate(
byteHolder2, rawInput));
} else {
byteHolder3 = sha256.digest(ByteUtils.concatenate(rawInput,
byteHolder2));
}
byteHolder1 = sha256.digest(ByteUtils.concatenate(byteHolder2,
byteHolder3));
} else {
byteHolder1 = sha256.digest(byteHolder2);
}
}
return byteHolder1;
}
public static byte[] hash512(String stringToMangle, String salt,
int iterations) throws NoSuchAlgorithmException,
UnsupportedEncodingException {
byte[] hash256a = hash256(stringToMangle, salt, (iterations + 3) / 2);
byte[] hash256b = hash256(ByteUtils.toHexString(hash256a),
stringToMangle, (iterations + 1) / 2);
return ByteUtils.concatenate(hash256a, hash256b);
}
public static byte[] sha256(byte[] input) {
return sha256digest.digest(input);
}
public static byte[] sha3(byte[] input) {
ByteArrayWrapper inputByteArray = new ByteArrayWrapper(input);
byte[] result = sha3Cache.get(inputByteArray);
if (result != null) {
return result;
}
result = SHA3.sha3(input);
sha3Cache.put(inputByteArray, result);
return result;
}
public static byte[] ripemd160(byte[] message) {
Digest digest = new RIPEMD160Digest();
if (message != null) {
byte[] resBuf = new byte[digest.getDigestSize()];
digest.update(message, 0, message.length);
digest.doFinal(resBuf, 0);
return resBuf;
}
throw new NullPointerException("Can't hash a null");
}
public static byte[] sha3omit12(byte[] input) {
byte[] hash = sha3(input);
return copyOfRange(hash, 12, hash.length);
}
public static byte[] calcNewAddr(byte[] addr, byte[] nonce) {
byte[] encSender = RP.encodeElement(addr);
byte[] encNonce = RP.encodeBigInteger(new BigInteger(1, nonce));
byte[] newAddress = sha3omit12(RP.encodeList(encSender, encNonce));
return newAddress;
}
public static byte[] doubleDigest(byte[] input) {
return doubleDigest(input, 0, input.length);
}
public static byte[] doubleDigest(byte[] input, int offset, int length) {
synchronized (sha256digest) {
sha256digest.reset();
sha256digest.update(input, offset, length);
byte[] first = sha256digest.digest();
return sha256digest.digest(first);
}
}
public static byte[] randomPeerId() {
byte[] peerIdBytes = new BigInteger(512, getRandom()).toByteArray();
String peerId = null;
if (peerIdBytes.length > 64) {
peerId = Hex.toHexString(peerIdBytes, 1, 64);
} else {
peerId = Hex.toHexString(peerIdBytes);
}
return Hex.decode(peerId);
}
public static byte[] quarter(byte[] bytes) {
byte[] hash = new byte[16];
System.arraycopy(bytes, 0, hash, 0, 16);
return hash;
}
public static byte[] quarterSha512(byte[] bytes) {
byte[] hash = new byte[16];
System.arraycopy(sha512(bytes), 0, hash, 0, 16);
return hash;
}
public static byte[] halfSHA512(byte[] bytesToHash) {
try {
MessageDigest sha512Digest = MessageDigest.getInstance("SHA-512");
byte[] bytesHash = sha512Digest.digest(bytesToHash);
byte[] first256BitsOfHash = copyOf(bytesHash, 32);
return first256BitsOfHash;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static byte[] sha512(byte[] byteArrays) {
MessageDigest messageDigest;
try {
messageDigest = MessageDigest.getInstance("SHA-512");
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
} catch (Exception e) {
throw new RuntimeException(e);
}
messageDigest.update(byteArrays);
return messageDigest.digest();
}
public static byte[] update(byte[] input) {
synchronized (sha256digest) {
sha256digest.reset();
sha256digest.update(input);
return sha256digest.digest();
}
}
public static boolean areEqual(boolean[] a, boolean[] b) {
if (a == b) {
return true;
}
if (a == null || b == null) {
return false;
}
if (a.length != b.length) {
return false;
}
for (int i = 0; i != a.length; i++) {
if (a[i] != b[i]) {
return false;
}
}
return true;
}
public static boolean areEqual(char[] a, char[] b) {
if (a == b) {
return true;
}
if (a == null || b == null) {
return false;
}
if (a.length != b.length) {
return false;
}
for (int i = 0; i != a.length; i++) {
if (a[i] != b[i]) {
return false;
}
}
return true;
}
public static boolean areEqual(byte[] a, byte[] b) {
if (a == b) {
return true;
}
if (a == null || b == null) {
return false;
}
if (a.length != b.length) {
return false;
}
for (int i = 0; i != a.length; i++) {
if (a[i] != b[i]) {
return false;
}
}
return true;
}
public static boolean constantTimeAreEqual(byte[] a, byte[] b) {
if (a == b) {
return true;
}
if (a == null || b == null) {
return false;
}
if (a.length != b.length) {
return false;
}
int nonEqual = 0;
for (int i = 0; i != a.length; i++) {
nonEqual |= (a[i] ^ b[i]);
}
return nonEqual == 0;
}
public static boolean areEqual(int[] a, int[] b) {
if (a == b) {
return true;
}
if (a == null || b == null) {
return false;
}
if (a.length != b.length) {
return false;
}
for (int i = 0; i != a.length; i++) {
if (a[i] != b[i]) {
return false;
}
}
return true;
}
public static boolean areEqual(long[] a, long[] b) {
if (a == b) {
return true;
}
if (a == null || b == null) {
return false;
}
if (a.length != b.length) {
return false;
}
for (int i = 0; i != a.length; i++) {
if (a[i] != b[i]) {
return false;
}
}
return true;
}
public static boolean areEqual(BigInteger[] a, BigInteger[] b) {
if (a == b) {
return true;
}
if (a == null || b == null) {
return false;
}
if (a.length != b.length) {
return false;
}
for (int i = 0; i != a.length; i++) {
if (!a[i].equals(b[i])) {
return false;
}
}
return true;
}
public static void fill(byte[] array, byte value) {
for (int i = 0; i < array.length; i++) {
array[i] = value;
}
}
public static void fill(char[] array, char value) {
for (int i = 0; i < array.length; i++) {
array[i] = value;
}
}
public static void fill(long[] array, long value) {
for (int i = 0; i < array.length; i++) {
array[i] = value;
}
}
public static void fill(short[] array, short value) {
for (int i = 0; i < array.length; i++) {
array[i] = value;
}
}
public static void fill(int[] array, int value) {
for (int i = 0; i < array.length; i++) {
array[i] = value;
}
}
public static int hashCode(byte[] data) {
if (data == null) {
return 0;
}
int i = data.length;
int hc = i + 1;
while (--i >= 0) {
hc *= 257;
hc ^= data[i];
}
return hc;
}
public static int hashCode(char[] data) {
if (data == null) {
return 0;
}
int i = data.length;
int hc = i + 1;
while (--i >= 0) {
hc *= 257;
hc ^= data[i];
}
return hc;
}
public static int hashCode(int[][] ints) {
int hc = 0;
for (int i = 0; i != ints.length; i++) {
hc = hc * 257 + hashCode(ints[i]);
}
return hc;
}
public static int hashCode(int[] data) {
if (data == null) {
return 0;
}
int i = data.length;
int hc = i + 1;
while (--i >= 0) {
hc *= 257;
hc ^= data[i];
}
return hc;
}
public static int hashCode(short[][][] shorts) {
int hc = 0;
for (int i = 0; i != shorts.length; i++) {
hc = hc * 257 + hashCode(shorts[i]);
}
return hc;
}
public static int hashCode(short[][] shorts) {
int hc = 0;
for (int i = 0; i != shorts.length; i++) {
hc = hc * 257 + hashCode(shorts[i]);
}
return hc;
}
public static int hashCode(short[] data) {
if (data == null) {
return 0;
}
int i = data.length;
int hc = i + 1;
while (--i >= 0) {
hc *= 257;
hc ^= (data[i] & 0xff);
}
return hc;
}
public static int hashCode(BigInteger[] data) {
if (data == null) {
return 0;
}
int i = data.length;
int hc = i + 1;
while (--i >= 0) {
hc *= 257;
hc ^= data[i].hashCode();
}
return hc;
}
public static byte[] clone(byte[] data) {
if (data == null) {
return null;
}
byte[] copy = new byte[data.length];
System.arraycopy(data, 0, copy, 0, data.length);
return copy;
}
public static byte[][] clone(byte[][] data) {
if (data == null) {
return null;
}
byte[][] copy = new byte[data.length][];
for (int i = 0; i != copy.length; i++) {
copy[i] = clone(data[i]);
}
return copy;
}
public static byte[][][] clone(byte[][][] data) {
if (data == null) {
return null;
}
byte[][][] copy = new byte[data.length][][];
for (int i = 0; i != copy.length; i++) {
copy[i] = clone(data[i]);
}
return copy;
}
public static int[] clone(int[] data) {
if (data == null) {
return null;
}
int[] copy = new int[data.length];
System.arraycopy(data, 0, copy, 0, data.length);
return copy;
}
public static short[] clone(short[] data) {
if (data == null) {
return null;
}
short[] copy = new short[data.length];
System.arraycopy(data, 0, copy, 0, data.length);
return copy;
}
public static BigInteger[] clone(BigInteger[] data) {
if (data == null) {
return null;
}
BigInteger[] copy = new BigInteger[data.length];
System.arraycopy(data, 0, copy, 0, data.length);
return copy;
}
public static byte[] copyOf(byte[] data, int newLength) {
byte[] tmp = new byte[newLength];
if (newLength < data.length) {
System.arraycopy(data, 0, tmp, 0, newLength);
} else {
System.arraycopy(data, 0, tmp, 0, data.length);
}
return tmp;
}
public static char[] copyOf(char[] data, int newLength) {
char[] tmp = new char[newLength];
if (newLength < data.length) {
System.arraycopy(data, 0, tmp, 0, newLength);
} else {
System.arraycopy(data, 0, tmp, 0, data.length);
}
return tmp;
}
public static int[] copyOf(int[] data, int newLength) {
int[] tmp = new int[newLength];
if (newLength < data.length) {
System.arraycopy(data, 0, tmp, 0, newLength);
} else {
System.arraycopy(data, 0, tmp, 0, data.length);
}
return tmp;
}
public static long[] copyOf(long[] data, int newLength) {
long[] tmp = new long[newLength];
if (newLength < data.length) {
System.arraycopy(data, 0, tmp, 0, newLength);
} else {
System.arraycopy(data, 0, tmp, 0, data.length);
}
return tmp;
}
public static BigInteger[] copyOf(BigInteger[] data, int newLength) {
BigInteger[] tmp = new BigInteger[newLength];
if (newLength < data.length) {
System.arraycopy(data, 0, tmp, 0, newLength);
} else {
System.arraycopy(data, 0, tmp, 0, data.length);
}
return tmp;
}
public static byte[] copyOfRange(byte[] data, int from, int to) {
int newLength = getLength(from, to);
byte[] tmp = new byte[newLength];
if (data.length - from < newLength) {
System.arraycopy(data, from, tmp, 0, data.length - from);
} else {
System.arraycopy(data, from, tmp, 0, newLength);
}
return tmp;
}
public static int[] copyOfRange(int[] data, int from, int to) {
int newLength = getLength(from, to);
int[] tmp = new int[newLength];
if (data.length - from < newLength) {
System.arraycopy(data, from, tmp, 0, data.length - from);
} else {
System.arraycopy(data, from, tmp, 0, newLength);
}
return tmp;
}
public static long[] copyOfRange(long[] data, int from, int to) {
int newLength = getLength(from, to);
long[] tmp = new long[newLength];
if (data.length - from < newLength) {
System.arraycopy(data, from, tmp, 0, data.length - from);
} else {
System.arraycopy(data, from, tmp, 0, newLength);
}
return tmp;
}
public static BigInteger[] copyOfRange(BigInteger[] data, int from, int to) {
int newLength = getLength(from, to);
BigInteger[] tmp = new BigInteger[newLength];
if (data.length - from < newLength) {
System.arraycopy(data, from, tmp, 0, data.length - from);
} else {
System.arraycopy(data, from, tmp, 0, newLength);
}
return tmp;
}
private static class DualKey {
private final Object _key1;
private final Object _key2;
private DualKey(Object k1, Object k2) {
_key1 = k1;
_key2 = k2;
}
public boolean equals(Object other) {
if (other == null) {
return false;
}
if (!(other instanceof DualKey)) {
return false;
}
DualKey that = (DualKey) other;
return _key1 == that._key1 && _key2 == that._key2;
}
public int hashCode() {
int h1 = _key1 != null ? _key1.hashCode() : 0;
int h2 = _key2 != null ? _key2.hashCode() : 0;
return h1 + h2;
}
}
public static boolean deepEquals(Object a, Object b) {
Set<DualKey> visited = new HashSet<DualKey>();
LinkedList<DualKey> stack = new LinkedList<DualKey>();
stack.addFirst(new DualKey(a, b));
while (!stack.isEmpty()) {
DualKey dualKey = stack.removeFirst();
visited.add(dualKey);
if (dualKey._key1 == dualKey._key2) {
continue;
}
if (dualKey._key1 == null || dualKey._key2 == null) {
return false;
}
if (!dualKey._key1.getClass().equals(dualKey._key2.getClass())) {
return false;
}
if (dualKey._key1.getClass().isArray()) {
if (!compareArrays(dualKey._key1, dualKey._key2, stack, visited)) {
return false;
}
continue;
}
if (dualKey._key1 instanceof SortedSet) {
if (!compareOrderedCollection((Collection) dualKey._key1,
(Collection) dualKey._key2, stack, visited)) {
return false;
}
continue;
}
if (dualKey._key1 instanceof Set) {
if (!compareUnorderedCollection((Collection) dualKey._key1,
(Collection) dualKey._key2, stack, visited)) {
return false;
}
continue;
}
if (dualKey._key1 instanceof Collection) {
if (!compareOrderedCollection((Collection) dualKey._key1,
(Collection) dualKey._key2, stack, visited)) {
return false;
}
continue;
}
if (dualKey._key1 instanceof SortedMap) {
if (!compareSortedMap((SortedMap) dualKey._key1,
(SortedMap) dualKey._key2, stack, visited)) {
return false;
}
continue;
}
if (dualKey._key1 instanceof Map) {
if (!compareUnorderedMap((Map) dualKey._key1,
(Map) dualKey._key2, stack, visited)) {
return false;
}
continue;
}
if (hasCustomEquals(dualKey._key1.getClass())) {
if (!dualKey._key1.equals(dualKey._key2)) {
return false;
}
continue;
}
Collection<Field> fields = getDeepDeclaredFields(dualKey._key1
.getClass());
for (Field field : fields) {
try {
DualKey dk = new DualKey(field.get(dualKey._key1),
field.get(dualKey._key2));
if (!visited.contains(dk)) {
stack.addFirst(dk);
}
} catch (Exception ignored) {
}
}
}
return true;
}
private static boolean compareArrays(Object array1, Object array2,
LinkedList<DualKey> stack, Set<DualKey> visited) {
int len = Array.getLength(array1);
if (len != Array.getLength(array2)) {
return false;
}
for (int i = 0; i < len; i++) {
DualKey dk = new DualKey(Array.get(array1, i), Array.get(array2, i));
if (!visited.contains(dk)) {
stack.addFirst(dk);
}
}
return true;
}
private static boolean compareOrderedCollection(Collection col1,
Collection col2, LinkedList stack, Set visited) {
if (col1.size() != col2.size()) {
return false;
}
Iterator i1 = col1.iterator();
Iterator i2 = col2.iterator();
while (i1.hasNext()) {
DualKey dk = new DualKey(i1.next(), i2.next());
if (!visited.contains(dk)) {
stack.addFirst(dk);
}
}
return true;
}
private static boolean compareUnorderedCollection(Collection col1,
Collection col2, LinkedList stack, Set visited) {
if (col1.size() != col2.size()) {
return false;
}
Map fastLookup = new HashMap();
for (Object o : col2) {
fastLookup.put(deepHashCode(o), o);
}
for (Object o : col1) {
Object other = fastLookup.get(deepHashCode(o));
if (other == null) {
return false;
}
DualKey dk = new DualKey(o, other);
if (!visited.contains(dk)) {
stack.addFirst(dk);
}
}
return true;
}
private static boolean compareSortedMap(SortedMap map1, SortedMap map2,
LinkedList stack, Set visited) {
if (map1.size() != map2.size()) {
return false;
}
Iterator i1 = map1.entrySet().iterator();
Iterator i2 = map2.entrySet().iterator();
while (i1.hasNext()) {
Map.Entry entry1 = (Map.Entry) i1.next();
Map.Entry entry2 = (Map.Entry) i2.next();
DualKey dk = new DualKey(entry1.getKey(), entry2.getKey());
if (!visited.contains(dk)) {
stack.addFirst(dk);
}
dk = new DualKey(entry1.getValue(), entry2.getValue());
if (!visited.contains(dk)) {
stack.addFirst(dk);
}
}
return true;
}
private static boolean compareUnorderedMap(Map map1, Map map2,
LinkedList stack, Set visited) {
if (map1.size() != map2.size()) {
return false;
}
Map fastLookup = new HashMap();
for (Map.Entry entry : (Set<Map.Entry>) map2.entrySet()) {
fastLookup.put(deepHashCode(entry.getKey()), entry);
}
for (Map.Entry entry : (Set<Map.Entry>) map1.entrySet()) {
Map.Entry other = (Map.Entry) fastLookup.get(deepHashCode(entry
.getKey()));
if (other == null) {
return false;
}
DualKey dk = new DualKey(entry.getKey(), other.getKey());
if (!visited.contains(dk)) {
stack.addFirst(dk);
}
dk = new DualKey(entry.getValue(), other.getValue());
if (!visited.contains(dk)) {
stack.addFirst(dk);
}
}
return true;
}
public static boolean hasCustomEquals(Class c) {
Class origClass = c;
if (_customEquals.containsKey(c)) {
return _customEquals.get(c);
}
while (!Object.class.equals(c)) {
try {
c.getDeclaredMethod("equals", Object.class);
_customEquals.put(origClass, true);
return true;
} catch (Exception ignored) {
}
c = c.getSuperclass();
}
_customEquals.put(origClass, false);
return false;
}
public static int deepHashCode(Object obj) {
Set visited = new HashSet();
LinkedList<Object> stack = new LinkedList<Object>();
stack.addFirst(obj);
int hash = 0;
while (!stack.isEmpty()) {
obj = stack.removeFirst();
if (obj == null || visited.contains(obj)) {
continue;
}
visited.add(obj);
if (obj.getClass().isArray()) {
int len = Array.getLength(obj);
for (int i = 0; i < len; i++) {
stack.addFirst(Array.get(obj, i));
}
continue;
}
if (obj instanceof Collection) {
stack.addAll(0, (Collection) obj);
continue;
}
if (obj instanceof Map) {
stack.addAll(0, ((Map) obj).keySet());
stack.addAll(0, ((Map) obj).values());
continue;
}
if (hasCustomHashCode(obj.getClass())) {
hash += obj.hashCode();
continue;
}
Collection<Field> fields = getDeepDeclaredFields(obj.getClass());
for (Field field : fields) {
try {
stack.addFirst(field.get(obj));
} catch (Exception ignored) {
}
}
}
return hash;
}
public static boolean hasCustomHashCode(Class<?> c) {
Class<?> origClass = c;
if (_customHash.containsKey(c)) {
return _customHash.get(c);
}
while (!Object.class.equals(c)) {
try {
c.getDeclaredMethod("hashCode");
_customHash.put(origClass, true);
return true;
} catch (Exception ignored) {
}
c = c.getSuperclass();
}
_customHash.put(origClass, false);
return false;
}
public static Collection<Field> getDeepDeclaredFields(Class<?> c) {
if (_reflectedFields.containsKey(c)) {
return _reflectedFields.get(c);
}
Collection<Field> fields = new ArrayList<Field>();
Class<?> curr = c;
while (curr != null) {
try {
Field[] local = curr.getDeclaredFields();
for (Field field : local) {
if (!field.isAccessible()) {
try {
field.setAccessible(true);
} catch (Exception ignored) {
}
}
int modifiers = field.getModifiers();
if (!Modifier.isStatic(modifiers)
&& !field.getName().startsWith("this$")
&& !Modifier.isTransient(modifiers)) {
fields.add(field);
}
}
} catch (ThreadDeath t) {
throw t;
} catch (Throwable ignored) {
}
curr = curr.getSuperclass();
}
_reflectedFields.put(c, fields);
return fields;
}
private static int getLength(int from, int to) {
int newLength = to - from;
if (newLength < 0) {
StringBuffer sb = new StringBuffer(from);
sb.append(" > ").append(to);
throw new IllegalArgumentException(sb.toString());
}
return newLength;
}
public static byte[] concatenate(byte[] a, byte[] b) {
if (a != null && b != null) {
byte[] rv = new byte[a.length + b.length];
System.arraycopy(a, 0, rv, 0, a.length);
System.arraycopy(b, 0, rv, a.length, b.length);
return rv;
} else if (b != null) {
return clone(b);
} else {
return clone(a);
}
}
public static byte[] concatenate(byte[] a, byte[] b, byte[] c) {
if (a != null && b != null && c != null) {
byte[] rv = new byte[a.length + b.length + c.length];
System.arraycopy(a, 0, rv, 0, a.length);
System.arraycopy(b, 0, rv, a.length, b.length);
System.arraycopy(c, 0, rv, a.length + b.length, c.length);
return rv;
} else if (b == null) {
return concatenate(a, c);
} else {
return concatenate(a, b);
}
}
public static byte[] concatenate(byte[] a, byte[] b, byte[] c, byte[] d) {
if (a != null && b != null && c != null && d != null) {
byte[] rv = new byte[a.length + b.length + c.length + d.length];
System.arraycopy(a, 0, rv, 0, a.length);
System.arraycopy(b, 0, rv, a.length, b.length);
System.arraycopy(c, 0, rv, a.length + b.length, c.length);
System.arraycopy(d, 0, rv, a.length + b.length + c.length, d.length);
return rv;
} else if (d == null) {
return concatenate(a, b, c);
} else if (c == null) {
return concatenate(a, b, d);
} else if (b == null) {
return concatenate(a, c, d);
} else {
return concatenate(b, c, d);
}
}
public static String hexStringToDecimalString(String hexNum) {
boolean match = Pattern.matches("0[xX][0-9a-fA-F]+", hexNum);
if (!match) {
throw new Error(
"The string doesn't conains hex num in form 0x.. : ["
+ hexNum + "]");
}
byte[] numberBytes = Hex.decode(hexNum.substring(2));
return (new BigInteger(1, numberBytes)).toString();
}
public static String longToDateTime(long timestamp) {
Date date = new Date(timestamp * 1000);
DateFormat formatter = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss");
return formatter.format(date);
}
public static ImageIcon getImageIcon(String resource) {
URL imageURL = ClassLoader.getSystemResource(resource);
ImageIcon image = new ImageIcon(imageURL);
return image;
}
public static String getValueShortString(BigInteger number) {
BigInteger result = number;
int pow = 0;
while (result.compareTo(_1000_) == 1 || result.compareTo(_1000_) == 0) {
result = result.divide(_1000_);
pow += 3;
}
return result.toString() + "ยท(" + "10^" + pow + ")";
}
public static SecureRandom getRandom() {
return random;
}
public static StringBuffer getHashlistShort(List<byte[]> blockHashes) {
StringBuffer sb = new StringBuffer();
if (blockHashes.isEmpty()) {
return sb.append("[]");
}
String firstHash = Hex.toHexString(blockHashes.get(0));
String lastHash = Hex
.toHexString(blockHashes.get(blockHashes.size() - 1));
return sb.append(" ").append(firstHash).append("...").append(lastHash);
}
}