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