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
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 -> 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 * @param offset the offset at which to start
280 * @return the int value
281 */
282 public static final int makeIntFromByte4(byte[] b) {
283 return makeIntFromByte4(b, 0);
284 }
285
286 /**
287 * Reads an int from 4 bytes of the given array at the given offset.
288 *
289 * @param b the byte array to read
290 * @param offset the offset at which to start
291 * @return the int value
292 */
293 public static final int makeIntFromByte4(byte[] b, int offset) {
294 return b[offset] << 24 | (b[offset + 1] & 0xff) << 16 | (b[offset + 2] & 0xff) << 8 | (b[offset + 3] & 0xff);
295 }
296
297 /**
298 * Reads an int from 2 bytes of the given array at offset 0.
299 *
300 * @param b the byte array to read
301 * @return the int value
302 */
303 public static final int makeIntFromByte2(byte[] b) {
304 return makeIntFromByte2(b, 0);
305 }
306
307 /**
308 * Reads an int from 2 bytes of the given array at the given offset.
309 *
310 * @param b the byte array to read
311 * @param offset the offset at which to start
312 * @return the int value
313 */
314 public static final int makeIntFromByte2(byte[] b, int offset) {
315 return (b[offset] & 0xff) << 8 | (b[offset + 1] & 0xff);
316 }
317
318 /**
319 * Returns true if the flag <code>testFlag</code> is set in the
320 * <code>flags</code> flagset.
321 *
322 * @param flagset the flagset to test
323 * @param testFlag the flag we search the presence of
324 * @return true if testFlag is present in the flagset, false otherwise.
325 */
326 public final static boolean isFlagSet(int flagSet, int testFlag) {
327 return (flagSet & testFlag) > 0;
328 }
329 }