• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 com.android.server.wifi.util;
17 
18 import android.text.TextUtils;
19 import android.util.ArrayMap;
20 
21 import java.io.PrintWriter;
22 import java.time.Duration;
23 import java.time.format.DateTimeParseException;
24 
25 /**
26  * Parses a list of key=value pairs, separated by some delimiter, and puts the results in
27  * an internal Map. Values can be then queried by key, or if not found, a default value
28  * can be used.
29  *
30  * Note: @hide class copied from android.util (with ProtoStream dependency stripped out)
31  */
32 public class KeyValueListParser {
33     private final ArrayMap<String, String> mValues = new ArrayMap<>();
34     private final TextUtils.StringSplitter mSplitter;
35 
36     /**
37      * Constructs a new KeyValueListParser. This can be reused for different strings
38      * by calling {@link #setString(String)}.
39      * @param delim The delimiter that separates key=value pairs.
40      */
KeyValueListParser(char delim)41     public KeyValueListParser(char delim) {
42         mSplitter = new TextUtils.SimpleStringSplitter(delim);
43     }
44 
45     /**
46      * Resets the parser with a new string to parse. The string is expected to be in the following
47      * format:
48      * <pre>key1=value,key2=value,key3=value</pre>
49      *
50      * where the delimiter is a comma.
51      *
52      * @param str the string to parse.
53      * @throws IllegalArgumentException if the string is malformed.
54      */
setString(String str)55     public void setString(String str) throws IllegalArgumentException {
56         mValues.clear();
57         if (str != null) {
58             mSplitter.setString(str);
59             for (String pair : mSplitter) {
60                 int sep = pair.indexOf('=');
61                 if (sep < 0) {
62                     mValues.clear();
63                     throw new IllegalArgumentException(
64                             "'" + pair + "' in '" + str + "' is not a valid key-value pair");
65                 }
66                 mValues.put(pair.substring(0, sep).trim(), pair.substring(sep + 1).trim());
67             }
68         }
69     }
70 
71     /**
72      * Get the value for key as an int.
73      * @param key The key to lookup.
74      * @param def The value to return if the key was not found, or the value was not a long.
75      * @return the int value associated with the key.
76      */
getInt(String key, int def)77     public int getInt(String key, int def) {
78         String value = mValues.get(key);
79         if (value != null) {
80             try {
81                 return Integer.parseInt(value);
82             } catch (NumberFormatException e) {
83                 // fallthrough
84             }
85         }
86         return def;
87     }
88 
89     /**
90      * Get the value for key as a long.
91      * @param key The key to lookup.
92      * @param def The value to return if the key was not found, or the value was not a long.
93      * @return the long value associated with the key.
94      */
getLong(String key, long def)95     public long getLong(String key, long def) {
96         String value = mValues.get(key);
97         if (value != null) {
98             try {
99                 return Long.parseLong(value);
100             } catch (NumberFormatException e) {
101                 // fallthrough
102             }
103         }
104         return def;
105     }
106 
107     /**
108      * Get the value for key as a float.
109      * @param key The key to lookup.
110      * @param def The value to return if the key was not found, or the value was not a float.
111      * @return the float value associated with the key.
112      */
getFloat(String key, float def)113     public float getFloat(String key, float def) {
114         String value = mValues.get(key);
115         if (value != null) {
116             try {
117                 return Float.parseFloat(value);
118             } catch (NumberFormatException e) {
119                 // fallthrough
120             }
121         }
122         return def;
123     }
124 
125     /**
126      * Get the value for key as a string.
127      * @param key The key to lookup.
128      * @param def The value to return if the key was not found.
129      * @return the string value associated with the key.
130      */
getString(String key, String def)131     public String getString(String key, String def) {
132         String value = mValues.get(key);
133         if (value != null) {
134             return value;
135         }
136         return def;
137     }
138 
139     /**
140      * Get the value for key as a boolean.
141      * @param key The key to lookup.
142      * @param def The value to return if the key was not found.
143      * @return the string value associated with the key.
144      */
getBoolean(String key, boolean def)145     public boolean getBoolean(String key, boolean def) {
146         String value = mValues.get(key);
147         if (value != null) {
148             try {
149                 return Boolean.parseBoolean(value);
150             } catch (NumberFormatException e) {
151                 // fallthrough
152             }
153         }
154         return def;
155     }
156 
157     /**
158      * Get the value for key as an integer array.
159      *
160      * The value should be encoded as "0:1:2:3:4"
161      *
162      * @param key The key to lookup.
163      * @param def The value to return if the key was not found.
164      * @return the int[] value associated with the key.
165      */
getIntArray(String key, int[] def)166     public int[] getIntArray(String key, int[] def) {
167         String value = mValues.get(key);
168         if (value != null) {
169             try {
170                 String[] parts = value.split(":");
171                 if (parts.length > 0) {
172                     int[] ret = new int[parts.length];
173                     for (int i = 0; i < parts.length; i++) {
174                         ret[i] = Integer.parseInt(parts[i]);
175                     }
176                     return ret;
177                 }
178             } catch (NumberFormatException e) {
179                 // fallthrough
180             }
181         }
182         return def;
183     }
184 
185     /**
186      * @return the number of keys.
187      */
size()188     public int size() {
189         return mValues.size();
190     }
191 
192     /**
193      * @return the key at {@code index}. Use with {@link #size()} to enumerate all key-value pairs.
194      */
keyAt(int index)195     public String keyAt(int index) {
196         return mValues.keyAt(index);
197     }
198 
199     /**
200      * {@hide}
201      * Parse a duration in millis based on java.time.Duration or just a number (millis)
202      */
getDurationMillis(String key, long def)203     public long getDurationMillis(String key, long def) {
204         String value = mValues.get(key);
205         if (value != null) {
206             try {
207                 if (value.startsWith("P") || value.startsWith("p")) {
208                     return Duration.parse(value).toMillis();
209                 } else {
210                     return Long.parseLong(value);
211                 }
212             } catch (NumberFormatException | DateTimeParseException e) {
213                 // fallthrough
214             }
215         }
216         return def;
217     }
218 
219     /** Represents an integer config value. */
220     public static class IntValue {
221         private final String mKey;
222         private final int mDefaultValue;
223         private int mValue;
224 
225         /** Constructor, initialize with a config key and a default value. */
IntValue(String key, int defaultValue)226         public IntValue(String key, int defaultValue) {
227             mKey = key;
228             mDefaultValue = defaultValue;
229             mValue = mDefaultValue;
230         }
231 
232         /** Read a value from {@link KeyValueListParser} */
parse(KeyValueListParser parser)233         public void parse(KeyValueListParser parser) {
234             mValue = parser.getInt(mKey, mDefaultValue);
235         }
236 
237         /** Return the config key. */
getKey()238         public String getKey() {
239             return mKey;
240         }
241 
242         /** Return the default value. */
getDefaultValue()243         public int getDefaultValue() {
244             return mDefaultValue;
245         }
246 
247         /** Return the actual config value. */
getValue()248         public int getValue() {
249             return mValue;
250         }
251 
252         /** Overwrites with a value. */
setValue(int value)253         public void setValue(int value) {
254             mValue = value;
255         }
256 
257         /** Used for dumpsys */
dump(PrintWriter pw, String prefix)258         public void dump(PrintWriter pw, String prefix) {
259             pw.print(prefix);
260             pw.print(mKey);
261             pw.print("=");
262             pw.print(mValue);
263             pw.println();
264         }
265     }
266 
267     /** Represents an long config value. */
268     public static class LongValue {
269         private final String mKey;
270         private final long mDefaultValue;
271         private long mValue;
272 
273         /** Constructor, initialize with a config key and a default value. */
LongValue(String key, long defaultValue)274         public LongValue(String key, long defaultValue) {
275             mKey = key;
276             mDefaultValue = defaultValue;
277             mValue = mDefaultValue;
278         }
279 
280         /** Read a value from {@link KeyValueListParser} */
parse(KeyValueListParser parser)281         public void parse(KeyValueListParser parser) {
282             mValue = parser.getLong(mKey, mDefaultValue);
283         }
284 
285         /** Return the config key. */
getKey()286         public String getKey() {
287             return mKey;
288         }
289 
290         /** Return the default value. */
getDefaultValue()291         public long getDefaultValue() {
292             return mDefaultValue;
293         }
294 
295         /** Return the actual config value. */
getValue()296         public long getValue() {
297             return mValue;
298         }
299 
300         /** Overwrites with a value. */
setValue(long value)301         public void setValue(long value) {
302             mValue = value;
303         }
304 
305         /** Used for dumpsys */
dump(PrintWriter pw, String prefix)306         public void dump(PrintWriter pw, String prefix) {
307             pw.print(prefix);
308             pw.print(mKey);
309             pw.print("=");
310             pw.print(mValue);
311             pw.println();
312         }
313     }
314 
315     /** Represents an string config value. */
316     public static class StringValue {
317         private final String mKey;
318         private final String mDefaultValue;
319         private String mValue;
320 
321         /** Constructor, initialize with a config key and a default value. */
StringValue(String key, String defaultValue)322         public StringValue(String key, String defaultValue) {
323             mKey = key;
324             mDefaultValue = defaultValue;
325             mValue = mDefaultValue;
326         }
327 
328         /** Read a value from {@link KeyValueListParser} */
parse(KeyValueListParser parser)329         public void parse(KeyValueListParser parser) {
330             mValue = parser.getString(mKey, mDefaultValue);
331         }
332 
333         /** Return the config key. */
getKey()334         public String getKey() {
335             return mKey;
336         }
337 
338         /** Return the default value. */
getDefaultValue()339         public String getDefaultValue() {
340             return mDefaultValue;
341         }
342 
343         /** Return the actual config value. */
getValue()344         public String getValue() {
345             return mValue;
346         }
347 
348         /** Overwrites with a value. */
setValue(String value)349         public void setValue(String value) {
350             mValue = value;
351         }
352 
353         /** Used for dumpsys */
dump(PrintWriter pw, String prefix)354         public void dump(PrintWriter pw, String prefix) {
355             pw.print(prefix);
356             pw.print(mKey);
357             pw.print("=");
358             pw.print(mValue);
359             pw.println();
360         }
361     }
362 
363     /** Represents an float config value. */
364     public static class FloatValue {
365         private final String mKey;
366         private final float mDefaultValue;
367         private float mValue;
368 
369         /** Constructor, initialize with a config key and a default value. */
FloatValue(String key, float defaultValue)370         public FloatValue(String key, float defaultValue) {
371             mKey = key;
372             mDefaultValue = defaultValue;
373             mValue = mDefaultValue;
374         }
375 
376         /** Read a value from {@link KeyValueListParser} */
parse(KeyValueListParser parser)377         public void parse(KeyValueListParser parser) {
378             mValue = parser.getFloat(mKey, mDefaultValue);
379         }
380 
381         /** Return the config key. */
getKey()382         public String getKey() {
383             return mKey;
384         }
385 
386         /** Return the default value. */
getDefaultValue()387         public float getDefaultValue() {
388             return mDefaultValue;
389         }
390 
391         /** Return the actual config value. */
getValue()392         public float getValue() {
393             return mValue;
394         }
395 
396         /** Overwrites with a value. */
setValue(float value)397         public void setValue(float value) {
398             mValue = value;
399         }
400 
401         /** Used for dumpsys */
dump(PrintWriter pw, String prefix)402         public void dump(PrintWriter pw, String prefix) {
403             pw.print(prefix);
404             pw.print(mKey);
405             pw.print("=");
406             pw.print(mValue);
407             pw.println();
408         }
409     }
410 }
411