001/*
002 *  Licensed to the Apache Software Foundation (ASF) under one
003 *  or more contributor license agreements.  See the NOTICE file
004 *  distributed with this work for additional information
005 *  regarding copyright ownership.  The ASF licenses this file
006 *  to you under the Apache License, Version 2.0 (the
007 *  "License"); you may not use this file except in compliance
008 *  with the License.  You may obtain a copy of the License at
009 *
010 *    http://www.apache.org/licenses/LICENSE-2.0
011 *
012 *  Unless required by applicable law or agreed to in writing,
013 *  software distributed under the License is distributed on an
014 *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 *  KIND, either express or implied.  See the License for the
016 *  specific language governing permissions and limitations
017 *  under the License.
018 *
019 */
020package org.apache.mina.proxy.utils;
021
022import java.io.UnsupportedEncodingException;
023
024/**
025 * ByteUtilities.java - Byte manipulation functions.
026 * 
027 * @author <a href="http://mina.apache.org">Apache MINA Project</a>
028 * @since MINA 2.0.0-M3
029 */
030public class ByteUtilities {
031
032    /**
033     * Returns the integer represented by up to 4 bytes in network byte order.
034     * 
035     * @param buf the buffer to read the bytes from
036     * @param start The starting position
037     * @param count The number of bytes to in the buffer
038     * @return the integer value
039     */
040    public static int networkByteOrderToInt(byte[] buf, int start, int count) {
041        if (count > 4) {
042            throw new IllegalArgumentException("Cannot handle more than 4 bytes");
043        }
044
045        int result = 0;
046
047        for (int i = 0; i < count; i++) {
048            result <<= 8;
049            result |= (buf[start + i] & 0xff);
050        }
051
052        return result;
053    }
054
055    /**
056     * Encodes an integer into up to 4 bytes in network byte order.
057     * 
058     * @param num the int to convert to a byte array
059     * @param count the number of reserved bytes for the write operation
060     * @return the resulting byte array
061     */
062    public static byte[] intToNetworkByteOrder(int num, int count) {
063        byte[] buf = new byte[count];
064        intToNetworkByteOrder(num, buf, 0, count);
065
066        return buf;
067    }
068
069    /**
070     * Encodes an integer into up to 4 bytes in network byte order in the 
071     * supplied buffer starting at <code>start</code> offset and writing
072     * <code>count</code> bytes.
073     * 
074     * @param num the int to convert to a byte array
075     * @param buf the buffer to write the bytes to
076     * @param start the offset from beginning for the write operation
077     * @param count the number of reserved bytes for the write operation
078     */
079    public static void intToNetworkByteOrder(int num, byte[] buf, int start, int count) {
080        if (count > 4) {
081            throw new IllegalArgumentException("Cannot handle more than 4 bytes");
082        }
083
084        for (int i = count - 1; i >= 0; i--) {
085            buf[start + i] = (byte) (num & 0xff);
086            num >>>= 8;
087        }
088    }
089
090    /**
091     * Write a 16 bit short as LITTLE_ENDIAN.
092     * 
093     * @param v the short to write
094     * @return the Short in a byte[]
095     */
096    public final static byte[] writeShort(short v) {
097        return writeShort(v, new byte[2], 0);
098    }
099
100    /**
101     * Write a 16 bit short as LITTLE_ENDIAN to
102     * the given array <code>b</code> at offset <code>offset</code>.
103     * 
104     * @param v the short to write
105     * @param b the byte array to write to
106     * @param offset the offset at which to start writing in the array
107     * @return the Short in a byte[]
108     */
109    public final static byte[] writeShort(short v, byte[] b, int offset) {
110        b[offset] = (byte) v;
111        b[offset + 1] = (byte) (v >> 8);
112
113        return b;
114    }
115
116    /**
117     * Write a 32 bit int as LITTLE_ENDIAN.
118     * 
119     * @param v the int to write
120     * @return the Int in a byte[]
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     * @return the Int in a byte[]
134     */
135    public final static byte[] writeInt(int v, byte[] b, int offset) {
136        b[offset] = (byte) v;
137        b[offset + 1] = (byte) (v >> 8);
138        b[offset + 2] = (byte) (v >> 16);
139        b[offset + 3] = (byte) (v >> 24);
140
141        return b;
142    }
143
144    /**
145     * Invert the endianness of words (4 bytes) in the given byte array 
146     * starting at the given offset and repeating length/4 times.
147     * eg: b0b1b2b3 -&gt; b3b2b1b0 
148     * 
149     * @param b the byte array 
150     * @param offset the offset at which to change word start
151     * @param length the number of bytes on which to operate 
152     * (should be a multiple of 4)
153     */
154    public final static void changeWordEndianess(byte[] b, int offset, 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 -@gt; 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, int length) {
178        byte tmp;
179
180        for (int i = offset; i < offset + length; i += 2) {
181            tmp = b[i];
182            b[i] = b[i + 1];
183            b[i + 1] = tmp;
184        }
185    }
186
187    /**
188     * Converts an OEM string as defined in NTLM protocol (eg ASCII charset)
189     * to a byte array.
190     * 
191     * @param s the string to convert
192     * @return the result byte array
193     * @throws UnsupportedEncodingException if the string is not an OEM string
194     */
195    public final static byte[] getOEMStringAsByteArray(String s) throws UnsupportedEncodingException {
196        return s.getBytes("ASCII");
197    }
198
199    /**
200     * Converts an UTF-16LE string as defined in NTLM protocol to a byte array.
201     * 
202     * @param s the string to convert
203     * @return the result byte array
204     * @throws UnsupportedEncodingException if the string is not an UTF-16LE string
205     */
206    public final static byte[] getUTFStringAsByteArray(String s) throws UnsupportedEncodingException {
207        return s.getBytes("UTF-16LE");
208    }
209
210    /**
211     * Encodes the string to a byte array using UTF-16LE or the ASCII charset
212     * in function of the <code>useUnicode</code> argument.
213     * 
214     * @param s the string to encode
215     * @param useUnicode if true then string is encoded to UTF-16LE 
216     * otherwise to ASCII
217     * @return the encoded string as a byte array
218     * @throws UnsupportedEncodingException if encoding fails
219     */
220    public final static byte[] encodeString(String s, boolean useUnicode) throws UnsupportedEncodingException {
221        if (useUnicode) {
222            return getUTFStringAsByteArray(s);
223        }
224
225        return getOEMStringAsByteArray(s);
226    }
227
228    /**
229     * Returns a hexadecimal representation of the given byte array.
230     * 
231     * @param bytes the array to output to an hex string
232     * @return the hex representation as a string
233     */
234    public static String asHex(byte[] bytes) {
235        return asHex(bytes, null);
236    }
237
238    /**
239     * Returns a hexadecimal representation of the given byte array.
240     * 
241     * @param bytes the array to output to an hex string
242     * @param separator the separator to use between each byte in the output
243     * string. If null no char is inserted between each byte value. 
244     * @return the hex representation as a string
245     */
246    public static String asHex(byte[] bytes, String separator) {
247        StringBuilder sb = new StringBuilder();
248        for (int i = 0; i < bytes.length; i++) {
249            String code = Integer.toHexString(bytes[i] & 0xFF);
250            if ((bytes[i] & 0xFF) < 16) {
251                sb.append('0');
252            }
253
254            sb.append(code);
255
256            if (separator != null && i < bytes.length - 1) {
257                sb.append(separator);
258            }
259        }
260
261        return sb.toString();
262    }
263
264    /**
265     * Converts a hex string representation to a byte array.
266     * 
267     * @param hex the string holding the hex values
268     * @return the resulting byte array
269     */
270    public static byte[] asByteArray(String hex) {
271        byte[] bts = new byte[hex.length() / 2];
272        for (int i = 0; i < bts.length; i++) {
273            bts[i] = (byte) Integer.parseInt(hex.substring(2 * i, 2 * i + 2), 16);
274        }
275
276        return bts;
277    }
278
279    /**
280     * Reads an int from 4 bytes of the given array at offset 0.
281     * 
282     * @param b the byte array to read
283     * @return the integer value
284     */
285    public static final int makeIntFromByte4(byte[] b) {
286        return makeIntFromByte4(b, 0);
287    }
288
289    /**
290     * Reads an int from 4 bytes of the given array at the given offset.
291     * 
292     * @param b the byte array to read
293     * @param offset the offset at which to start
294     * @return the int value
295     */
296    public static final int makeIntFromByte4(byte[] b, int offset) {
297        return b[offset] << 24 | (b[offset + 1] & 0xff) << 16 | (b[offset + 2] & 0xff) << 8 | (b[offset + 3] & 0xff);
298    }
299
300    /**
301     * Reads an int from 2 bytes of the given array at offset 0.
302     * 
303     * @param b the byte array to read
304     * @return the int value     
305     */
306    public static final int makeIntFromByte2(byte[] b) {
307        return makeIntFromByte2(b, 0);
308    }
309
310    /**
311     * Reads an int from 2 bytes of the given array at the given offset.
312     * 
313     * @param b the byte array to read
314     * @param offset the offset at which to start
315     * @return the int value
316     */
317    public static final int makeIntFromByte2(byte[] b, int offset) {
318        return (b[offset] & 0xff) << 8 | (b[offset + 1] & 0xff);
319    }
320
321    /**
322     * Returns true if the flag <code>testFlag</code> is set in the
323     * <code>flags</code> flagset.
324     * 
325     * @param flagSet the flagset to test
326     * @param testFlag the flag we search the presence of
327     * @return true if testFlag is present in the flagset, false otherwise.
328     */
329    public final static boolean isFlagSet(int flagSet, int testFlag) {
330        return (flagSet & testFlag) > 0;
331    }
332}