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 */ 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 */ 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 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 */ 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 */ 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 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 */ 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