EndianUtil.java

package org.sim0mq.message.util;

import java.nio.ByteOrder;

/**
 * Method to help with Little Endian / Big Endian conversions for the Sim0MQ messages. All Sim0MQ messages are encoded Big
 * Endian over the wire.
 * <p>
 * Copyright (c) 2016-2017 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
 * BSD-style license. See <a href="http://sim0mq.org/docs/current/license.html">Sim0MQ License</a>.
 * </p>
 * $LastChangedDate: 2015-07-24 02:58:59 +0200 (Fri, 24 Jul 2015) $, @version $Revision: 1147 $, by $Author: averbraeck $,
 * initial version Dec 15, 2016 <br>
 * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
 */
public final class EndianUtil
{
    /** do we want to send the messages in big endian? */
    private static boolean defaultBigEndian = true;

    /** is the platform big endian? */
    private static final boolean PLATFORM_BIG_ENDIAN = ByteOrder.nativeOrder().equals(ByteOrder.BIG_ENDIAN);

    /**
     * Utility class - do not instantiate.
     */
    private EndianUtil()
    {
        //
    }

    /**
     * Decode a short.
     * @param message the ZeroMQ byte array to decode
     * @param pointer the first byte to consider
     * @return the short value
     */
    public static short decodeShort(final byte[] message, final int pointer)
    {
        if (defaultBigEndian)
        {
            return (short) (((message[pointer] & 0xff) << 8) | ((message[pointer + 1] & 0xff)));
        }
        else
        {
            return (short) (((message[pointer + 1] & 0xff) << 8) | ((message[pointer] & 0xff)));
        }
    }

    /**
     * Decode a int.
     * @param message the ZeroMQ byte array to decode
     * @param pointer the first byte to consider
     * @return the integer value
     */
    public static int decodeInt(final byte[] message, final int pointer)
    {
        if (defaultBigEndian)
        {
            return (((message[pointer] & 0xff) << 24) | ((message[pointer + 1] & 0xff) << 16)
                    | ((message[pointer + 2] & 0xff) << 8) | ((message[pointer + 3] & 0xff)));
        }
        else
        {
            return (((message[pointer + 3] & 0xff) << 24) | ((message[pointer + 2] & 0xff) << 16)
                    | ((message[pointer + 1] & 0xff) << 8) | ((message[pointer] & 0xff)));
        }
    }

    /**
     * Decode a long.
     * @param message the ZeroMQ byte array to decode
     * @param pointer the first byte to consider
     * @return the long value
     */
    public static long decodeLong(final byte[] message, final int pointer)
    {
        if (defaultBigEndian)
        {
            return ((((long) message[pointer]) << 56) | (((long) message[pointer + 1] & 0xff) << 48)
                    | (((long) message[pointer + 2] & 0xff) << 40) | (((long) message[pointer + 3] & 0xff) << 32)
                    | (((long) message[pointer + 4] & 0xff) << 24) | (((long) message[pointer + 5] & 0xff) << 16)
                    | (((long) message[pointer + 6] & 0xff) << 8) | (((long) message[pointer + 7] & 0xff)));
        }
        else
        {
            return ((((long) message[pointer + 7]) << 56) | (((long) message[pointer + 6] & 0xff) << 48)
                    | (((long) message[pointer + 5] & 0xff) << 40) | (((long) message[pointer + 4] & 0xff) << 32)
                    | (((long) message[pointer + 3] & 0xff) << 24) | (((long) message[pointer + 2] & 0xff) << 16)
                    | (((long) message[pointer + 1] & 0xff) << 8) | (((long) message[pointer] & 0xff)));
        }
    }

    /**
     * Decode a float.
     * @param message the ZeroMQ byte array to decode
     * @param pointer the first byte to consider
     * @return the float value
     */
    public static float decodeFloat(final byte[] message, final int pointer)
    {
        int bits = decodeInt(message, pointer);
        return Float.intBitsToFloat(bits);
    }

    /**
     * Decode a double.
     * @param message the ZeroMQ byte array to decode
     * @param pointer the first byte to consider
     * @return the double value
     */
    public static double decodeDouble(final byte[] message, final int pointer)
    {
        long bits = decodeLong(message, pointer);
        return Double.longBitsToDouble(bits);
    }

    /**
     * Decode a char (16 bits).
     * @param message the ZeroMQ byte array to decode
     * @param pointer the first byte to consider
     * @return the short value
     */
    public static char decodeChar(final byte[] message, final int pointer)
    {
        return (char) decodeShort(message, pointer);
    }

    /**
     * Decode a String including the length int from the message byte array.
     * @param message the message byte array
     * @param pointer the start position in the array
     * @return the Java String at position pointer
     */
    public static String decodeUTF8String(final byte[] message, final int pointer)
    {
        int len = decodeInt(message, pointer);
        char[] c = new char[len];
        for (int i = 0; i < len; i++)
        {
            c[i] = (char) message[pointer + i + 4];
        }
        return String.copyValueOf(c);
    }

    /**
     * Decode a String including the length int from the message byte array.
     * @param message the message byte array
     * @param pointer the start position in the array
     * @return the Java String at position pointer
     */
    public static String decodeUTF16String(final byte[] message, final int pointer)
    {
        int len = decodeInt(message, pointer);
        char[] c = new char[len];
        for (int i = 0; i < len; i++)
        {
            c[i] = decodeChar(message, pointer + 2 * i + 4);
        }
        return String.copyValueOf(c);
    }

