package org.ripple.power.blockchain.list; import java.math.BigInteger; import java.util.Arrays; import java.util.List; import org.ripple.power.Helper; import org.ripple.power.utils.ByteUtils; import org.ripple.bouncycastle.util.encoders.Hex; public class Value { private Object value; public Value(Object obj) { if (obj == null) { return; } if (obj instanceof Value) { this.value = ((Value) obj).asObj(); } else { this.value = obj; } } public Object asObj() { return value; } public List<Object> asList() { Object[] valueArray = (Object[]) value; return Arrays.asList(valueArray); } public int asInt() { if (isInt()) { return (Integer) value; } else if (isBytes()) { return new BigInteger(1, asBytes()).intValue(); } return 0; } public long asLong() { if (isLong()) { return (Long) value; } else if (isBytes()) { return new BigInteger(1, asBytes()).longValue(); } return 0; } public BigInteger asBigInt() { return (BigInteger) value; } public String asString() { if (isBytes()) { return new String((byte[]) value); } else if (isString()) { return (String) value; } return ""; } public byte[] asBytes() { if (isBytes()) { return (byte[]) value; } else if (isString()) { return asString().getBytes(); } return ByteUtils.EMPTY_BYTE_ARRAY; } public int[] asSlice() { return (int[]) value; } public Value get(int index) { if (isList()) { if (asList().size() <= index) { return new Value(null); } if (index < 0) { throw new RuntimeException("Negative index not allowed"); } return new Value(asList().get(index)); } return new Value(null); } public byte[] encode() { return RP.encode(value); } public boolean cmp(Value o) { return Helper.deepEquals(this, o); } public boolean isList() { return value != null && value.getClass().isArray() && !value.getClass().getComponentType().isPrimitive(); } public boolean isString() { return value instanceof String; } public boolean isInt() { return value instanceof Integer; } public boolean isLong() { return value instanceof Long; } public boolean isBigInt() { return value instanceof BigInteger; } public boolean isBytes() { return value instanceof byte[]; } public boolean isReadbleString() { int readableChars = 0; byte[] data = (byte[]) value; if (data.length == 1 && data[0] > 31 && data[0] < 126) { return true; } for (int i = 0; i < data.length; ++i) { if (data[i] > 32 && data[i] < 126) ++readableChars; } if ((double) readableChars / (double) data.length > 0.55) return true; else return false; } public boolean isHexString() { int hexChars = 0; byte[] data = (byte[]) value; for (int i = 0; i < data.length; ++i) { if ((data[i] >= 48 && data[i] <= 57) || (data[i] >= 97 && data[i] <= 102)) ++hexChars; } if ((double) hexChars / (double) data.length > 0.9) return true; else return false; } public boolean isHashCode() { return this.asBytes().length == 32; } public boolean isNull() { return value == null; } public boolean isEmpty() { if (isNull()) return true; if (isBytes() && asBytes().length == 0) return true; if (isList() && asList().isEmpty()) return true; if (isString() && asString().equals("")) return true; return false; } public int length() { if (isList()) { return asList().size(); } else if (isBytes()) { return asBytes().length; } else if (isString()) { return asString().length(); } return 0; } public String toString() { StringBuffer buffer = new StringBuffer(); if (isList()) { Object[] list = (Object[]) value; if (list.length == 2) { buffer.append("[ "); Value key = new Value(list[0]); byte[] keyNibbles = CompactEncoder.binToNibblesNoTerminator(key .asBytes()); String keyString = ByteUtils.nibblesToPrettyString(keyNibbles); buffer.append(keyString); buffer.append(","); Value val = new Value(list[1]); buffer.append(val.toString()); buffer.append(" ]"); return buffer.toString(); } buffer.append(" ["); for (int i = 0; i < list.length; ++i) { Value val = new Value(list[i]); if (val.isString() || val.isEmpty()) { buffer.append("'").append(val.toString()).append("'"); } else { buffer.append(val.toString()); } if (i < list.length - 1) buffer.append(", "); } buffer.append("] "); return buffer.toString(); } else if (isEmpty()) { return ""; } else if (isBytes()) { StringBuffer output = new StringBuffer(); if (isHashCode()) { output.append(Hex.toHexString(asBytes())); } else if (isReadbleString()) { output.append("'"); for (byte oneByte : asBytes()) { if (oneByte < 16) { output.append("\\x").append( ByteUtils.oneByteToHexString(oneByte)); } else { output.append(Character.valueOf((char) oneByte)); } } output.append("'"); return output.toString(); } return Hex.toHexString(this.asBytes()); } else if (isString()) { return asString(); } return "Unexpected type"; } public static Value fromRlpEncoded(byte[] data) { if (data != null && data.length != 0) { return new Value(RP.decode(data, 0).getDecoded()); } return null; } public int countBranchNodes() { if (this.isList()) { List<Object> objList = this.asList(); int i = 0; for (Object obj : objList) { i += (new Value(obj)).countBranchNodes(); } return i; } else if (this.isBytes()) { this.asBytes(); } return 0; } }