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(
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 }