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