    /**
     * Encode a short into a message buffer.
     * @param v the variable to encode
     * @param message the message buffer to encode the variable into
     * @param pointer the pointer to start writing
     * @return the new pointer after writing
     */
    public static int encodeShort(final short v, final byte[] message, final int pointer)
    {
        int p = pointer;
        if (defaultBigEndian)
        {
            message[p++] = (byte) (v >> 8);
            message[p++] = (byte) (v);
        }
        else
        {
            message[p++] = (byte) (v);
            message[p++] = (byte) (v >> 8);
        }
        return p;
    }

    /**
     * Encode a char (16 bits) into a message buffer.
     * @param v the variable to encode
     * @param message the message buffer to encode the variable into
     * @param pointer the pointer to start writing
     * @return the new pointer after writing
     */
    public static int encodeChar(final char v, final byte[] message, final int pointer)
    {
        return encodeShort((short) v, message, pointer);
    }

    /**
     * Encode a int into a message buffer.
     * @param v the variable to encode
     * @param message the message buffer to encode the variable into
     * @param pointer the pointer to start writing
     * @return the new pointer after writing
     */
    public static int encodeInt(final int v, final byte[] message, final int pointer)
    {
        int p = pointer;
        if (defaultBigEndian)
        {
            message[p++] = (byte) ((v >> 24) & 0xFF);
            message[p++] = (byte) ((v >> 16) & 0xFF);
            message[p++] = (byte) ((v >> 8) & 0xFF);
            message[p++] = (byte) (v & 0xFF);
        }
        else
        {
            message[p++] = (byte) (v & 0xFF);
            message[p++] = (byte) ((v >> 8) & 0xFF);
            message[p++] = (byte) ((v >> 16) & 0xFF);
            message[p++] = (byte) ((v >> 24) & 0xFF);
        }
        return p;
    }

    /**
     * Encode a long into a message buffer.
     * @param v the variable to encode
     * @param message the message buffer to encode the variable into
     * @param pointer the pointer to start writing
     * @return the new pointer after writing
     */
    public static int encodeLong(final long v, final byte[] message, final int pointer)
    {
        int p = pointer;
        if (defaultBigEndian)
        {
            message[p++] = (byte) ((v >> 56) & 0xFF);
            message[p++] = (byte) ((v >> 48) & 0xFF);
            message[p++] = (byte) ((v >> 40) & 0xFF);
            message[p++] = (byte) ((v >> 32) & 0xFF);
            message[p++] = (byte) ((v >> 24) & 0xFF);
            message[p++] = (byte) ((v >> 16) & 0xFF);
            message[p++] = (byte) ((v >> 8) & 0xFF);
            message[p++] = (byte) (v & 0xFF);
        }
        else
        {
            message[p++] = (byte) (v & 0xFF);
            message[p++] = (byte) ((v >> 8) & 0xFF);
            message[p++] = (byte) ((v >> 16) & 0xFF);
            message[p++] = (byte) ((v >> 24) & 0xFF);
            message[p++] = (byte) ((v >> 32) & 0xFF);
            message[p++] = (byte) ((v >> 40) & 0xFF);
            message[p++] = (byte) ((v >> 48) & 0xFF);
            message[p++] = (byte) ((v >> 56) & 0xFF);
        }
        return p;
    }

    /**
     * Encode a float into a message buffer.
     * @param v the variable to encode
     * @param message the message buffer to encode the variable into
     * @param pointer the pointer to start writing
     * @return the new pointer after writing
     */
    public static int encodeFloat(final float v, final byte[] message, final int pointer)
    {
        int vint = Float.floatToIntBits(v);
        return encodeInt(vint, message, pointer);
    }

    /**
     * Encode a double into a message buffer.
     * @param v the variable to encode
     * @param message the message buffer to encode the variable into
     * @param pointer the pointer to start writing
     * @return the new pointer after writing
     */
    public static int encodeDouble(final double v, final byte[] message, final int pointer)
    {
        long vlong = Double.doubleToLongBits(v);
        return encodeLong(vlong, message, pointer);
    }

    /**
     * Return a long encoded as a byte array.
     * @param v the long variable to encode
     * @return the byte array.
     */
    public static byte[] longToByteArray(final long v)
    {
        byte[] message = new byte[8];
        int pointer = 0;
        encodeLong(v, message, pointer);
        return message;
    }

    /**
     * Return an int encoded as a byte array.
     * @param v the int variable to encode
     * @return the byte array.
     */
    public static byte[] intToByteArray(final int v)
    {
        byte[] message = new byte[4];
        int pointer = 0;
        encodeInt(v, message, pointer);
        return message;
    }

    /**
     * Return a double encoded as a byte array.
     * @param v the double variable to encode
     * @return the byte array.
     */
    public static byte[] doubleToByteArray(final double v)
    {
        byte[] message = new byte[8];
        int pointer = 0;
        encodeDouble(v, message, pointer);
        return message;
    }

    /**
     * Return a float encoded as a byte array.
     * @param v the float variable to encode
     * @return the byte array.
     */
    public static byte[] floatToByteArray(final float v)
    {
        byte[] message = new byte[4];
        int pointer = 0;
        encodeFloat(v, message, pointer);
        return message;
    }

    /**
     * @return defaultBigEndian
     */
    public static boolean isDefaultBigEndian()
    {
        return defaultBigEndian;
    }

    /**
     * @param defaultBigEndian set defaultBigEndian
     */
    public static void setDefaultBigEndian(final boolean defaultBigEndian)
    {
        EndianUtil.defaultBigEndian = defaultBigEndian;
    }

    /**
     * @return platformbigendian
     */
    public static boolean isPlatformBigEndian()
    {
        return PLATFORM_BIG_ENDIAN;
    }

}