NativeUtil.java revision 99ee64591d5d0ac986b1dbd676382b8a1409a36f
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();
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     * Converts an ssid string to an arraylist of UTF_8 byte values.
161     * These forms are acceptable:
162     * a) ASCII String encapsulated in quotes, or
163     * b) Hex string with no delimiters.
164     *
165     * @param ssidStr String to be converted.
166     * @throws IllegalArgumentException for null string.
167     */
168    public static ArrayList<Byte> decodeSsid(String ssidStr) {
169        if (ssidStr == null) {
170            throw new IllegalArgumentException("null ssid string");
171        }
172        int length = ssidStr.length();
173        if ((length > 1) && (ssidStr.charAt(0) == '"') && (ssidStr.charAt(length - 1) == '"')) {
174            ssidStr = ssidStr.substring(1, ssidStr.length() - 1);
175            return stringToByteArrayList(ssidStr);
176        } else {
177            return byteArrayToArrayList(hexStringToByteArray(ssidStr));
178        }
179    }
180
181    /**
182     * Converts an ArrayList<Byte> of UTF_8 byte values to ssid string.
183     * The string will either be:
184     * a) ASCII String encapsulated in quotes (if all the bytes are ASCII encodeable and non null),
185     * or
186     * b) Hex string with no delimiters.
187     *
188     * @param ssidBytes List of bytes for ssid.
189     * @throws IllegalArgumentException for null bytes.
190     */
191    public static String encodeSsid(ArrayList<Byte> ssidBytes) {
192        if (ssidBytes == null) {
193            throw new IllegalArgumentException("null ssid bytes");
194        }
195        byte[] ssidArray = byteArrayFromArrayList(ssidBytes);
196        // Check for 0's in the byte stream in which case we cannot convert this into a string.
197        if (!ssidBytes.contains(Byte.valueOf((byte) 0))) {
198            CharsetDecoder decoder = StandardCharsets.US_ASCII.newDecoder();
199            try {
200                CharBuffer decoded = decoder.decode(ByteBuffer.wrap(ssidArray));
201                return "\"" + decoded.toString() + "\"";
202            } catch (CharacterCodingException cce) {
203            }
204        }
205        return hexStringFromByteArray(ssidArray);
206    }
207
208    /**
209     * Convert from an array of primitive bytes to an array list of Byte.
210     */
211    private static ArrayList<Byte> byteArrayToArrayList(byte[] bytes) {
212        ArrayList<Byte> byteList = new ArrayList<>();
213        for (Byte b : bytes) {
214            byteList.add(b);
215        }
216        return byteList;
217    }
218
219    /**
220     * Convert from an array list of Byte to an array of primitive bytes.
221     */
222    private static byte[] byteArrayFromArrayList(ArrayList<Byte> bytes) {
223        byte[] byteArray = new byte[bytes.size()];
224        int i = 0;
225        for (Byte b : bytes) {
226            byteArray[i++] = b;
227        }
228        return byteArray;
229    }
230
231    /**
232     * Converts a hex string to byte array.
233     *
234     * @param hexStr String to be converted.
235     * @throws IllegalArgumentException for null string.
236     */
237    public static byte[] hexStringToByteArray(String hexStr) {
238        if (hexStr == null) {
239            throw new IllegalArgumentException("null hex string");
240        }
241        return HexEncoding.decode(hexStr.toCharArray(), false);
242    }
243
244    /**
245     * Converts a byte array to hex string.
246     *
247     * @param bytes List of bytes for ssid.
248     * @throws IllegalArgumentException for null bytes.
249     */
250    public static String hexStringFromByteArray(byte[] bytes) {
251        if (bytes == null) {
252            throw new IllegalArgumentException("null hex bytes");
253        }
254        return new String(HexEncoding.encode(bytes));
255    }
256}
257