1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the 7 * "License"); you may not use this file except in compliance 8 * with the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, 13 * software distributed under the License is distributed on an 14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 * KIND, either express or implied. See the License for the 16 * specific language governing permissions and limitations 17 * under the License. 18 * 19 */ 20 package org.apache.mina.proxy.utils; 21 22 import java.io.UnsupportedEncodingException; 23 24 /** 25 * ByteUtilities.java - Byte manipulation functions. 26 * 27 * @author <a href="http://mina.apache.org">Apache MINA Project</a> 28 * @since MINA 2.0.0-M3 29 */ 30 public class ByteUtilities { 31 32 /** 33 * Returns the integer represented by up to 4 bytes in network byte order. 34 * 35 * @param buf the buffer to read the bytes from 36 * @param start 37 * @param count 38 * @return the integer value 39 */ 40 public static int networkByteOrderToInt(byte[] buf, int start, int count) { 41 if (count > 4) { 42 throw new IllegalArgumentException("Cannot handle more than 4 bytes"); 43 } 44 45 int result = 0; 46 47 for (int i = 0; i < count; i++) { 48 result <<= 8; 49 result |= (buf[start + i] & 0xff); 50 } 51 52 return result; 53 } 54 55 /** 56 * Encodes an integer into up to 4 bytes in network byte order. 57 * 58 * @param num the int to convert to a byte array 59 * @param count the number of reserved bytes for the write operation 60 * @return the resulting byte array 61 */ 62 public static byte[] intToNetworkByteOrder(int num, int count) { 63 byte[] buf = new byte[count]; 64 intToNetworkByteOrder(num, buf, 0, count); 65 66 return buf; 67 } 68 69 /** 70 * Encodes an integer into up to 4 bytes in network byte order in the 71 * supplied buffer starting at <code>start</code> offset and writing 72 * <code>count</code> bytes. 73 * 74 * @param num the int to convert to a byte array 75 * @param buf the buffer to write the bytes to 76 * @param start the offset from beginning for the write operation 77 * @param count the number of reserved bytes for the write operation 78 */ 79 public static void intToNetworkByteOrder(int num, byte[] buf, int start, int count) { 80 if (count > 4) { 81 throw new IllegalArgumentException("Cannot handle more than 4 bytes"); 82 } 83 84 for (int i = count - 1; i >= 0; i--) { 85 buf[start + i] = (byte) (num & 0xff); 86 num >>>= 8; 87 } 88 } 89 90 /** 91 * Write a 16 bit short as LITTLE_ENDIAN. 92 * 93 * @param v the short to write 94 */ 95 public final static byte[] writeShort(short v) { 96 return writeShort(v, new byte[2], 0); 97 } 98 99 /** 100 * Write a 16 bit short as LITTLE_ENDIAN to 101 * the given array <code>b</code> at offset <code>offset</code>. 102 * 103 * @param v the short to write 104 * @param b the byte array to write to 105 * @param offset the offset at which to start writing in the array 106 */ 107 public final static byte[] writeShort(short v, byte[] b, int offset) { 108 b[offset] = (byte) v; 109 b[offset + 1] = (byte) (v >> 8); 110 111 return b; 112 } 113 114 /** 115 * Write a 32 bit int as LITTLE_ENDIAN. 116 * 117 * @param v the int to write 118 */ 119 public final static byte[] writeInt(int v) { 120 return writeInt(v, new byte[4], 0); 121 } 122 123 /** 124 * Write a 32 bit int as LITTLE_ENDIAN to 125 * the given array <code>b</code> at offset <code>offset</code>. 126 * 127 * @param v the int to write 128 * @param b the byte array to write to 129 * @param offset the offset at which to start writing in the array 130 */ 131 public final static byte[] writeInt(int v, byte[] b, int offset) { 132 b[offset] = (byte) v; 133 b[offset + 1] = (byte) (v >> 8); 134 b[offset + 2] = (byte) (v >> 16); 135 b[offset + 3] = (byte) (v >> 24); 136 137 return b; 138 } 139 140 /** 141 * Invert the endianness of words (4 bytes) in the given byte array 142 * starting at the given offset and repeating length/4 times. 143 * eg: b0b1b2b3 -> b3b2b1b0 144 * 145 * @param b the byte array 146 * @param offset the offset at which to change word start 147 * @param length the number of bytes on which to operate 148 * (should be a multiple of 4) 149 */ 150 public final static void changeWordEndianess(byte[] b, int offset, int length) { 151 byte tmp; 152 153 for (int i = offset; i < offset + length; i += 4) { 154 tmp = b[i]; 155 b[i] = b[i + 3]; 156 b[i + 3] = tmp; 157 tmp = b[i + 1]; 158 b[i + 1] = b[i + 2]; 159 b[i + 2] = tmp; 160 } 161 } 162 163 /** 164 * Invert two bytes in the given byte array starting at the given 165 * offset and repeating the inversion length/2 times. 166 * eg: b0b1 -@gt; b1b0 167 * 168 * @param b the byte array 169 * @param offset the offset at which to change word start 170 * @param length the number of bytes on which to operate 171 * (should be a multiple of 2) 172 */ 173 public final static void changeByteEndianess(byte[] b, int offset, int length) { 174 byte tmp; 175 176 for (int i = offset; i < offset + length; i += 2) { 177 tmp = b[i]; 178 b[i] = b[i + 1]; 179 b[i + 1] = tmp; 180 } 181 } 182 183 /** 184 * Converts an OEM string as defined in NTLM protocol (eg ASCII charset) 185 * to a byte array. 186 * 187 * @param s the string to convert 188 * @return the result byte array 189 * @throws UnsupportedEncodingException if the string is not an OEM string 190 */ 191 public final static byte[] getOEMStringAsByteArray(String s) throws UnsupportedEncodingException { 192 return s.getBytes("ASCII"); 193 } 194 195 /** 196 * Converts an UTF-16LE string as defined in NTLM protocol to a byte array. 197 * 198 * @param s the string to convert 199 * @return the result byte array 200 * @throws UnsupportedEncodingException if the string is not an UTF-16LE string 201 */ 202 public final static byte[] getUTFStringAsByteArray(String s) throws UnsupportedEncodingException { 203 return s.getBytes("UTF-16LE"); 204 } 205 206 /** 207 * Encodes the string to a byte array using UTF-16LE or the ASCII charset 208 * in function of the <code>useUnicode</code> argument. 209 * 210 * @param s the string to encode 211 * @param useUnicode if true then string is encoded to UTF-16LE 212 * otherwise to ASCII 213 * @return the encoded string as a byte array 214 * @throws UnsupportedEncodingException if encoding fails 215 */ 216 public final static byte[] encodeString(String s, boolean useUnicode) throws UnsupportedEncodingException { 217 if (useUnicode) { 218 return getUTFStringAsByteArray(s); 219 } 220 221 return getOEMStringAsByteArray(s); 222 } 223 224 /** 225 * Returns a hexadecimal representation of the given byte array. 226 * 227 * @param bytes the array to output to an hex string 228 * @return the hex representation as a string 229 */ 230 public static String asHex(byte[] bytes) { 231 return asHex(bytes, null); 232 } 233 234 /** 235 * Returns a hexadecimal representation of the given byte array. 236 * 237 * @param bytes the array to output to an hex string 238 * @param separator the separator to use between each byte in the output 239 * string. If null no char is inserted between each byte value. 240 * @return the hex representation as a string 241 */ 242 public static String asHex(byte[] bytes, String separator) { 243 StringBuilder sb = new StringBuilder(); 244 for (int i = 0; i < bytes.length; i++) { 245 String code = Integer.toHexString(bytes[i] & 0xFF); 246 if ((bytes[i] & 0xFF) < 16) { 247 sb.append('0'); 248 } 249 250 sb.append(code); 251 252 if (separator != null && i < bytes.length - 1) { 253 sb.append(separator); 254 } 255 } 256 257 return sb.toString(); 258 } 259 260 /** 261 * Converts a hex string representation to a byte array. 262 * 263 * @param hex the string holding the hex values 264 * @return the resulting byte array 265 */ 266 public static byte[] asByteArray(String hex) { 267 byte[] bts = new byte[hex.length() / 2]; 268 for (int i = 0; i < bts.length; i++) { 269 bts[i] = (byte) Integer.parseInt(hex.substring(2 * i, 2 * i + 2), 16); 270 } 271 272 return bts; 273 } 274 275 /** 276 * Reads an int from 4 bytes of the given array at offset 0. 277 * 278 * @param b the byte array to read 279 * @return the integer value 280 */ 281 public static final int makeIntFromByte4(byte[] b) { 282 return makeIntFromByte4(b, 0); 283 } 284 285 /** 286 * Reads an int from 4 bytes of the given array at the given offset. 287 * 288 * @param b the byte array to read 289 * @param offset the offset at which to start 290 * @return the int value 291 */ 292 public static final int makeIntFromByte4(byte[] b, int offset) { 293 return b[offset] << 24 | (b[offset + 1] & 0xff) << 16 | (b[offset + 2] & 0xff) << 8 | (b[offset + 3] & 0xff); 294 } 295 296 /** 297 * Reads an int from 2 bytes of the given array at offset 0. 298 * 299 * @param b the byte array to read 300 * @return the int value 301 */ 302 public static final int makeIntFromByte2(byte[] b) { 303 return makeIntFromByte2(b, 0); 304 } 305 306 /** 307 * Reads an int from 2 bytes of the given array at the given offset. 308 * 309 * @param b the byte array to read 310 * @param offset the offset at which to start 311 * @return the int value 312 */ 313 public static final int makeIntFromByte2(byte[] b, int offset) { 314 return (b[offset] & 0xff) << 8 | (b[offset + 1] & 0xff); 315 } 316 317 /** 318 * Returns true if the flag <code>testFlag</code> is set in the 319 * <code>flags</code> flagset. 320 * 321 * @param flagSet the flagset to test 322 * @param testFlag the flag we search the presence of 323 * @return true if testFlag is present in the flagset, false otherwise. 324 */ 325 public final static boolean isFlagSet(int flagSet, int testFlag) { 326 return (flagSet & testFlag) > 0; 327 } 328 }