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