BinaryConverter.java
/**
 * This utility class provides static methods to convert byte arrays to
 * primitive integral data types, and to build byte arrays from primitive
 * integral types and Java Strings.  This conversion to and from binary allows
 * compressed streams of data to be passed around, e.g. between different Java
 * applications across a network, between applications written in different
 * languages, etc.
 *
 * @author Michael Fitzmaurice, October 2001
 */
public class BinaryConverter
{
    /**
     * Private constructor - since this is intended as purely a utility class,
     * we want to ensure that the user cannot instantiate it. This also ensures
     * that BinaryConverter cannot be subclassed
     */
     private BinaryConverter()
     {

     }

    ///////////////////////////////////////////////////////////////////////////
    //              METHODS TO CONVERT BYTE ARRAYS TO PRIMITIVES
    ///////////////////////////////////////////////////////////////////////////

    /**
     * Converts a given byte array of length 2 into it's short equivalent
     *
     * @param bytesIn the byte array to be converted
     *
     * @return The resultant short
     *
     * @exception IllegalArgumentException If the bytesIn argument
     * is not exactly 2 bytes in length (size of a Java short)
     */
    public static short bytesToShort(byte[] bytesIn)
        throws IllegalArgumentException
    {
        // we can only work with arrays containing 2 bytes (size of a Java short)
        if(bytesIn.length != 2)
        {
            throw new IllegalArgumentException( "Input to bytesToShort is "
                                                + bytesIn.length + " bytes long " +
                                                ", instead of 2 bytes");
        }

        // this cast is safe (see bytesToLongNum comments)
        return (short)bytesToLongNum(bytesIn);
    }

    /**
     * Converts a given byte array of length 4 into it's int equivalent
     *
     * @param bytesIn the byte array to be converted
     *
     * @return The resultant int
     *
     * @exception IllegalArgumentException If the bytesIn argument
     * is not exactly 4 bytes in length (size of a Java int)
     */
    public static int bytesToInt(byte[] bytesIn)
        throws IllegalArgumentException
    {
        // we can only work with arrays containing 4 bytes (size of a Java int)
        if(bytesIn.length != 4)
        {
            throw new IllegalArgumentException( "Input to bytesToInt is "
                                                + bytesIn.length + " bytes long " +
                                                ", instead of 4 bytes");
        }

        // this cast is safe - (see bytesToLongNum comments)
        return (int)bytesToLongNum(bytesIn);
    }

    /**
     * Converts a given byte array of length 8 into it's long equivalent
     *
     * @param bytesIn the byte array to be converted
     *
     * @return The resultant long
     *
     * @exception IllegalArgumentException If the bytesIn argument
     * is not exactly 8 bytes in length (size of a Java long)
     */
    public static long bytesToLong(byte[] bytesIn)
        throws IllegalArgumentException
    {
        // we can only work with arrays containing 8 bytes (size of a Java long)
        if(bytesIn.length != 8)
        {
            throw new IllegalArgumentException( "Input to bytesToLong is " +
                                                bytesIn.length + " bytes long" +
                                                ", instead of 8 bytes");
        }

        return bytesToLongNum(bytesIn);
    }

    /**
     * Generic helper method to prevent algorithm duplication
     *
     * @param bytesIn The byte array to be converted to it's equivalent long value
     *
     * @return The resultant long. This should be cast back to the required
     * type in the calling method. Since this method uses the removeSign helper
     * method, calling code can be sure that the truncation involved in casting
     * this long back to the desired type will not affect the value of the number
     * in any way.
     */
    private static long bytesToLongNum(byte[] bytesIn)
    {
        // we can find out how many times to perform the ORing and
        // shifting by examining the size of the byte[] argument
        int numberOfOps      = (bytesIn.length - 1);
        long returnValue     = 0;
        long cleanValue      = 0;

        for(int i = 0; i < numberOfOps; i++)
        {
            cleanValue  = removeSign(bytesIn[i]);
            returnValue = (returnValue | cleanValue);
            returnValue <<= 8;
        }

        cleanValue    = removeSign(bytesIn[numberOfOps]);
        returnValue   = (returnValue | cleanValue);

        return returnValue;
    }

