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