View Javadoc
1   package org.sim0mq.message;
2   
3   import org.djunits.unit.Unit;
4   import org.sim0mq.Sim0MQException;
5   import org.sim0mq.message.types.Sim0MQDisplayType;
6   import org.sim0mq.message.types.Sim0MQUnitType;
7   import org.sim0mq.message.types.TypesUtil;
8   import org.sim0mq.message.util.EndianUtil;
9   
10  /**
11   * Container for decoding a message to allow for easy buffer manipulation including the pointer.
12   * <p>
13   * Copyright (c) 2013-2017 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
14   * BSD-style license. See <a href="http://sim0mq.org/docs/current/license.html">Sim0MQ License</a>.
15   * </p>
16   * $LastChangedDate: 2015-07-24 02:58:59 +0200 (Fri, 24 Jul 2015) $, @version $Revision: 1147 $, by $Author: averbraeck $,
17   * initial version Aug 11, 2018 <br>
18   * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
19   */
20  class MessageBuffer
21  {
22      /** the message content. */
23      private byte[] message;
24  
25      /** the pointer into the message content. */
26      private int pointer;
27  
28      /**
29       * Create a message buffer for decoding.
30       * @param message the message
31       */
32      MessageBuffer(final byte[] message)
33      {
34          this.message = message;
35          this.pointer = 0;
36      }
37  
38      /**
39       * @return the pointer into the message buffer
40       */
41      public int getPointer()
42      {
43          return this.pointer;
44      }
45  
46      /**
47       * @return whether the buffer has more bytes to process
48       */
49      public boolean hasMore()
50      {
51          return this.pointer < this.message.length;
52      }
53  
54      /**
55       * @return the next byte in the buffer
56       */
57      public byte getByte()
58      {
59          return this.message[this.pointer++];
60      }
61  
62      /**
63       * @return the next short in the buffer
64       */
65      public short getShort()
66      {
67          short value = EndianUtil.decodeShort(this.message, this.pointer);
68          this.pointer += 2;
69          return value;
70      }
71  
72      /**
73       * @return the next int in the buffer
74       */
75      public int getInt()
76      {
77          int value = EndianUtil.decodeInt(this.message, this.pointer);
78          this.pointer += 4;
79          return value;
80      }
81  
82      /**
83       * @return the next long in the buffer
84       */
85      public long getLong()
86      {
87          long value = EndianUtil.decodeLong(this.message, this.pointer);
88          this.pointer += 8;
89          return value;
90      }
91  
92      /**
93       * @return the next float in the buffer
94       */
95      public float getFloat()
96      {
97          float value = EndianUtil.decodeFloat(this.message, this.pointer);
98          this.pointer += 4;
99          return value;
100     }
101 
102     /**
103      * @return the next double in the buffer
104      */
105     public double getDouble()
106     {
107         double value = EndianUtil.decodeDouble(this.message, this.pointer);
108         this.pointer += 8;
109         return value;
110     }
111 
112     /**
113      * @return the next boolean in the buffer
114      */
115     public boolean getBoolean()
116     {
117         return getByte() == 0 ? false : true;
118     }
119 
120     /**
121      * @return the next char with UTF8 in the buffer
122      */
123     public char getCharUTF8()
124     {
125         return (char) getByte();
126     }
127 
128     /**
129      * @return the next char with UTF16 in the buffer
130      */
131     public char getCharUTF16()
132     {
133         char value = EndianUtil.decodeChar(this.message, this.pointer);
134         this.pointer += 2;
135         return value;
136     }
137 
138     /**
139      * @return the next String with UTF8 in the buffer
140      */
141     public String getStringUTF8()
142     {
143         String s = EndianUtil.decodeUTF8String(this.message, this.pointer);
144         this.pointer += 4 + s.length();
145         return s;
146     }
147 
148     /**
149      * @return the next String with UTF16 in the buffer
150      */
151     public String getStringUTF16()
152     {
153         String s = EndianUtil.decodeUTF16String(this.message, this.pointer);
154         this.pointer += 4 + 2 * s.length();
155         return s;
156     }
157 
158     /**
159      * @return the next 1, 2, or 3 byte Unit in the buffer
160      */
161     public Unit<? extends Unit<?>> getUnit()
162     {
163         Unit<? extends Unit<?>> unit;
164         Sim0MQUnitType unitType = Sim0MQUnitType.getUnitType(getByte());
165         if (unitType.getCode() == 100) // money
166         {
167             unit = decodeMoneyUnit();
168         }
169         else if (unitType.getCode() >= 101 && unitType.getCode() <= 106)
170         {
171             unit = decodeMoneyPerUnit(unitType);
172         }
173         else
174         {
175             Sim0MQDisplayType displayType = Sim0MQDisplayType.getDisplayType(unitType, getByte());
176             unit = displayType.getDjunitsType();
177         }
178         return unit;
179     }
180 
181     /**
182      * Decode the 2-byte Money unit in the message (code 100).
183      * @return decoded money unit
184      */
185     private Unit<? extends Unit<?>> decodeMoneyUnit()
186     {
187         short moneyCode = getShort();
188         Sim0MQDisplayType displayType = Sim0MQDisplayType.getDisplayType(Sim0MQUnitType.MONEY, moneyCode);
189         return displayType.getDjunitsType();
190     }
191 
192     /**
193      * Decode the 2-byte MoneyPerUnit unit in the message (code 101 - 106).
194      * @param unitType the unit type (e.g., MoneyPerArea)
195      * @return decoded MoneyPerUnit unit
196      */
197     @SuppressWarnings("checkstyle:needbraces")
198     private Unit<? extends Unit<?>> decodeMoneyPerUnit(final Sim0MQUnitType unitType)
199     {
200         short moneyCode = getShort();
201         Sim0MQDisplayType moneyDisplayType = Sim0MQDisplayType.getDisplayType(Sim0MQUnitType.MONEY, moneyCode);
202         byte perCode = getByte();
203         Sim0MQDisplayType perDisplayType;
204         if (unitType.getCode() == 101)
205             perDisplayType = Sim0MQDisplayType.getDisplayType(Sim0MQUnitType.AREA, perCode);
206         else if (unitType.getCode() == 102)
207             perDisplayType = Sim0MQDisplayType.getDisplayType(Sim0MQUnitType.ENERGY, perCode);
208         else if (unitType.getCode() == 103)
209             perDisplayType = Sim0MQDisplayType.getDisplayType(Sim0MQUnitType.LENGTH, perCode);
210         else if (unitType.getCode() == 104)
211             perDisplayType = Sim0MQDisplayType.getDisplayType(Sim0MQUnitType.MASS, perCode);
212         else if (unitType.getCode() == 105)
213             perDisplayType = Sim0MQDisplayType.getDisplayType(Sim0MQUnitType.DURATION, perCode);
214         else if (unitType.getCode() == 106)
215             perDisplayType = Sim0MQDisplayType.getDisplayType(Sim0MQUnitType.VOLUME, perCode);
216         else
217             throw new RuntimeException(new Sim0MQException("Unknown MoneyPerUnit type with code " + unitType.getCode()));
218         return TypesUtil.moneyPerUnitType(moneyDisplayType, perDisplayType);
219     }
220 
221 }