    /**
     * Helper method to 'clean' (convert to all zeros) the most significant 7
     * bytes of a long, whilst preserving the least significant byte. This is
     * necessary in order to prevent negative bytes from having their sign
     * extended after promotion to a long, which would give unexpected results
     * when performing AND/OR operations involving the promoted byte and some
     * other number.
     *
     * @param num The number to be cleaned. This can also be of any integral type
     * narrower than a long (e.g. byte), due to method call type promotion.
     *
     * @return The 'clean' number
     */
    private static long removeSign(long num)
    {
        // this mask contains all zeros in the most significant
        // 7 bytes and all 1s in the least significant byte
        long bitMask = 0xff;
        // by ANDing with the mask, only the least significant byte of the
        // original number will be preserved - every other bit will be set to 0
        return (num & bitMask);
    }

    /**
     * Converts a given byte array of arbitrary length into it's String
     * equivalent, using the platform's default character encoding. The length
     * of the new String is a function of the encoding, and hence may not be
     * equal to the length of the byte array.
     *
     * @param bytesIn the byte array to be converted
     *
     * @return The resultant String
     */
    public static String bytesToString(byte[] bytesIn)
    {
        return new String(bytesIn);
    }

    ///////////////////////////////////////////////////////////////////////////
    //              METHODS TO CONVERT PRIMITIVES TO  BYTE ARRAYS
    ///////////////////////////////////////////////////////////////////////////

    /**
     * Converts num to an array of bytes. The bytes are
     * written out in the conventional 'right-to-left' manner, i.e.
     * the last byte in the array will be the rightmost eight bits
     * of num. This allows the reader to take the bytes
     * and read them from array index[0] to array index[length - 1],
     * left-shifting after each read, thus reconstituting all the bits
     * in their original order (note Java's 'big endian' architecture).
     *
     * @param num The short to be converted
     *
     * @return A byte array representation of num
     */
    public static byte[] shortToBytes(short num)
    {
        return buildByteArray(2, num);
    }

    /**
     * Converts num to an array of bytes. The bytes are
     * written out in the conventional 'right-to-left' manner, i.e.
     * the last byte in the array will be the rightmost eight bits
     * of num. This allows the reader to take the bytes
     * and read them from array index[0] to array index[length - 1],
     * left-shifting after each read, thus reconstituting all the bits
     * in their original order.
     *
     * @param num The int to be converted
     *
     * @return A byte array representation of num
     */
    public static byte[] intToBytes(int num)
    {
        return buildByteArray(4, num);
    }

    /**
     * Converts num to an array of bytes. The bytes are
     * written out in the conventional 'right-to-left' manner, i.e.
     * the last byte in the array will be the rightmost eight bits
     * of num. This allows the reader to take the bytes
     * and read them from array index[0] to array index[length - 1],
     * left-shifting after each read, thus reconstituting all the bits
     * in their original order.
     *
     * @param num The long to be converted
     *
     * @return A byte array representation of num
     */
    public static byte[] longToBytes(long num)
    {
        return buildByteArray(8, num);
    }

    /**
     * Helper method - performs shifting & recording into byte array
     * for all integral types.
     *
     * @param size The size of the byte array required. This should
     * always correspond to the size in bytes of the original data type
     * being passed, i.e. 2 for shorts, 4 for ints, 8 for longs.
     * @param num The number to be converted. Integral types smaller than
     * long can also be passed to this method, due to type promotion in
     * method calls. This makes it a general purpose method for all the
     * numeric types handled by this class.
     *
     * @return The resultant byte array
     */
    private static byte[] buildByteArray(int size, long num)
    {
        byte[] returnValue = new byte[size];

        int numberOfShifts = (size - 1);

        // :NB: Java is 'big endian' - this dictates the position
        // in the byte array where we must add each successive byte -
        // most significant bit must be in leftmost position of array

        for(int i = 0; i < numberOfShifts; i++)
        {
            // get the current least significant (rightmost) 8 bits
            byte b = (byte)num;
            // add them to the outermost free place in the byte[]
            returnValue[numberOfShifts - i] = b;
            // use the unsigned rightshift operator, since
            // there is no need to preserve the sign.
            num >>>= 8;
        }

        // now put the final 8 bits (originally most significant)
        // in at 1st (leftmost) position
        returnValue[0] = (byte)num;

        return returnValue;
    }

    /**
     * Converts s to an array of bytes according to
     * the platform's default character encoding.
     *
     * @param s The String to be converted
     *
     * @return A byte array representation of s
     */
     public static byte[] stringToBytes(String s)
     {
        return s.getBytes();
     }
}

BinaryConverter.java