MessageBuffer.java
package org.sim0mq.message;
import org.djunits.unit.Unit;
import org.sim0mq.Sim0MQException;
import org.sim0mq.message.types.Sim0MQDisplayType;
import org.sim0mq.message.types.Sim0MQUnitType;
import org.sim0mq.message.types.TypesUtil;
import org.sim0mq.message.util.EndianUtil;
/**
* Container for decoding a message to allow for easy buffer manipulation including the pointer.
* <p>
* Copyright (c) 2013-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 Aug 11, 2018 <br>
* @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
*/
class MessageBuffer
{
/** the message content. */
private byte[] message;
/** the pointer into the message content. */
private int pointer;
/**
* Create a message buffer for decoding.
* @param message the message
*/
MessageBuffer(final byte[] message)
{
this.message = message;
this.pointer = 0;
}
/**
* @return the pointer into the message buffer
*/
public int getPointer()
{
return this.pointer;
}
/**
* @return whether the buffer has more bytes to process
*/
public boolean hasMore()
{
return this.pointer < this.message.length;
}
/**
* @return the next byte in the buffer
*/
public byte getByte()
{
return this.message[this.pointer++];
}
/**
* @return the next short in the buffer
*/
public short getShort()
{
short value = EndianUtil.decodeShort(this.message, this.pointer);
this.pointer += 2;
return value;
}
/**
* @return the next int in the buffer
*/
public int getInt()
{
int value = EndianUtil.decodeInt(this.message, this.pointer);
this.pointer += 4;
return value;
}
/**
* @return the next long in the buffer
*/
public long getLong()
{
long value = EndianUtil.decodeLong(this.message, this.pointer);
this.pointer += 8;
return value;
}
/**
* @return the next float in the buffer
*/
public float getFloat()
{
float value = EndianUtil.decodeFloat(this.message, this.pointer);
this.pointer += 4;
return value;
}
/**
* @return the next double in the buffer
*/
public double getDouble()
{
double value = EndianUtil.decodeDouble(this.message, this.pointer);
this.pointer += 8;
return value;
}
/**
* @return the next boolean in the buffer
*/
public boolean getBoolean()
{
return getByte() == 0 ? false : true;
}
/**
* @return the next char with UTF8 in the buffer
*/
public char getCharUTF8()
{
return (char) getByte();
}
/**
* @return the next char with UTF16 in the buffer
*/
public char getCharUTF16()
{
char value = EndianUtil.decodeChar(this.message, this.pointer);
this.pointer += 2;
return value;
}
/**
* @return the next String with UTF8 in the buffer
*/
public String getStringUTF8()
{
String s = EndianUtil.decodeUTF8String(this.message, this.pointer);
this.pointer += 4 + s.length();
return s;
}
/**
* @return the next String with UTF16 in the buffer
*/
public String getStringUTF16()
{
String s = EndianUtil.decodeUTF16String(this.message, this.pointer);
this.pointer += 4 + 2 * s.length();
return s;
}
/**
* @return the next 1, 2, or 3 byte Unit in the buffer
*/
public Unit<? extends Unit<?>> getUnit()
{
Unit<? extends Unit<?>> unit;
Sim0MQUnitType unitType = Sim0MQUnitType.getUnitType(getByte());
if (unitType.getCode() == 100) // money
{
unit = decodeMoneyUnit();
}
else if (unitType.getCode() >= 101 && unitType.getCode() <= 106)
{
unit = decodeMoneyPerUnit(unitType);
}
else
{
Sim0MQDisplayType displayType = Sim0MQDisplayType.getDisplayType(unitType, getByte());
unit = displayType.getDjunitsType();
}
return unit;
}
/**
* Decode the 2-byte Money unit in the message (code 100).
* @return decoded money unit
*/
private Unit<? extends Unit<?>> decodeMoneyUnit()
{
short moneyCode = getShort();
Sim0MQDisplayType displayType = Sim0MQDisplayType.getDisplayType(Sim0MQUnitType.MONEY, moneyCode);
return displayType.getDjunitsType();
}
/**
* Decode the 2-byte MoneyPerUnit unit in the message (code 101 - 106).
* @param unitType the unit type (e.g., MoneyPerArea)
* @return decoded MoneyPerUnit unit
*/
@SuppressWarnings("checkstyle:needbraces")
private Unit<? extends Unit<?>> decodeMoneyPerUnit(final Sim0MQUnitType unitType)
{
short moneyCode = getShort();
Sim0MQDisplayType moneyDisplayType = Sim0MQDisplayType.getDisplayType(Sim0MQUnitType.MONEY, moneyCode);
byte perCode = getByte();
Sim0MQDisplayType perDisplayType;
if (unitType.getCode() == 101)
perDisplayType = Sim0MQDisplayType.getDisplayType(Sim0MQUnitType.AREA, perCode);
else if (unitType.getCode() == 102)
perDisplayType = Sim0MQDisplayType.getDisplayType(Sim0MQUnitType.ENERGY, perCode);
else if (unitType.getCode() == 103)
perDisplayType = Sim0MQDisplayType.getDisplayType(Sim0MQUnitType.LENGTH, perCode);
else if (unitType.getCode() == 104)
perDisplayType = Sim0MQDisplayType.getDisplayType(Sim0MQUnitType.MASS, perCode);
else if (unitType.getCode() == 105)
perDisplayType = Sim0MQDisplayType.getDisplayType(Sim0MQUnitType.DURATION, perCode);
else if (unitType.getCode() == 106)
perDisplayType = Sim0MQDisplayType.getDisplayType(Sim0MQUnitType.VOLUME, perCode);
else
throw new RuntimeException(new Sim0MQException("Unknown MoneyPerUnit type with code " + unitType.getCode()));
return TypesUtil.moneyPerUnitType(moneyDisplayType, perDisplayType);
}
}