• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 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.ddmuilib.logcat;
17 
18 import com.android.ddmlib.Log.LogLevel;
19 
20 import java.util.ArrayList;
21 import java.util.List;
22 
23 /**
24  * Class to help save/restore user created filters.
25  *
26  * Users can create multiple filters in the logcat view. These filters could have regexes
27  * in their settings. All of the user created filters are saved into a single Eclipse
28  * preference. This class helps in generating the string to be saved given a list of
29  * {@link LogCatFilter}'s, and also does the reverse of creating the list of filters
30  * given the encoded string.
31  */
32 public final class LogCatFilterSettingsSerializer {
33     private static final char SINGLE_QUOTE = '\'';
34     private static final char ESCAPE_CHAR = '\\';
35 
36     private static final String ATTR_DELIM = ", ";
37     private static final String KW_DELIM = ": ";
38 
39     private static final String KW_NAME = "name";
40     private static final String KW_TAG = "tag";
41     private static final String KW_TEXT = "text";
42     private static final String KW_PID = "pid";
43     private static final String KW_APP = "app";
44     private static final String KW_LOGLEVEL = "level";
45 
46     /**
47      * Encode the settings from a list of {@link LogCatFilter}'s into a string for saving to
48      * the preference store. See
49      * {@link LogCatFilterSettingsSerializer#decodeFromPreferenceString(String)} for the
50      * reverse operation.
51      * @param filters list of filters to save.
52      * @return an encoded string that can be saved in Eclipse preference store. The encoded string
53      * is of a list of key:'value' pairs.
54      */
encodeToPreferenceString(List<LogCatFilter> filters)55     public String encodeToPreferenceString(List<LogCatFilter> filters) {
56         StringBuffer sb = new StringBuffer();
57 
58         for (LogCatFilter f : filters) {
59             if (f.isTransient()) {
60                 // do not persist transient filters
61                 continue;
62             }
63 
64             sb.append(KW_NAME); sb.append(KW_DELIM); sb.append(quoteString(f.getName()));
65                                                                         sb.append(ATTR_DELIM);
66             sb.append(KW_TAG);  sb.append(KW_DELIM); sb.append(quoteString(f.getTag()));
67                                                                         sb.append(ATTR_DELIM);
68             sb.append(KW_TEXT); sb.append(KW_DELIM); sb.append(quoteString(f.getText()));
69                                                                         sb.append(ATTR_DELIM);
70             sb.append(KW_PID);  sb.append(KW_DELIM); sb.append(quoteString(f.getPid()));
71                                                                         sb.append(ATTR_DELIM);
72             sb.append(KW_APP);  sb.append(KW_DELIM); sb.append(quoteString(f.getAppName()));
73                                                                         sb.append(ATTR_DELIM);
74             sb.append(KW_LOGLEVEL); sb.append(KW_DELIM);
75                                        sb.append(quoteString(f.getLogLevel().getStringValue()));
76                                        sb.append(ATTR_DELIM);
77         }
78         return sb.toString();
79     }
80 
81     /**
82      * Decode an encoded string representing the settings of a list of logcat
83      * filters into a list of {@link LogCatFilter}'s.
84      * @param pref encoded preference string
85      * @return a list of {@link LogCatFilter}
86      */
decodeFromPreferenceString(String pref)87     public List<LogCatFilter> decodeFromPreferenceString(String pref) {
88         List<LogCatFilter> fs = new ArrayList<LogCatFilter>();
89 
90         /* first split the string into a list of key, value pairs */
91         List<String> kv = getKeyValues(pref);
92         if (kv.size() == 0) {
93             return fs;
94         }
95 
96         /* construct filter settings from the key value pairs */
97         int index = 0;
98         while (index < kv.size()) {
99             String name = "";
100             String tag = "";
101             String pid = "";
102             String app = "";
103             String text = "";
104             LogLevel level = LogLevel.VERBOSE;
105 
106             assert kv.get(index).equals(KW_NAME);
107             name = kv.get(index + 1);
108 
109             index += 2;
110             while (index < kv.size() && !kv.get(index).equals(KW_NAME)) {
111                 String key = kv.get(index);
112                 String value = kv.get(index + 1);
113                 index += 2;
114 
115                 if (key.equals(KW_TAG)) {
116                     tag = value;
117                 } else if (key.equals(KW_TEXT)) {
118                     text = value;
119                 } else if (key.equals(KW_PID)) {
120                     pid = value;
121                 } else if (key.equals(KW_APP)) {
122                     app = value;
123                 } else if (key.equals(KW_LOGLEVEL)) {
124                     level = LogLevel.getByString(value);
125                 }
126             }
127 
128             fs.add(new LogCatFilter(name, tag, text, pid, app, level));
129         }
130 
131         return fs;
132     }
133 
getKeyValues(String pref)134     private List<String> getKeyValues(String pref) {
135         List<String> kv = new ArrayList<String>();
136         int index = 0;
137         while (index < pref.length()) {
138             String kw = getKeyword(pref.substring(index));
139             if (kw == null) {
140                 break;
141             }
142             index += kw.length() + KW_DELIM.length();
143 
144             String value = getNextString(pref.substring(index));
145             index += value.length() + ATTR_DELIM.length();
146 
147             value = unquoteString(value);
148 
149             kv.add(kw);
150             kv.add(value);
151         }
152 
153         return kv;
154     }
155 
156     /**
157      * Enclose a string in quotes, escaping all the quotes within the string.
158      */
quoteString(String s)159     private String quoteString(String s) {
160         return SINGLE_QUOTE + s.replace(Character.toString(SINGLE_QUOTE), "\\'")
161                 + SINGLE_QUOTE;
162     }
163 
164     /**
165      * Recover original string from its escaped version created using
166      * {@link LogCatFilterSettingsSerializer#quoteString(String)}.
167      */
unquoteString(String s)168     private String unquoteString(String s) {
169         s = s.substring(1, s.length() - 1); /* remove start and end QUOTES */
170         return s.replace("\\'", Character.toString(SINGLE_QUOTE));
171     }
172 
getKeyword(String pref)173     private String getKeyword(String pref) {
174         int kwlen = pref.indexOf(KW_DELIM);
175         if (kwlen == -1) {
176             return null;
177         }
178 
179         return pref.substring(0, kwlen);
180     }
181 
182     /**
183      * Get the next quoted string from the input stream of characters.
184      */
getNextString(String s)185     private String getNextString(String s) {
186         assert s.charAt(0) == SINGLE_QUOTE;
187 
188         StringBuffer sb = new StringBuffer();
189 
190         int index = 0;
191         while (index < s.length()) {
192             sb.append(s.charAt(index));
193 
194             if (index > 0
195                     && s.charAt(index) == SINGLE_QUOTE          // current char is a single quote
196                     && s.charAt(index - 1) != ESCAPE_CHAR) {    // prev char wasn't a backslash
197                 /* break if an unescaped SINGLE QUOTE (end of string) is seen */
198                 break;
199             }
200 
201             index++;
202         }
203 
204         return sb.toString();
205     }
206 }
207