1 /* 2 * Copyright (C) 2015 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 package android.util; 17 18 import android.text.TextUtils; 19 20 import java.time.Duration; 21 import java.time.format.DateTimeParseException; 22 23 /** 24 * Parses a list of key=value pairs, separated by some delimiter, and puts the results in 25 * an internal Map. Values can be then queried by key, or if not found, a default value 26 * can be used. 27 * @hide 28 */ 29 public class KeyValueListParser { 30 private final ArrayMap<String, String> mValues = new ArrayMap<>(); 31 private final TextUtils.StringSplitter mSplitter; 32 33 /** 34 * Constructs a new KeyValueListParser. This can be reused for different strings 35 * by calling {@link #setString(String)}. 36 * @param delim The delimiter that separates key=value pairs. 37 */ KeyValueListParser(char delim)38 public KeyValueListParser(char delim) { 39 mSplitter = new TextUtils.SimpleStringSplitter(delim); 40 } 41 42 /** 43 * Resets the parser with a new string to parse. The string is expected to be in the following 44 * format: 45 * <pre>key1=value,key2=value,key3=value</pre> 46 * 47 * where the delimiter is a comma. 48 * 49 * @param str the string to parse. 50 * @throws IllegalArgumentException if the string is malformed. 51 */ setString(String str)52 public void setString(String str) throws IllegalArgumentException { 53 mValues.clear(); 54 if (str != null) { 55 mSplitter.setString(str); 56 for (String pair : mSplitter) { 57 int sep = pair.indexOf('='); 58 if (sep < 0) { 59 mValues.clear(); 60 throw new IllegalArgumentException( 61 "'" + pair + "' in '" + str + "' is not a valid key-value pair"); 62 } 63 mValues.put(pair.substring(0, sep).trim(), pair.substring(sep + 1).trim()); 64 } 65 } 66 } 67 68 /** 69 * Get the value for key as an int. 70 * @param key The key to lookup. 71 * @param def The value to return if the key was not found, or the value was not a long. 72 * @return the int value associated with the key. 73 */ getInt(String key, int def)74 public int getInt(String key, int def) { 75 String value = mValues.get(key); 76 if (value != null) { 77 try { 78 return Integer.parseInt(value); 79 } catch (NumberFormatException e) { 80 // fallthrough 81 } 82 } 83 return def; 84 } 85 86 /** 87 * Get the value for key as a long. 88 * @param key The key to lookup. 89 * @param def The value to return if the key was not found, or the value was not a long. 90 * @return the long value associated with the key. 91 */ getLong(String key, long def)92 public long getLong(String key, long def) { 93 String value = mValues.get(key); 94 if (value != null) { 95 try { 96 return Long.parseLong(value); 97 } catch (NumberFormatException e) { 98 // fallthrough 99 } 100 } 101 return def; 102 } 103 104 /** 105 * Get the value for key as a float. 106 * @param key The key to lookup. 107 * @param def The value to return if the key was not found, or the value was not a float. 108 * @return the float value associated with the key. 109 */ getFloat(String key, float def)110 public float getFloat(String key, float def) { 111 String value = mValues.get(key); 112 if (value != null) { 113 try { 114 return Float.parseFloat(value); 115 } catch (NumberFormatException e) { 116 // fallthrough 117 } 118 } 119 return def; 120 } 121 122 /** 123 * Get the value for key as a string. 124 * @param key The key to lookup. 125 * @param def The value to return if the key was not found. 126 * @return the string value associated with the key. 127 */ getString(String key, String def)128 public String getString(String key, String def) { 129 String value = mValues.get(key); 130 if (value != null) { 131 return value; 132 } 133 return def; 134 } 135 136 /** 137 * Get the value for key as a boolean. 138 * @param key The key to lookup. 139 * @param def The value to return if the key was not found. 140 * @return the string value associated with the key. 141 */ getBoolean(String key, boolean def)142 public boolean getBoolean(String key, boolean def) { 143 String value = mValues.get(key); 144 if (value != null) { 145 try { 146 return Boolean.parseBoolean(value); 147 } catch (NumberFormatException e) { 148 // fallthrough 149 } 150 } 151 return def; 152 } 153 154 /** 155 * Get the value for key as an integer array. 156 * 157 * The value should be encoded as "0:1:2:3:4" 158 * 159 * @param key The key to lookup. 160 * @param def The value to return if the key was not found. 161 * @return the int[] value associated with the key. 162 */ getIntArray(String key, int[] def)163 public int[] getIntArray(String key, int[] def) { 164 String value = mValues.get(key); 165 if (value != null) { 166 try { 167 String[] parts = value.split(":"); 168 if (parts.length > 0) { 169 int[] ret = new int[parts.length]; 170 for (int i = 0; i < parts.length; i++) { 171 ret[i] = Integer.parseInt(parts[i]); 172 } 173 return ret; 174 } 175 } catch (NumberFormatException e) { 176 // fallthrough 177 } 178 } 179 return def; 180 } 181 182 /** 183 * @return the number of keys. 184 */ size()185 public int size() { 186 return mValues.size(); 187 } 188 189 /** 190 * @return the key at {@code index}. Use with {@link #size()} to enumerate all key-value pairs. 191 */ keyAt(int index)192 public String keyAt(int index) { 193 return mValues.keyAt(index); 194 } 195 196 /** 197 * {@hide} 198 * Parse a duration in millis based on java.time.Duration or just a number (millis) 199 */ getDurationMillis(String key, long def)200 public long getDurationMillis(String key, long def) { 201 String value = mValues.get(key); 202 if (value != null) { 203 try { 204 if (value.startsWith("P") || value.startsWith("p")) { 205 return Duration.parse(value).toMillis(); 206 } else { 207 return Long.parseLong(value); 208 } 209 } catch (NumberFormatException | DateTimeParseException e) { 210 // fallthrough 211 } 212 } 213 return def; 214 } 215 } 216