NativeUtil.java revision 6a8908d2bc0367397eb92444ac78cc8d43160ef6
1/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.wifi.util;
18
19import libcore.util.HexEncoding;
20
21import java.nio.ByteBuffer;
22import java.nio.CharBuffer;
23import java.nio.charset.CharacterCodingException;
24import java.nio.charset.CharsetDecoder;
25import java.nio.charset.StandardCharsets;
26import java.util.ArrayList;
27
28/**
29 * Provide utility functions for native interfacing modules.
30 */
31public class NativeUtil {
32    private static final String ANY_MAC_STR = "any";
33    private static final byte[] ANY_MAC_BYTES = {0, 0, 0, 0, 0, 0};
34    private static final int MAC_LENGTH = 6;
35    private static final int MAC_OUI_LENGTH = 3;
36    private static final int MAC_STR_LENGTH = MAC_LENGTH * 2 + 5;
37
38    /**
39     * Convert the string to byte array list.
40     *
41     * @return the UTF_8 char byte values of str, as an ArrayList.
42     * @throws IllegalArgumentException if a null string is sent.
43     */
44    public static ArrayList<Byte> stringToByteArrayList(String str) {
45        if (str == null) {
46            throw new IllegalArgumentException("null string");
47        }
48        ArrayList<Byte> byteArrayList = new ArrayList<Byte>();
49        for (byte b : str.getBytes(StandardCharsets.UTF_8)) {
50            byteArrayList.add(new Byte(b));
51        }
52        return byteArrayList;
53    }
54
55    /**
56     * Convert the byte array list to string.
57     *
58     * @return the string decoded from UTF_8 byte values in byteArrayList.
59     * @throws IllegalArgumentException if a null byte array list is sent.
60     */
61    public static String stringFromByteArrayList(ArrayList<Byte> byteArrayList) {
62        if (byteArrayList == null) {
63            throw new IllegalArgumentException("null byte array list");
64        }
65        byte[] byteArray = new byte[byteArrayList.size()];
66        int i = 0;
67        for (Byte b : byteArrayList) {
68            byteArray[i] = b;
69            i++;
70        }
71        return new String(byteArray, StandardCharsets.UTF_8);
72    }
73
74    /**
75     * Convert the string to byte array.
76     *
77     * @return the UTF_8 char byte values of str, as an Array.
78     * @throws IllegalArgumentException if a null string is sent.
79     */
80    public static byte[] stringToByteArray(String str) {
81        if (str == null) {
82            throw new IllegalArgumentException("null string");
83        }
84        return str.getBytes(StandardCharsets.UTF_8);
85    }
86
87    /**
88     * Convert the byte array list to string.
89     *
90     * @return the string decoded from UTF_8 byte values in byteArray.
91     * @throws IllegalArgumentException if a null byte array is sent.
92     */
93    public static String stringFromByteArray(byte[] byteArray) {
94        if (byteArray == null) {
95            throw new IllegalArgumentException("null byte array");
96        }
97        return new String(byteArray);
98    }
99
100    /**
101     * Converts a mac address string to an array of Bytes.
102     *
103     * @param macStr string of format: "XX:XX:XX:XX:XX:XX" or "XXXXXXXXXXXX", where X is any
104     *        hexadecimal digit.
105     *        Passing "any" is the same as 00:00:00:00:00:00
106     * @throws IllegalArgumentException for various malformed inputs.
107     */
108    public static byte[] macAddressToByteArray(String macStr) {
109        if (macStr == null) {
110            throw new IllegalArgumentException("null mac string");
111        }
112        if (ANY_MAC_STR.equals(macStr)) return ANY_MAC_BYTES;
113        String cleanMac = macStr.replace(":", "");
114        if (cleanMac.length() != MAC_LENGTH * 2) {
115            throw new IllegalArgumentException("invalid mac string length: " + cleanMac);
116        }
117        return HexEncoding.decode(cleanMac.toCharArray(), false);
118    }
119
120    /**
121     * Converts an array of 6 bytes to a HexEncoded String with format: "XX:XX:XX:XX:XX:XX", where X
122     * is any hexadecimal digit.
123     *
124     * @param macArray byte array of mac values, must have length 6
125     * @throws IllegalArgumentException for malformed inputs.
126     */
127    public static String macAddressFromByteArray(byte[] macArray) {
128        if (macArray == null) {
129            throw new IllegalArgumentException("null mac bytes");
130        }
131        if (macArray.length != MAC_LENGTH) {
132            throw new IllegalArgumentException("invalid macArray length: " + macArray.length);
133        }
134        StringBuilder sb = new StringBuilder(MAC_STR_LENGTH);
135        for (int i = 0; i < macArray.length; i++) {
136            if (i != 0) sb.append(":");
137            sb.append(new String(HexEncoding.encode(macArray, i, 1)));
138        }
139        return sb.toString().toLowerCase();
140    }
141
142    /**
143     * Converts a mac address OUI string to an array of Bytes.
144     *
145     * @param macStr string of format: "XX:XX:XX" or "XXXXXX", where X is any hexadecimal digit.
146     * @throws IllegalArgumentException for various malformed inputs.
147     */
148    public static byte[] macAddressOuiToByteArray(String macStr) {
149        if (macStr == null) {
150            throw new IllegalArgumentException("null mac string");
151        }
152        String cleanMac = macStr.replace(":", "");
153        if (cleanMac.length() != MAC_OUI_LENGTH * 2) {
154            throw new IllegalArgumentException("invalid mac oui string length: " + cleanMac);
155        }
156        return HexEncoding.decode(cleanMac.toCharArray(), false);
157    }
158
159    /**
160     * Remove enclosed quotes of the provided string.
161     *
162     * @param quotedStr String to be unquoted.
163     * @return String without the enclosing quotes.
164     */
165    public static String removeEnclosingQuotes(String quotedStr) {
166        int length = quotedStr.length();
167        if ((length >= 2)
168                && (quotedStr.charAt(0) == '"') && (quotedStr.charAt(length - 1) == '"')) {
169            return quotedStr.substring(1, length - 1);
170        }
171        return quotedStr;
172    }
173
174    /**
175     * Converts an string to an arraylist of UTF_8 byte values.
176     * These forms are acceptable:
177     * a) ASCII String encapsulated in quotes, or
178     * b) Hex string with no delimiters.
179     *
180     * @param str String to be converted.
181     * @throws IllegalArgumentException for null string.
182     */
183    public static ArrayList<Byte> hexOrQuotedAsciiStringToBytes(String str) {
184        if (str == null) {
185            throw new IllegalArgumentException("null string");
186        }
187        int length = str.length();
188        if ((length > 1) && (str.charAt(0) == '"') && (str.charAt(length - 1) == '"')) {
189            str = str.substring(1, str.length() - 1);
190            return stringToByteArrayList(str);
191        } else {
192            return byteArrayToArrayList(hexStringToByteArray(str));
193        }
194    }
195
196    /**
197     * Converts an ArrayList<Byte> of UTF_8 byte values to string.
198     * The string will either be:
199     * a) ASCII String encapsulated in quotes (if all the bytes are ASCII encodeable and non null),
200     * or
201     * b) Hex string with no delimiters.
202     *
203     * @param bytes List of bytes for ssid.
204     * @throws IllegalArgumentException for null bytes.
205     */
206    public static String bytesToHexOrQuotedAsciiString(ArrayList<Byte> bytes) {
207        if (bytes == null) {
208            throw new IllegalArgumentException("null ssid bytes");
209        }
210        byte[] byteArray = byteArrayFromArrayList(bytes);
211        // Check for 0's in the byte stream in which case we cannot convert this into a string.
212        if (!bytes.contains(Byte.valueOf((byte) 0))) {
213            CharsetDecoder decoder = StandardCharsets.US_ASCII.newDecoder();
214            try {
215                CharBuffer decoded = decoder.decode(ByteBuffer.wrap(byteArray));
216                return "\"" + decoded.toString() + "\"";
217            } catch (CharacterCodingException cce) {
218            }
219        }
220        return hexStringFromByteArray(byteArray);
221    }
222
223    /**
224     * Converts an ssid string to an arraylist of UTF_8 byte values.
225     * These forms are acceptable:
226     * a) ASCII String encapsulated in quotes, or
227     * b) Hex string with no delimiters.
228     *
229     * @param ssidStr String to be converted.
230     * @throws IllegalArgumentException for null string.
231     */
232    public static ArrayList<Byte> decodeSsid(String ssidStr) {
233        return hexOrQuotedAsciiStringToBytes(ssidStr);
234    }
235
236    /**
237     * Converts an ArrayList<Byte> of UTF_8 byte values to ssid string.
238     * The string will either be:
239     * a) ASCII String encapsulated in quotes (if all the bytes are ASCII encodeable and non null),
240     * or
241     * b) Hex string with no delimiters.
242     *
243     * @param ssidBytes List of bytes for ssid.
244     * @throws IllegalArgumentException for null bytes.
245     */
246    public static String encodeSsid(ArrayList<Byte> ssidBytes) {
247        return bytesToHexOrQuotedAsciiString(ssidBytes);
248    }
249
250    /**
251     * Convert from an array of primitive bytes to an array list of Byte.
252     */
253    public static ArrayList<Byte> byteArrayToArrayList(byte[] bytes) {
254        ArrayList<Byte> byteList = new ArrayList<>();
255        for (Byte b : bytes) {
256            byteList.add(b);
257        }
258        return byteList;
259    }
260
261    /**
262     * Convert from an array list of Byte to an array of primitive bytes.
263     */
264    public static byte[] byteArrayFromArrayList(ArrayList<Byte> bytes) {
265        byte[] byteArray = new byte[bytes.size()];
266        int i = 0;
267        for (Byte b : bytes) {
268            byteArray[i++] = b;
269        }
270        return byteArray;
271    }
272
273    /**
274     * Converts a hex string to byte array.
275     *
276     * @param hexStr String to be converted.
277     * @throws IllegalArgumentException for null string.
278     */
279    public static byte[] hexStringToByteArray(String hexStr) {
280        if (hexStr == null) {
281            throw new IllegalArgumentException("null hex string");
282        }
283        return HexEncoding.decode(hexStr.toCharArray(), false);
284    }
285
286    /**
287     * Converts a byte array to hex string.
288     *
289     * @param bytes List of bytes for ssid.
290     * @throws IllegalArgumentException for null bytes.
291     */
292    public static String hexStringFromByteArray(byte[] bytes) {
293        if (bytes == null) {
294            throw new IllegalArgumentException("null hex bytes");
295        }
296        return new String(HexEncoding.encode(bytes)).toLowerCase();
297    }
298}
299