View Javadoc

1   package org.jscsi.target.util;
2   
3   
4   import java.nio.ByteBuffer;
5   
6   
7   /**
8    * This utility class contains static methods for reading/writing integers of various lengths and character strings
9    * from/to {@link ByteBuffer} objects and byte arrays.
10   * 
11   * @author Andreas Ergenzinger
12   */
13  public final class ReadWrite {
14  
15      /**
16       * Reads a specified byte from a {@link ByteBuffer} and returns its value as an unsigned integer.
17       * 
18       * @param buffer the {@link ByteBuffer} containing the byte
19       * @param start the index position of the byte in the {@link ByteBuffer}
20       * @return the unsigned integer value of the byte
21       */
22      public static final int readOneByteInt (ByteBuffer buffer, int start) {
23          final byte b = buffer.get(start);
24          return (b & 255);
25      }
26  
27      /**
28       * Reads a specified byte from a byte array and returns its value as an unsigned integer.
29       * 
30       * @param array the array containing the byte
31       * @param start the index position of the byte in the array
32       * @return the unsigned integer value of the byte
33       */
34      public static final int readOneByteInt (byte[] array, int start) {
35          return (array[start] & 255);
36      }
37  
38      /**
39       * Reads an unsigned 2-byte integer from two consecutive big-endian-ordered bytes of a {@link ByteBuffer} object and
40       * returns the value.
41       * 
42       * @param buffer the {@link ByteBuffer} containing the bytes
43       * @param start the index position of the most-significant byte
44       * @return the unsigned value of the two-byte integer
45       */
46      public static final int readTwoByteInt (ByteBuffer buffer, int start) {
47          final byte b1 = buffer.get(start);
48          final byte b2 = buffer.get(start + 1);
49          return ((b1 & 255) << 8) | (b2 & 255);
50      }
51  
52      /**
53       * Reads an unsigned 2-byte integer from two consecutive big-endian-ordered bytes of a byte array and returns the
54       * value.
55       * 
56       * @param array the byte array containing the bytes
57       * @param start the index position of the most-significant byte
58       * @return the unsigned value of the two-byte integer
59       */
60      public static final int readTwoByteInt (byte[] array, int start) {
61          return ((array[start] & 255) << 8) | (array[start + 1] & 255);
62      }
63  
64      /**
65       * Reads an unsigned 3-byte integer from three consecutive big-endian-ordered bytes of a {@link ByteBuffer} object
66       * and returns the value.
67       * 
68       * @param buffer the {@link ByteBuffer} containing the bytes
69       * @param start the index position of the most-significant byte
70       * @return the unsigned value of the three-byte integer
71       */
72      public static final int readThreeByteInt (ByteBuffer buffer, int start) {
73          final byte b1 = buffer.get(start);
74          final byte b2 = buffer.get(start + 1);
75          final byte b3 = buffer.get(start + 2);
76          return ((b1 & 255) << 16) | ((b2 & 255) << 8) | (b3 & 255);
77      }
78  
79      /**
80       * Reads an unsigned 3-byte integer from three consecutive big-endian-ordered bytes of a byte array and returns the
81       * value.
82       * 
83       * @param array the byte array containing the bytes
84       * @param start the index position of the most-significant byte
85       * @return the unsigned value of the three-byte integer
86       */
87      public static final int readThreeByteInt (byte[] array, int start) {
88          return ((array[start] & 255) << 16) | ((array[start + 1] & 255) << 8) | (array[start + 2] & 255);
89      }
90  
91      /**
92       * Reads a (signed) 4-byte integer from four consecutive big-endian-ordered bytes of a {@link ByteBuffer} object and
93       * returns the value.
94       * 
95       * @param buffer the {@link ByteBuffer} containing the bytes
96       * @param start the index position of the most-significant byte
97       * @return the value of the four-byte integer
98       */
99      public static final int readFourByteInt (ByteBuffer buffer, int start) {
100         final byte b1 = buffer.get(start);
101         final byte b2 = buffer.get(start + 1);
102         final byte b3 = buffer.get(start + 2);
103         final byte b4 = buffer.get(start + 3);
104         return ((b1 & 255) << 24) | ((b2 & 255) << 16) | ((b3 & 255) << 8) | (b4 & 255);
105     }
106 
107     /**
108      * Reads a (signed) 4-byte integer from four consecutive big-endian-ordered bytes of a byte array and returns the
109      * value.
110      * 
111      * @param array the byte array containing the bytes
112      * @param start the index position of the most-significant byte
113      * @return the unsigned value of the four-byte integer
114      */
115     public static final int readFourByteInt (byte[] array, int start) {
116         return ((array[start] & 255) << 24) | ((array[start + 1] & 255) << 16) | ((array[start + 2] & 255) << 8) | (array[start + 3] & 255);
117     }
118 
119     /**
120      * Puts the characters in the passed String into an array of one or more ByteBuffers and returns it.
121      * <p>
122      * If the String does not end with a null character, one will be appended. If the String's length is larger than the
123      * specified <i>bufferSize</i>, all but the last ByteBuffer will have <i>capacity() = bufferSize</i>, the last one
124      * will contain the remaining String characters.
125      * 
126      * @param string the String to be put into the ByteBuffer
127      * @param bufferSize the maximum size of the returned ByteBuffers
128      * @return an array of ByteBuffers containing the passed String
129      */
130     public static ByteBuffer[] stringToTextDataSegments (String string, int bufferSize) {
131 
132         int numberOfParts = string.length() / bufferSize + 1;
133         ByteBuffer[] segments = new ByteBuffer[numberOfParts];
134 
135         int bytesRemaining = string.length();
136         for (int i = 0; i < numberOfParts; ++i) {
137             if (bytesRemaining > bufferSize) {
138                 segments[i] = stringToByteBuffer(string.substring(i * bufferSize, (i + 1) * bufferSize));
139             } else {
140                 segments[i] = stringToByteBuffer(string.substring(i * bufferSize));
141             }
142         }
143         return segments;
144     }
145 
146     /**
147      * Puts the characters in the passed String into a ByteBuffer of equal length and returns it.
148      * 
149      * @param string any String
150      * @return a ByteBuffer containing the characters of the passed String
151      */
152     private static ByteBuffer stringToByteBuffer (final String string) {
153         final ByteBuffer buffer = ByteBuffer.allocate(string.length());
154         for (int i = 0; i < string.length(); ++i)
155             buffer.put((byte) string.charAt(i));
156         buffer.clear();
157         return buffer;
158     }
159 
160     /**
161      * Appends the content of a <code>ProtocolDataUnit</code> (text) data segment to a {@link StringBuilder};
162      * 
163      * @param byteBuffer the PDU's data segment
164      * @param stringBuilder the {@link StringBuilder} that will be extended
165      */
166     public static final void appendTextDataSegmentToStringBuffer (final ByteBuffer byteBuffer, final StringBuilder stringBuilder) {
167         final String s = new String(byteBuffer.array());
168         stringBuilder.append(s);
169     }
170 
171     /**
172      * Writes the given <i>value</i> to the <i>buffer</i> in big-endian format, with the index position of the most
173      * significant byte being <i>start</i>.
174      * 
175      * To get the value back from the buffer, use readUnsignedInt.
176      * 
177      * @param value the integer to write to the ByteBuffer
178      * @param buffer where the integer will be stored
179      * @param start index of the most significant byte of the stored <i>value</i>
180      */
181     public static final void writeInt (int value, final ByteBuffer buffer, int start) {
182         buffer.position(start);
183         buffer.put((byte) (value >>> 24));
184         buffer.put((byte) (value >>> 16));
185         buffer.put((byte) (value >>> 8));
186         buffer.put((byte) value);
187     }
188 
189     /**
190      * Returns the bytes in a {@link ByteBuffer} as a UTF-8 encoded {@link String}.
191      * 
192      * @param buffer a {@link ByteBuffer} containing UTF-8 encoded characters.
193      * @return a String representation of the <i>buffer</i>'s content
194      */
195     public static String byteBufferToString (final ByteBuffer buffer) {
196         buffer.rewind();
197         return new String(buffer.array());
198     }
199 
200     /**
201      * Splits the passed <i>value</i> into bytes and returns them in an array, in big-endian format.
202      * 
203      * @param value the long to split
204      * @return byte representation of the parameter
205      */
206     public static byte[] longToBytes (final long value) {
207         final byte[] bytes = new byte[8];
208         for (int i = 0; i < bytes.length; ++i)
209             bytes[i] = (byte) (value >> (8 * (bytes.length - 1 - i)));
210         return bytes;
211     }
212 
213     /**
214      * Writes the given <i>value</i> to the <i>buffer</i> in big-endian format, with the index position of the most
215      * significant byte being <i>index</i>.
216      * 
217      * @param value the integer to write to the ByteBuffer
218      * @param buffer where the integer will be stored
219      * @param index index of the most significant byte of the stored <i>value</i>
220      */
221     public static void writeLong (final ByteBuffer buffer, final long value, final int index) {
222         final byte[] bytes = longToBytes(value);
223         buffer.position(index);
224         for (int i = 0; i < bytes.length; ++i)
225             buffer.put(bytes[i]);
226     }
227 
228     /**
229      * Writes the two least-significant big-endian-ordered bytes of an integer the a specified position in a
230      * {@link ByteBuffer}.
231      * 
232      * @param buffer where the bytes will be written
233      * @param value the value to convert and copy
234      * @param index the position of the most significant byte in the {@link ByteBuffer}
235      */
236     public static void writeTwoByteInt (final ByteBuffer buffer, final int value, final int index) {
237         buffer.position(index);
238         buffer.put((byte) (value >> 8));// most significant byte
239         buffer.put((byte) value);// least significant byte
240     }
241 
242     /**
243      * Writes the three least-significant big-endian-ordered bytes of an integer the a specified position in a
244      * {@link ByteBuffer}.
245      * 
246      * @param buffer where the bytes will be written
247      * @param value the value to convert and copy
248      * @param index the position of the most significant byte in the {@link ByteBuffer}
249      */
250     public static void writeThreeByteInt (final ByteBuffer buffer, final int value, final int index) {
251 
252         buffer.position(index);
253         buffer.put((byte) (value >> 16));// most significant byte
254         buffer.put((byte) (value >> 8));
255         buffer.put((byte) value);// least significant byte
256     }
257 
258     /**
259      * Reads an unsigned 4-byte integer from four consecutive big-endian-ordered bytes of a {@link ByteBuffer} object
260      * and returns the value.
261      * 
262      * @param buffer the {@link ByteBuffer} containing the bytes
263      * @param start the index position of the most-significant byte
264      * @return the value of the unsigned four-byte integer
265      */
266     public static long readUnsignedInt (final ByteBuffer buffer, final int start) {
267         return readFourByteInt(buffer, start) & 0xffffffffL;
268     }
269 
270 }