EndianUtil.java
package org.djutils.serialization;
import java.io.UnsupportedEncodingException;
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="https://sim0mq.org/docs/current/license.html">Sim0MQ License</a>.
* </p>
* @author <a href="https://www.tudelft.nl/averbraeck">Alexander Verbraeck</a>
*/
public final class EndianUtil
{
/** Does this EndianUtil encode and decode messages in bigEndian? */
private final boolean bigEndian;
/** Is this platform bigEndian? */
private static final boolean PLATFORM_BIG_ENDIAN = ByteOrder.nativeOrder().equals(ByteOrder.BIG_ENDIAN);
/**
* Report whether this platform is bigEndian, or littleEndian.
* @return boolean; true if this platform is bigEndian; false if this platform is littleEndian
*/
public static boolean isPlatformBigEndian()
{
return PLATFORM_BIG_ENDIAN;
}
/** Directly usable bigEndian EndianUtil. */
public static final EndianUtil BIG_ENDIAN = new EndianUtil(true);
/** Directly usable littleEndian EndianUtil. */
public static final EndianUtil LITTLE_ENDIAN = new EndianUtil(false);
/**
* Construct an EndianUtil object with user specified endianness.
* @param bigEndian boolean; if true encoding and decoding use big endian style; if false; encoding and decoding use little
* endian style
*/
private EndianUtil(final boolean bigEndian)
{
this.bigEndian = bigEndian;
}
/**
* Construct an EndianUtil object that uses bigEndian encoding.
* @return EndianUtil that uses bigEndian encoding
*/
public static EndianUtil bigEndian()
{
return BIG_ENDIAN;
}
/**
* Construct an EndianUtil object that uses littleEndian encoding.
* @return EndianUtil that uses littleEndian encoding
*/
public static EndianUtil littleEndian()
{
return LITTLE_ENDIAN;
}
/**
* Report if this EndianUtil is bigEndian.
* @return bigEndian boolean; true if this EndianUtil is bigEndian; false if this EndianUtil is littleEndian
*/
public boolean isBigEndian()
{
return this.bigEndian;
}
/**
* Decode a short.
* @param message the ZeroMQ byte array to decode
* @param pointer the first byte to consider
* @return the short value
*/
public short decodeShort(final byte[] message, final int pointer)
{
if (this.bigEndian)
{
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 int decodeInt(final byte[] message, final int pointer)
{
if (this.bigEndian)
{
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 long decodeLong(final byte[] message, final int pointer)
{
if (this.bigEndian)
{
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 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 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 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
* @throws SerializationException when the bytes cannot be parsed as UTF8
*/
public String decodeUTF8String(final byte[] message, final int pointer) throws SerializationException
{
int len = decodeInt(message, pointer);
byte[] c = new byte[len];
for (int i = 0; i < len; i++)
{
c[i] = message[pointer + i + 4];
}
try
{
return new String(c, "UTF-8");
}
catch (UnsupportedEncodingException e)
{
throw new SerializationException(e);
}
}
/**
* 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 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 int encodeShort(final short v, final byte[] message, final int pointer)
{
int p = pointer;
if (this.bigEndian)
{
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 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
*/
public void encodeInt(final int v, final byte[] message, final int pointer)
{
int p = pointer;
if (this.bigEndian)
{
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);
}
}
/**
* 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 int encodeLong(final long v, final byte[] message, final int pointer)
{
int p = pointer;
if (this.bigEndian)
{
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
*/
public void encodeFloat(final float v, final byte[] message, final int pointer)
{
int vint = Float.floatToIntBits(v);
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 int encodeDouble(final double v, final byte[] message, final int pointer)
{
long vlong = Double.doubleToLongBits(v);
return encodeLong(vlong, message, pointer);
}
@Override
public String toString()
{
return "EndianUtil [bigEndian=" + this.bigEndian + "]";
}
}