Loading java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java +68 −14 Original line number Diff line number Diff line Loading @@ -53,7 +53,9 @@ public final class KeySpecParser { private static final int MAX_STRING_REFERENCE_INDIRECTION = 10; // Constants for parsing. private static final char LABEL_END = '|'; private static final char COMMA = ','; private static final char BACKSLASH = '\\'; private static final char VERTICAL_BAR = '|'; private static final String PREFIX_TEXT = "!text/"; static final String PREFIX_ICON = "!icon/"; private static final String PREFIX_CODE = "!code/"; Loading @@ -64,6 +66,59 @@ public final class KeySpecParser { // Intentional empty constructor for utility class. } /** * Split the text containing multiple key specifications separated by commas into an array of * key specifications. * A key specification can contain a character escaped by the backslash character, including a * comma character. * Note that an empty key specification will be eliminated from the result array. * * @param text the text containing multiple key specifications. * @return an array of key specification text. Null if the specified <code>text</code> is empty * or has no key specifications. */ public static String[] splitKeySpecs(final String text) { final int size = text.length(); if (size == 0) { return null; } // Optimization for one-letter key specification. if (size == 1) { return text.charAt(0) == COMMA ? null : new String[] { text }; } ArrayList<String> list = null; int start = 0; // The characters in question in this loop are COMMA and BACKSLASH. These characters never // match any high or low surrogate character. So it is OK to iterate through with char // index. for (int pos = 0; pos < size; pos++) { final char c = text.charAt(pos); if (c == COMMA) { // Skip empty entry. if (pos - start > 0) { if (list == null) { list = CollectionUtils.newArrayList(); } list.add(text.substring(start, pos)); } // Skip comma start = pos + 1; } else if (c == BACKSLASH) { // Skip escape character and escaped character. pos++; } } final String remain = (size - start > 0) ? text.substring(start) : null; if (list == null) { return remain != null ? new String[] { remain } : null; } if (remain != null) { list.add(remain); } return list.toArray(new String[list.size()]); } private static boolean hasIcon(final String moreKeySpec) { return moreKeySpec.startsWith(PREFIX_ICON); } Loading @@ -78,14 +133,14 @@ public final class KeySpecParser { } private static String parseEscape(final String text) { if (text.indexOf(Constants.CSV_ESCAPE) < 0) { if (text.indexOf(BACKSLASH) < 0) { return text; } final int length = text.length(); final StringBuilder sb = new StringBuilder(); for (int pos = 0; pos < length; pos++) { final char c = text.charAt(pos); if (c == Constants.CSV_ESCAPE && pos + 1 < length) { if (c == BACKSLASH && pos + 1 < length) { // Skip escape char pos++; sb.append(text.charAt(pos)); Loading @@ -97,20 +152,20 @@ public final class KeySpecParser { } private static int indexOfLabelEnd(final String moreKeySpec, final int start) { if (moreKeySpec.indexOf(Constants.CSV_ESCAPE, start) < 0) { final int end = moreKeySpec.indexOf(LABEL_END, start); if (moreKeySpec.indexOf(BACKSLASH, start) < 0) { final int end = moreKeySpec.indexOf(VERTICAL_BAR, start); if (end == 0) { throw new KeySpecParserError(LABEL_END + " at " + start + ": " + moreKeySpec); throw new KeySpecParserError(VERTICAL_BAR + " at " + start + ": " + moreKeySpec); } return end; } final int length = moreKeySpec.length(); for (int pos = start; pos < length; pos++) { final char c = moreKeySpec.charAt(pos); if (c == Constants.CSV_ESCAPE && pos + 1 < length) { if (c == BACKSLASH && pos + 1 < length) { // Skip escape char pos++; } else if (c == LABEL_END) { } else if (c == VERTICAL_BAR) { return pos; } } Loading @@ -136,9 +191,9 @@ public final class KeySpecParser { return null; } if (indexOfLabelEnd(moreKeySpec, end + 1) >= 0) { throw new KeySpecParserError("Multiple " + LABEL_END + ": " + moreKeySpec); throw new KeySpecParserError("Multiple " + VERTICAL_BAR + ": " + moreKeySpec); } return parseEscape(moreKeySpec.substring(end + /* LABEL_END */1)); return parseEscape(moreKeySpec.substring(end + /* VERTICAL_BAR */1)); } static String getOutputText(final String moreKeySpec) { Loading Loading @@ -169,7 +224,7 @@ public final class KeySpecParser { if (hasCode(moreKeySpec)) { final int end = indexOfLabelEnd(moreKeySpec, 0); if (indexOfLabelEnd(moreKeySpec, end + 1) >= 0) { throw new KeySpecParserError("Multiple " + LABEL_END + ": " + moreKeySpec); throw new KeySpecParserError("Multiple " + VERTICAL_BAR + ": " + moreKeySpec); } return parseCode(moreKeySpec.substring(end + 1), codesSet, CODE_UNSPECIFIED); } Loading Loading @@ -204,7 +259,7 @@ public final class KeySpecParser { public static int getIconId(final String moreKeySpec) { if (moreKeySpec != null && hasIcon(moreKeySpec)) { final int end = moreKeySpec.indexOf(LABEL_END, PREFIX_ICON.length()); final int end = moreKeySpec.indexOf(VERTICAL_BAR, PREFIX_ICON.length()); final String name = (end < 0) ? moreKeySpec.substring(PREFIX_ICON.length()) : moreKeySpec.substring(PREFIX_ICON.length(), end); return KeyboardIconsSet.getIconId(name); Loading Loading @@ -351,7 +406,7 @@ public final class KeySpecParser { final String name = text.substring(pos + prefixLen, end); sb.append(textsSet.getText(name)); pos = end - 1; } else if (c == Constants.CSV_ESCAPE) { } else if (c == BACKSLASH) { if (sb != null) { // Append both escape character and escaped character. sb.append(text.substring(pos, Math.min(pos + 2, size))); Loading @@ -366,7 +421,6 @@ public final class KeySpecParser { text = sb.toString(); } } while (sb != null); return text; } Loading java/src/com/android/inputmethod/keyboard/internal/KeyStyle.java +1 −3 Original line number Diff line number Diff line Loading @@ -18,8 +18,6 @@ package com.android.inputmethod.keyboard.internal; import android.content.res.TypedArray; import com.android.inputmethod.latin.StringUtils; public abstract class KeyStyle { private final KeyboardTextsSet mTextsSet; Loading @@ -42,7 +40,7 @@ public abstract class KeyStyle { protected String[] parseStringArray(final TypedArray a, final int index) { if (a.hasValue(index)) { final String text = KeySpecParser.resolveTextReference(a.getString(index), mTextsSet); return StringUtils.parseCsvString(text); return KeySpecParser.splitKeySpecs(text); } return null; } Loading java/src/com/android/inputmethod/latin/Constants.java +0 −4 Original line number Diff line number Diff line Loading @@ -215,10 +215,6 @@ public final class Constants { } } // Constants for CSV parsing. public static final char CSV_SEPARATOR = ','; public static final char CSV_ESCAPE = '\\'; private Constants() { // This utility class is not publicly instantiable. } Loading java/src/com/android/inputmethod/latin/SettingsValues.java +1 −1 Original line number Diff line number Diff line Loading @@ -100,7 +100,7 @@ public final class SettingsValues { mWordConnectors = StringUtils.toCodePointArray(res.getString(R.string.symbols_word_connectors)); Arrays.sort(mWordConnectors); final String[] suggestPuncsSpec = StringUtils.parseCsvString(res.getString( final String[] suggestPuncsSpec = KeySpecParser.splitKeySpecs(res.getString( R.string.suggested_punctuations)); mSuggestPuncList = createSuggestPuncList(suggestPuncsSpec); mWordSeparators = res.getString(R.string.symbols_word_separators); Loading java/src/com/android/inputmethod/latin/StringUtils.java +0 −38 Original line number Diff line number Diff line Loading @@ -153,44 +153,6 @@ public final class StringUtils { return codePoints; } public static String[] parseCsvString(final String text) { final int size = text.length(); if (size == 0) { return null; } if (codePointCount(text) == 1) { return text.codePointAt(0) == Constants.CSV_SEPARATOR ? null : new String[] { text }; } ArrayList<String> list = null; int start = 0; for (int pos = 0; pos < size; pos++) { final char c = text.charAt(pos); if (c == Constants.CSV_SEPARATOR) { // Skip empty entry. if (pos - start > 0) { if (list == null) { list = CollectionUtils.newArrayList(); } list.add(text.substring(start, pos)); } // Skip comma start = pos + 1; } else if (c == Constants.CSV_ESCAPE) { // Skip escape character and escaped character. pos++; } } final String remain = (size - start > 0) ? text.substring(start) : null; if (list == null) { return remain != null ? new String[] { remain } : null; } if (remain != null) { list.add(remain); } return list.toArray(new String[list.size()]); } // This method assumes the text is not null. For the empty string, it returns CAPITALIZE_NONE. public static int getCapitalizationType(final String text) { // If the first char is not uppercase, then the word is either all lower case or Loading Loading
java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java +68 −14 Original line number Diff line number Diff line Loading @@ -53,7 +53,9 @@ public final class KeySpecParser { private static final int MAX_STRING_REFERENCE_INDIRECTION = 10; // Constants for parsing. private static final char LABEL_END = '|'; private static final char COMMA = ','; private static final char BACKSLASH = '\\'; private static final char VERTICAL_BAR = '|'; private static final String PREFIX_TEXT = "!text/"; static final String PREFIX_ICON = "!icon/"; private static final String PREFIX_CODE = "!code/"; Loading @@ -64,6 +66,59 @@ public final class KeySpecParser { // Intentional empty constructor for utility class. } /** * Split the text containing multiple key specifications separated by commas into an array of * key specifications. * A key specification can contain a character escaped by the backslash character, including a * comma character. * Note that an empty key specification will be eliminated from the result array. * * @param text the text containing multiple key specifications. * @return an array of key specification text. Null if the specified <code>text</code> is empty * or has no key specifications. */ public static String[] splitKeySpecs(final String text) { final int size = text.length(); if (size == 0) { return null; } // Optimization for one-letter key specification. if (size == 1) { return text.charAt(0) == COMMA ? null : new String[] { text }; } ArrayList<String> list = null; int start = 0; // The characters in question in this loop are COMMA and BACKSLASH. These characters never // match any high or low surrogate character. So it is OK to iterate through with char // index. for (int pos = 0; pos < size; pos++) { final char c = text.charAt(pos); if (c == COMMA) { // Skip empty entry. if (pos - start > 0) { if (list == null) { list = CollectionUtils.newArrayList(); } list.add(text.substring(start, pos)); } // Skip comma start = pos + 1; } else if (c == BACKSLASH) { // Skip escape character and escaped character. pos++; } } final String remain = (size - start > 0) ? text.substring(start) : null; if (list == null) { return remain != null ? new String[] { remain } : null; } if (remain != null) { list.add(remain); } return list.toArray(new String[list.size()]); } private static boolean hasIcon(final String moreKeySpec) { return moreKeySpec.startsWith(PREFIX_ICON); } Loading @@ -78,14 +133,14 @@ public final class KeySpecParser { } private static String parseEscape(final String text) { if (text.indexOf(Constants.CSV_ESCAPE) < 0) { if (text.indexOf(BACKSLASH) < 0) { return text; } final int length = text.length(); final StringBuilder sb = new StringBuilder(); for (int pos = 0; pos < length; pos++) { final char c = text.charAt(pos); if (c == Constants.CSV_ESCAPE && pos + 1 < length) { if (c == BACKSLASH && pos + 1 < length) { // Skip escape char pos++; sb.append(text.charAt(pos)); Loading @@ -97,20 +152,20 @@ public final class KeySpecParser { } private static int indexOfLabelEnd(final String moreKeySpec, final int start) { if (moreKeySpec.indexOf(Constants.CSV_ESCAPE, start) < 0) { final int end = moreKeySpec.indexOf(LABEL_END, start); if (moreKeySpec.indexOf(BACKSLASH, start) < 0) { final int end = moreKeySpec.indexOf(VERTICAL_BAR, start); if (end == 0) { throw new KeySpecParserError(LABEL_END + " at " + start + ": " + moreKeySpec); throw new KeySpecParserError(VERTICAL_BAR + " at " + start + ": " + moreKeySpec); } return end; } final int length = moreKeySpec.length(); for (int pos = start; pos < length; pos++) { final char c = moreKeySpec.charAt(pos); if (c == Constants.CSV_ESCAPE && pos + 1 < length) { if (c == BACKSLASH && pos + 1 < length) { // Skip escape char pos++; } else if (c == LABEL_END) { } else if (c == VERTICAL_BAR) { return pos; } } Loading @@ -136,9 +191,9 @@ public final class KeySpecParser { return null; } if (indexOfLabelEnd(moreKeySpec, end + 1) >= 0) { throw new KeySpecParserError("Multiple " + LABEL_END + ": " + moreKeySpec); throw new KeySpecParserError("Multiple " + VERTICAL_BAR + ": " + moreKeySpec); } return parseEscape(moreKeySpec.substring(end + /* LABEL_END */1)); return parseEscape(moreKeySpec.substring(end + /* VERTICAL_BAR */1)); } static String getOutputText(final String moreKeySpec) { Loading Loading @@ -169,7 +224,7 @@ public final class KeySpecParser { if (hasCode(moreKeySpec)) { final int end = indexOfLabelEnd(moreKeySpec, 0); if (indexOfLabelEnd(moreKeySpec, end + 1) >= 0) { throw new KeySpecParserError("Multiple " + LABEL_END + ": " + moreKeySpec); throw new KeySpecParserError("Multiple " + VERTICAL_BAR + ": " + moreKeySpec); } return parseCode(moreKeySpec.substring(end + 1), codesSet, CODE_UNSPECIFIED); } Loading Loading @@ -204,7 +259,7 @@ public final class KeySpecParser { public static int getIconId(final String moreKeySpec) { if (moreKeySpec != null && hasIcon(moreKeySpec)) { final int end = moreKeySpec.indexOf(LABEL_END, PREFIX_ICON.length()); final int end = moreKeySpec.indexOf(VERTICAL_BAR, PREFIX_ICON.length()); final String name = (end < 0) ? moreKeySpec.substring(PREFIX_ICON.length()) : moreKeySpec.substring(PREFIX_ICON.length(), end); return KeyboardIconsSet.getIconId(name); Loading Loading @@ -351,7 +406,7 @@ public final class KeySpecParser { final String name = text.substring(pos + prefixLen, end); sb.append(textsSet.getText(name)); pos = end - 1; } else if (c == Constants.CSV_ESCAPE) { } else if (c == BACKSLASH) { if (sb != null) { // Append both escape character and escaped character. sb.append(text.substring(pos, Math.min(pos + 2, size))); Loading @@ -366,7 +421,6 @@ public final class KeySpecParser { text = sb.toString(); } } while (sb != null); return text; } Loading
java/src/com/android/inputmethod/keyboard/internal/KeyStyle.java +1 −3 Original line number Diff line number Diff line Loading @@ -18,8 +18,6 @@ package com.android.inputmethod.keyboard.internal; import android.content.res.TypedArray; import com.android.inputmethod.latin.StringUtils; public abstract class KeyStyle { private final KeyboardTextsSet mTextsSet; Loading @@ -42,7 +40,7 @@ public abstract class KeyStyle { protected String[] parseStringArray(final TypedArray a, final int index) { if (a.hasValue(index)) { final String text = KeySpecParser.resolveTextReference(a.getString(index), mTextsSet); return StringUtils.parseCsvString(text); return KeySpecParser.splitKeySpecs(text); } return null; } Loading
java/src/com/android/inputmethod/latin/Constants.java +0 −4 Original line number Diff line number Diff line Loading @@ -215,10 +215,6 @@ public final class Constants { } } // Constants for CSV parsing. public static final char CSV_SEPARATOR = ','; public static final char CSV_ESCAPE = '\\'; private Constants() { // This utility class is not publicly instantiable. } Loading
java/src/com/android/inputmethod/latin/SettingsValues.java +1 −1 Original line number Diff line number Diff line Loading @@ -100,7 +100,7 @@ public final class SettingsValues { mWordConnectors = StringUtils.toCodePointArray(res.getString(R.string.symbols_word_connectors)); Arrays.sort(mWordConnectors); final String[] suggestPuncsSpec = StringUtils.parseCsvString(res.getString( final String[] suggestPuncsSpec = KeySpecParser.splitKeySpecs(res.getString( R.string.suggested_punctuations)); mSuggestPuncList = createSuggestPuncList(suggestPuncsSpec); mWordSeparators = res.getString(R.string.symbols_word_separators); Loading
java/src/com/android/inputmethod/latin/StringUtils.java +0 −38 Original line number Diff line number Diff line Loading @@ -153,44 +153,6 @@ public final class StringUtils { return codePoints; } public static String[] parseCsvString(final String text) { final int size = text.length(); if (size == 0) { return null; } if (codePointCount(text) == 1) { return text.codePointAt(0) == Constants.CSV_SEPARATOR ? null : new String[] { text }; } ArrayList<String> list = null; int start = 0; for (int pos = 0; pos < size; pos++) { final char c = text.charAt(pos); if (c == Constants.CSV_SEPARATOR) { // Skip empty entry. if (pos - start > 0) { if (list == null) { list = CollectionUtils.newArrayList(); } list.add(text.substring(start, pos)); } // Skip comma start = pos + 1; } else if (c == Constants.CSV_ESCAPE) { // Skip escape character and escaped character. pos++; } } final String remain = (size - start > 0) ? text.substring(start) : null; if (list == null) { return remain != null ? new String[] { remain } : null; } if (remain != null) { list.add(remain); } return list.toArray(new String[list.size()]); } // This method assumes the text is not null. For the empty string, it returns CAPITALIZE_NONE. public static int getCapitalizationType(final String text) { // If the first char is not uppercase, then the word is either all lower case or Loading