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