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