/* * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.ddmuilib.logcat; import com.android.ddmlib.Log.LogLevel; import java.util.ArrayList; import java.util.List; /** * Class to help save/restore user created filters. * * Users can create multiple filters in the logcat view. These filters could have regexes * in their settings. All of the user created filters are saved into a single Eclipse * preference. This class helps in generating the string to be saved given a list of * {@link LogCatFilter}'s, and also does the reverse of creating the list of filters * given the encoded string. */ public final class LogCatFilterSettingsSerializer { private static final char SINGLE_QUOTE = '\''; private static final char ESCAPE_CHAR = '\\'; private static final String ATTR_DELIM = ", "; private static final String KW_DELIM = ": "; private static final String KW_NAME = "name"; private static final String KW_TAG = "tag"; private static final String KW_TEXT = "text"; private static final String KW_PID = "pid"; private static final String KW_APP = "app"; private static final String KW_LOGLEVEL = "level"; /** * Encode the settings from a list of {@link LogCatFilter}'s into a string for saving to * the preference store. See * {@link LogCatFilterSettingsSerializer#decodeFromPreferenceString(String)} for the * reverse operation. * @param filters list of filters to save. * @return an encoded string that can be saved in Eclipse preference store. The encoded string * is of a list of key:'value' pairs. */ public String encodeToPreferenceString(List<LogCatFilter> filters) { StringBuffer sb = new StringBuffer(); for (LogCatFilter f : filters) { if (f.isTransient()) { // do not persist transient filters continue; } sb.append(KW_NAME); sb.append(KW_DELIM); sb.append(quoteString(f.getName())); sb.append(ATTR_DELIM); sb.append(KW_TAG); sb.append(KW_DELIM); sb.append(quoteString(f.getTag())); sb.append(ATTR_DELIM); sb.append(KW_TEXT); sb.append(KW_DELIM); sb.append(quoteString(f.getText())); sb.append(ATTR_DELIM); sb.append(KW_PID); sb.append(KW_DELIM); sb.append(quoteString(f.getPid())); sb.append(ATTR_DELIM); sb.append(KW_APP); sb.append(KW_DELIM); sb.append(quoteString(f.getAppName())); sb.append(ATTR_DELIM); sb.append(KW_LOGLEVEL); sb.append(KW_DELIM); sb.append(quoteString(f.getLogLevel().getStringValue())); sb.append(ATTR_DELIM); } return sb.toString(); } /** * Decode an encoded string representing the settings of a list of logcat * filters into a list of {@link LogCatFilter}'s. * @param pref encoded preference string * @return a list of {@link LogCatFilter} */ public List<LogCatFilter> decodeFromPreferenceString(String pref) { List<LogCatFilter> fs = new ArrayList<LogCatFilter>(); /* first split the string into a list of key, value pairs */ List<String> kv = getKeyValues(pref); if (kv.size() == 0) { return fs; } /* construct filter settings from the key value pairs */ int index = 0; while (index < kv.size()) { String name = ""; String tag = ""; String pid = ""; String app = ""; String text = ""; LogLevel level = LogLevel.VERBOSE; assert kv.get(index).equals(KW_NAME); name = kv.get(index + 1); index += 2; while (index < kv.size() && !kv.get(index).equals(KW_NAME)) { String key = kv.get(index); String value = kv.get(index + 1); index += 2; if (key.equals(KW_TAG)) { tag = value; } else if (key.equals(KW_TEXT)) { text = value; } else if (key.equals(KW_PID)) { pid = value; } else if (key.equals(KW_APP)) { app = value; } else if (key.equals(KW_LOGLEVEL)) { level = LogLevel.getByString(value); } } fs.add(new LogCatFilter(name, tag, text, pid, app, level)); } return fs; } private List<String> getKeyValues(String pref) { List<String> kv = new ArrayList<String>(); int index = 0; while (index < pref.length()) { String kw = getKeyword(pref.substring(index)); if (kw == null) { break; } index += kw.length() + KW_DELIM.length(); String value = getNextString(pref.substring(index)); index += value.length() + ATTR_DELIM.length(); value = unquoteString(value); kv.add(kw); kv.add(value); } return kv; } /** * Enclose a string in quotes, escaping all the quotes within the string. */ private String quoteString(String s) { return SINGLE_QUOTE + s.replace(Character.toString(SINGLE_QUOTE), "\\'") + SINGLE_QUOTE; } /** * Recover original string from its escaped version created using * {@link LogCatFilterSettingsSerializer#quoteString(String)}. */ private String unquoteString(String s) { s = s.substring(1, s.length() - 1); /* remove start and end QUOTES */ return s.replace("\\'", Character.toString(SINGLE_QUOTE)); } private String getKeyword(String pref) { int kwlen = pref.indexOf(KW_DELIM); if (kwlen == -1) { return null; } return pref.substring(0, kwlen); } /** * Get the next quoted string from the input stream of characters. */ private String getNextString(String s) { assert s.charAt(0) == SINGLE_QUOTE; StringBuffer sb = new StringBuffer(); int index = 0; while (index < s.length()) { sb.append(s.charAt(index)); if (index > 0 && s.charAt(index) == SINGLE_QUOTE // current char is a single quote && s.charAt(index - 1) != ESCAPE_CHAR) { // prev char wasn't a backslash /* break if an unescaped SINGLE QUOTE (end of string) is seen */ break; } index++; } return sb.toString(); } }