1 package com.android.server.wifi.hotspot2; 2 3 import static com.android.server.wifi.hotspot2.anqp.Constants.BYTES_IN_EUI48; 4 import static com.android.server.wifi.hotspot2.anqp.Constants.BYTE_MASK; 5 import static com.android.server.wifi.hotspot2.anqp.Constants.NIBBLE_MASK; 6 7 import com.android.server.wifi.hotspot2.anqp.Constants; 8 9 import java.nio.ByteBuffer; 10 import java.util.ArrayList; 11 import java.util.Calendar; 12 import java.util.Collection; 13 import java.util.LinkedList; 14 import java.util.List; 15 import java.util.TimeZone; 16 17 public abstract class Utils { 18 19 public static final long UNSET_TIME = -1; 20 21 private static final int EUI48Length = 6; 22 private static final int EUI64Length = 8; 23 private static final long EUI48Mask = 0xffffffffffffL; 24 private static final String[] PLMNText = {"org", "3gppnetwork", "mcc*", "mnc*", "wlan" }; 25 hs2LogTag(Class c)26 public static String hs2LogTag(Class c) { 27 return "HS20"; 28 } 29 splitDomain(String domain)30 public static List<String> splitDomain(String domain) { 31 32 if (domain.endsWith(".")) 33 domain = domain.substring(0, domain.length() - 1); 34 int at = domain.indexOf('@'); 35 if (at >= 0) 36 domain = domain.substring(at + 1); 37 38 String[] labels = domain.toLowerCase().split("\\."); 39 LinkedList<String> labelList = new LinkedList<String>(); 40 for (String label : labels) { 41 labelList.addFirst(label); 42 } 43 44 return labelList; 45 } 46 parseMac(String s)47 public static long parseMac(String s) { 48 if (s == null) { 49 throw new IllegalArgumentException("Null MAC adddress"); 50 } 51 long mac = 0; 52 int count = 0; 53 for (int n = 0; n < s.length(); n++) { 54 int nibble = Utils.fromHex(s.charAt(n), true); // Set lenient to not blow up on ':' 55 if (nibble >= 0) { // ... and use only legit hex. 56 mac = (mac << 4) | nibble; 57 count++; 58 } 59 } 60 if (count < 12 || (count&1) == 1) { 61 throw new IllegalArgumentException("Bad MAC address: '" + s + "'"); 62 } 63 return mac; 64 } 65 66 /** 67 * Convert from mac address as long to simple string in hex code, same as "%012x". 68 * @param mac The Mac address as long value. 69 * @return String value of mac address. 70 */ macToSimpleString(long mac)71 public static String macToSimpleString(long mac) { 72 StringBuilder sb = new StringBuilder(); 73 for (int n = BYTES_IN_EUI48 - 1; n >= 0; n--) { 74 long b = (mac >>> (n * Byte.SIZE)) & BYTE_MASK; 75 sb.append(b > 0xf ? Long.toHexString(b) : "0" + Long.toHexString(b)); 76 } 77 return sb.toString(); 78 } 79 80 /** 81 * Convert from mac address as long to string in hex code, separated with colon. 82 * @param mac The Mac address as long value. 83 * @return String value of mac address. 84 */ macToString(long mac)85 public static String macToString(long mac) { 86 int len = (mac & ~EUI48Mask) != 0 ? EUI64Length : EUI48Length; 87 StringBuilder sb = new StringBuilder(); 88 boolean first = true; 89 for (int n = (len - 1) * Byte.SIZE; n >= 0; n -= Byte.SIZE) { 90 if (first) { 91 first = false; 92 } else { 93 sb.append(':'); 94 } 95 long b = (mac >>> n) & Constants.BYTE_MASK; 96 sb.append(b > 0xf ? Long.toHexString(b) : "0" + Long.toHexString(b)); 97 } 98 return sb.toString(); 99 } 100 getMccMnc(List<String> domain)101 public static String getMccMnc(List<String> domain) { 102 if (domain.size() != PLMNText.length) { 103 return null; 104 } 105 106 for (int n = 0; n < PLMNText.length; n++ ) { 107 String expect = PLMNText[n]; 108 int len = expect.endsWith("*") ? expect.length() - 1 : expect.length(); 109 if (!domain.get(n).regionMatches(0, expect, 0, len)) { 110 return null; 111 } 112 } 113 114 String prefix = domain.get(2).substring(3) + domain.get(3).substring(3); 115 for (int n = 0; n < prefix.length(); n++) { 116 char ch = prefix.charAt(n); 117 if (ch < '0' || ch > '9') { 118 return null; 119 } 120 } 121 return prefix; 122 } 123 roamingConsortiumsToString(long[] ois)124 public static String roamingConsortiumsToString(long[] ois) { 125 if (ois == null) { 126 return "null"; 127 } 128 List<Long> list = new ArrayList<Long>(ois.length); 129 for (long oi : ois) { 130 list.add(oi); 131 } 132 return roamingConsortiumsToString(list); 133 } 134 roamingConsortiumsToString(Collection<Long> ois)135 public static String roamingConsortiumsToString(Collection<Long> ois) { 136 StringBuilder sb = new StringBuilder(); 137 boolean first = true; 138 for (long oi : ois) { 139 if (first) { 140 first = false; 141 } else { 142 sb.append(", "); 143 } 144 if (Long.numberOfLeadingZeros(oi) > 40) { 145 sb.append(String.format("%06x", oi)); 146 } else { 147 sb.append(String.format("%010x", oi)); 148 } 149 } 150 return sb.toString(); 151 } 152 toUnicodeEscapedString(String s)153 public static String toUnicodeEscapedString(String s) { 154 StringBuilder sb = new StringBuilder(s.length()); 155 for (int n = 0; n < s.length(); n++) { 156 char ch = s.charAt(n); 157 if (ch>= ' ' && ch < 127) { 158 sb.append(ch); 159 } 160 else { 161 sb.append("\\u").append(String.format("%04x", (int)ch)); 162 } 163 } 164 return sb.toString(); 165 } 166 toHexString(byte[] data)167 public static String toHexString(byte[] data) { 168 if (data == null) { 169 return "null"; 170 } 171 StringBuilder sb = new StringBuilder(data.length * 3); 172 173 boolean first = true; 174 for (byte b : data) { 175 if (first) { 176 first = false; 177 } else { 178 sb.append(' '); 179 } 180 sb.append(String.format("%02x", b & BYTE_MASK)); 181 } 182 return sb.toString(); 183 } 184 toHex(byte[] octets)185 public static String toHex(byte[] octets) { 186 StringBuilder sb = new StringBuilder(octets.length * 2); 187 for (byte o : octets) { 188 sb.append(String.format("%02x", o & BYTE_MASK)); 189 } 190 return sb.toString(); 191 } 192 hexToBytes(String text)193 public static byte[] hexToBytes(String text) { 194 if ((text.length() & 1) == 1) { 195 throw new NumberFormatException("Odd length hex string: " + text.length()); 196 } 197 byte[] data = new byte[text.length() >> 1]; 198 int position = 0; 199 for (int n = 0; n < text.length(); n += 2) { 200 data[position] = 201 (byte) (((fromHex(text.charAt(n), false) & NIBBLE_MASK) << 4) | 202 (fromHex(text.charAt(n + 1), false) & NIBBLE_MASK)); 203 position++; 204 } 205 return data; 206 } 207 fromHex(char ch, boolean lenient)208 public static int fromHex(char ch, boolean lenient) throws NumberFormatException { 209 if (ch <= '9' && ch >= '0') { 210 return ch - '0'; 211 } else if (ch >= 'a' && ch <= 'f') { 212 return ch + 10 - 'a'; 213 } else if (ch <= 'F' && ch >= 'A') { 214 return ch + 10 - 'A'; 215 } else if (lenient) { 216 return -1; 217 } else { 218 throw new NumberFormatException("Bad hex-character: " + ch); 219 } 220 } 221 toAscii(int b)222 private static char toAscii(int b) { 223 return b >= ' ' && b < 0x7f ? (char) b : '.'; 224 } 225 isDecimal(String s)226 static boolean isDecimal(String s) { 227 for (int n = 0; n < s.length(); n++) { 228 char ch = s.charAt(n); 229 if (ch < '0' || ch > '9') { 230 return false; 231 } 232 } 233 return true; 234 } 235 compare(Comparable<T> c1, T c2)236 public static <T extends Comparable> int compare(Comparable<T> c1, T c2) { 237 if (c1 == null) { 238 return c2 == null ? 0 : -1; 239 } 240 else if (c2 == null) { 241 return 1; 242 } 243 else { 244 return c1.compareTo(c2); 245 } 246 } 247 bytesToBingoCard(ByteBuffer data, int len)248 public static String bytesToBingoCard(ByteBuffer data, int len) { 249 ByteBuffer dup = data.duplicate(); 250 dup.limit(dup.position() + len); 251 return bytesToBingoCard(dup); 252 } 253 bytesToBingoCard(ByteBuffer data)254 public static String bytesToBingoCard(ByteBuffer data) { 255 ByteBuffer dup = data.duplicate(); 256 StringBuilder sbx = new StringBuilder(); 257 while (dup.hasRemaining()) { 258 sbx.append(String.format("%02x ", dup.get() & BYTE_MASK)); 259 } 260 dup = data.duplicate(); 261 sbx.append(' '); 262 while (dup.hasRemaining()) { 263 sbx.append(String.format("%c", toAscii(dup.get() & BYTE_MASK))); 264 } 265 return sbx.toString(); 266 } 267 toHMS(long millis)268 public static String toHMS(long millis) { 269 long time = millis >= 0 ? millis : -millis; 270 long tmp = time / 1000L; 271 long ms = time - tmp * 1000L; 272 273 time = tmp; 274 tmp /= 60L; 275 long s = time - tmp * 60L; 276 277 time = tmp; 278 tmp /= 60L; 279 long m = time - tmp * 60L; 280 281 return String.format("%s%d:%02d:%02d.%03d", millis < 0 ? "-" : "", tmp, m, s, ms); 282 } 283 toUTCString(long ms)284 public static String toUTCString(long ms) { 285 if (ms < 0) { 286 return "unset"; 287 } 288 Calendar c = Calendar.getInstance(TimeZone.getTimeZone("UTC")); 289 c.setTimeInMillis(ms); 290 return String.format("%4d/%02d/%02d %2d:%02d:%02dZ", 291 c.get(Calendar.YEAR), 292 c.get(Calendar.MONTH) + 1, 293 c.get(Calendar.DAY_OF_MONTH), 294 c.get(Calendar.HOUR_OF_DAY), 295 c.get(Calendar.MINUTE), 296 c.get(Calendar.SECOND)); 297 } 298 unquote(String s)299 public static String unquote(String s) { 300 if (s == null) { 301 return null; 302 } 303 else if (s.length() > 1 && s.startsWith("\"") && s.endsWith("\"")) { 304 return s.substring(1, s.length()-1); 305 } 306 else { 307 return s; 308 } 309 } 310 } 311