Home | History | Annotate | Download | only in logcat
      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