package org.ripple.power.txns.btc; import java.math.BigInteger; import java.util.Arrays; import org.ripple.power.Helper; /** * A script stack element is a series of zero or more bytes. The stack consists of stack elements * that are added and removed as the script is interpreted. The byte array is processed * as a little-endian signed number for numeric script operations. */ public class StackElement implements Comparable<StackElement> { /** The bytes represented by this stack element */ private final byte[] bytes; /** * Creates a new stack element from a byte array * * @param bytes The bytes for this element */ public StackElement(byte[] bytes) { this.bytes = bytes; } /** * Creates a new stack element from an existing stack element * * @param elem Existing stack element */ public StackElement(StackElement elem) { bytes = elem.getBytes(); } /** * Creates a new stack element from a BigInteger. Numeric values are stored * on the stack in MPI format with the bytes reversed. * * @param bigInteger BigInteger */ public StackElement(BigInteger bigInteger) { bytes = Helper.reverseBytes(Helper.encodeMPI(bigInteger, false)); } /** * Creates a new stack element containing TRUE or FALSE * * @param isTrue TRUE if stack element is TRUE */ public StackElement(boolean isTrue) { bytes = new byte[1]; bytes[0] = isTrue ? (byte)1 : (byte)0; } /** * Returns the bytes for this stack element * * @return The bytes for this element */ public byte[] getBytes() { return bytes; } /** * Returns a BigInteger representing the bytes for this stack element. Numeric * values are stored on the stack in MPI format with the bytes reversed. * * @return Unsigned BigInteger */ public BigInteger getBigInteger() { return Helper.decodeMPI(Helper.reverseBytes(bytes), false); } /** * Tests if this element represents a TRUE or FALSE result. Any non-zero value is TRUE * while any zero (positive or negative) is FALSE. A zero-length stack element is FALSE. * * @return TRUE or FALSE depending on the bytes in this element */ public boolean isTrue() { boolean isTrue = false; for (int i=0; i<bytes.length && !isTrue; i++) { if (bytes[i] == (byte)0x80) { if (i != bytes.length-1) isTrue = true; } else if (bytes[i] != 0) { isTrue = true; } } return isTrue; } /** * Return the hash code for this stack element * * @return Hash code */ @Override public int hashCode() { return Arrays.hashCode(bytes); } /** * Tests if two stack elements are equal * * @param obj Object to compare * @return TRUE if the two byte array are the same */ @Override public boolean equals(Object obj) { return (obj!=null && (obj instanceof StackElement) && Arrays.equals(bytes, ((StackElement)obj).bytes)); } /** * Compares this stack element to another stack element * * @param cmpElem Element to compare * @return -1 if less than, 0 if equal, 1 if greater */ @Override public int compareTo(StackElement cmpElem) { return getBigInteger().compareTo(cmpElem.getBigInteger()); } }