HexUtil.java Source code

Java tutorial

Introduction

Here is the source code for HexUtil.java

Source

//package freenet.support;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.util.BitSet;

/**
 * Number in hexadecimal format are used throughout Freenet.
 * 
 * <p>Unless otherwise stated, the conventions follow the rules outlined in the 
 * Java Language Specification.</p>
 * 
 * @author syoung
 */
public class HexUtil {
    /**
     * Converts a byte array into a string of lower case hex chars.
     * 
     * @param bs
     *            A byte array
     * @param off
     *            The index of the first byte to read
     * @param length
     *            The number of bytes to read.
     * @return the string of hex chars.
     */
    public static final String bytesToHex(byte[] bs, int off, int length) {
        if (bs.length <= off || bs.length < off + length)
            throw new IllegalArgumentException();
        StringBuilder sb = new StringBuilder(length * 2);
        bytesToHexAppend(bs, off, length, sb);
        return sb.toString();
    }

    public static final void bytesToHexAppend(byte[] bs, int off, int length, StringBuilder sb) {
        if (bs.length <= off || bs.length < off + length)
            throw new IllegalArgumentException();
        sb.ensureCapacity(sb.length() + length * 2);
        for (int i = off; i < (off + length); i++) {
            sb.append(Character.forDigit((bs[i] >>> 4) & 0xf, 16));
            sb.append(Character.forDigit(bs[i] & 0xf, 16));
        }
    }

    public static final String bytesToHex(byte[] bs) {
        return bytesToHex(bs, 0, bs.length);
    }

    public static final byte[] hexToBytes(String s) {
        return hexToBytes(s, 0);
    }

    public static final byte[] hexToBytes(String s, int off) {
        byte[] bs = new byte[off + (1 + s.length()) / 2];
        hexToBytes(s, bs, off);
        return bs;
    }

    /**
     * Converts a String of hex characters into an array of bytes.
     * 
     * @param s
     *            A string of hex characters (upper case or lower) of even
     *            length.
     * @param out
     *            A byte array of length at least s.length()/2 + off
     * @param off
     *            The first byte to write of the array
     */
    public static final void hexToBytes(String s, byte[] out, int off)
            throws NumberFormatException, IndexOutOfBoundsException {

        int slen = s.length();
        if ((slen % 2) != 0) {
            s = '0' + s;
        }

        if (out.length < off + slen / 2) {
            throw new IndexOutOfBoundsException(
                    "Output buffer too small for input (" + out.length + '<' + off + slen / 2 + ')');
        }

        // Safe to assume the string is even length
        byte b1, b2;
        for (int i = 0; i < slen; i += 2) {
            b1 = (byte) Character.digit(s.charAt(i), 16);
            b2 = (byte) Character.digit(s.charAt(i + 1), 16);
            if ((b1 < 0) || (b2 < 0)) {
                throw new NumberFormatException();
            }
            out[off + i / 2] = (byte) (b1 << 4 | b2);
        }
    }

    /**
     * Pack the bits in ba into a byte[].
     *
     * @param ba : the BitSet
     * @param size : How many bits shall be taken into account starting from the LSB?
     */
    public final static byte[] bitsToBytes(BitSet ba, int size) {
        int bytesAlloc = countBytesForBits(size);
        byte[] b = new byte[bytesAlloc];
        StringBuilder sb = null;

        for (int i = 0; i < b.length; i++) {
            short s = 0;
            for (int j = 0; j < 8; j++) {
                int idx = i * 8 + j;
                boolean val = idx > size - 1 ? false : ba.get(idx);
                s |= val ? (1 << j) : 0;
            }
            if (s > 255)
                throw new IllegalStateException("WTF? s = " + s);
            b[i] = (byte) s;
        }
        return b;
    }

    /**
     * Pack the bits in ba into a byte[] then convert that
     * to a hex string and return it.
     */
    public final static String bitsToHexString(BitSet ba, int size) {
        return bytesToHex(bitsToBytes(ba, size));
    }

    /**
     * @return the number of bytes required to represent the
     * bitset
     */
    public static int countBytesForBits(int size) {
        // Brackets matter here! == takes precedence over the rest
        return (size / 8) + ((size % 8) == 0 ? 0 : 1);
    }

    /**
     * Read bits from a byte array into a bitset
     * @param b the byte[] to read from
     * @param ba the bitset to write to
     */
    public static void bytesToBits(byte[] b, BitSet ba, int maxSize) {

        int x = 0;
        for (int i = 0; i < b.length; i++) {
            for (int j = 0; j < 8; j++) {
                if (x > maxSize)
                    break;
                int mask = 1 << j;
                boolean value = (mask & b[i]) != 0;
                ba.set(x, value);
                x++;
            }
        }
    }

    /**
     * Read a hex string of bits and write it into a bitset
     * @param s hex string of the stored bits
     * @param ba the bitset to store the bits in
     * @param length the maximum number of bits to store 
     */
    public static void hexToBits(String s, BitSet ba, int length) {
        byte[] b = hexToBytes(s);
        bytesToBits(b, ba, length);
    }

    /**
      * Write a (reasonably short) BigInteger to a stream.
      * @param integer the BigInteger to write
      * @param out the stream to write it to
      */
    public static void writeBigInteger(BigInteger integer, DataOutputStream out) throws IOException {
        if (integer.signum() == -1) {
            //dump("Negative BigInteger", Logger.ERROR, true);
            throw new IllegalStateException("Negative BigInteger!");
        }
        byte[] buf = integer.toByteArray();
        if (buf.length > Short.MAX_VALUE)
            throw new IllegalStateException("Too long: " + buf.length);
        out.writeShort((short) buf.length);
        out.write(buf);
    }

    /**
    * Read a (reasonably short) BigInteger from a DataInputStream
    * @param dis the stream to read from
    * @return a BigInteger
    */
    public static BigInteger readBigInteger(DataInputStream dis) throws IOException {
        short i = dis.readShort();
        if (i < 0)
            throw new IOException("Invalid BigInteger length: " + i);
        byte[] buf = new byte[i];
        dis.readFully(buf);
        return new BigInteger(1, buf);
    }

    /**
     * Turn a BigInteger into a hex string.
     * BigInteger.toString(16) NPEs on Sun JDK 1.4.2_05. :<
     * The bugs in their Big* are getting seriously irritating...
     */
    public static String biToHex(BigInteger bi) {
        return bytesToHex(bi.toByteArray());
    }
}