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