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 }