aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTadashi G. Takaoka <takaoka@google.com>2012-02-03 19:34:47 +0900
committerTadashi G. Takaoka <takaoka@google.com>2012-02-03 20:03:23 +0900
commitaca8870128caeec74ed4426f3c1e23ab60597453 (patch)
tree210c0150956a73bc3e4417935bafc0379db48ab3
parent9f491e34ac2c96c3d18f30f9710b1a3ecab173e7 (diff)
downloadlatinime-aca8870128caeec74ed4426f3c1e23ab60597453.tar.gz
latinime-aca8870128caeec74ed4426f3c1e23ab60597453.tar.xz
latinime-aca8870128caeec74ed4426f3c1e23ab60597453.zip
Recursively resolve @string/resource reference in key key spec parsing
Change-Id: I9d172605e90e828e00f7c4c8d49548498aa3b50d
-rw-r--r--java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java70
-rw-r--r--tests/res/values/donottranslate.xml3
-rw-r--r--tests/src/com/android/inputmethod/keyboard/internal/KeySpecParserCsvTests.java12
3 files changed, 59 insertions, 26 deletions
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java b/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java
index adb5f4759..e3c5da456 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeySpecParser.java
@@ -43,6 +43,8 @@ import java.util.Arrays;
public class KeySpecParser {
private static final boolean DEBUG = LatinImeLogger.sDBG;
+ private static final int MAX_STRING_REFERENCE_INDIRECTION = 10;
+
// Constants for parsing.
private static int COMMA = ',';
private static final char ESCAPE_CHAR = '\\';
@@ -274,35 +276,51 @@ public class KeySpecParser {
return resId;
}
- private static String resolveStringResource(String text, Resources res, int packageNameResId) {
- final int size = text.length();
- if (size < PREFIX_STRING.length()) {
- return text;
- }
+ private static String resolveStringResource(String rawText, Resources res,
+ int packageNameResId) {
+ int level = 0;
+ String text = rawText;
+ StringBuilder sb;
+ do {
+ level++;
+ if (level >= MAX_STRING_REFERENCE_INDIRECTION) {
+ throw new RuntimeException("too many @string/resource indirection: " + text);
+ }
- StringBuilder sb = null;
- for (int pos = 0; pos < size; pos++) {
- final char c = text.charAt(pos);
- if (c == PREFIX_AT && text.startsWith(PREFIX_STRING, pos)) {
- if (sb == null) {
- sb = new StringBuilder(text.substring(0, pos));
- }
- final int end = searchResourceNameEnd(text, pos + PREFIX_STRING.length());
- final String resName = text.substring(pos + 1, end);
- final int resId = getResourceId(res, resName, packageNameResId);
- sb.append(res.getString(resId));
- pos = end - 1;
- } else if (c == ESCAPE_CHAR) {
- if (sb != null) {
- // Append both escape character and escaped character.
- sb.append(text.substring(pos, Math.min(pos + 2, size)));
+ final int size = text.length();
+ if (size < PREFIX_STRING.length()) {
+ return text;
+ }
+
+ sb = null;
+ for (int pos = 0; pos < size; pos++) {
+ final char c = text.charAt(pos);
+ if (c == PREFIX_AT && text.startsWith(PREFIX_STRING, pos)) {
+ if (sb == null) {
+ sb = new StringBuilder(text.substring(0, pos));
+ }
+ final int end = searchResourceNameEnd(text, pos + PREFIX_STRING.length());
+ final String resName = text.substring(pos + 1, end);
+ final int resId = getResourceId(res, resName, packageNameResId);
+ sb.append(res.getString(resId));
+ pos = end - 1;
+ } else if (c == ESCAPE_CHAR) {
+ if (sb != null) {
+ // Append both escape character and escaped character.
+ sb.append(text.substring(pos, Math.min(pos + 2, size)));
+ }
+ pos++;
+ } else if (sb != null) {
+ sb.append(c);
}
- pos++;
- } else if (sb != null) {
- sb.append(c);
}
- }
- return (sb == null) ? text : sb.toString();
+
+ if (sb != null) {
+ text = sb.toString();
+ }
+ } while (sb != null);
+
+ return text;
}
private static int searchResourceNameEnd(String text, int start) {
diff --git a/tests/res/values/donottranslate.xml b/tests/res/values/donottranslate.xml
index d0cde71a5..1ca4451d4 100644
--- a/tests/res/values/donottranslate.xml
+++ b/tests/res/values/donottranslate.xml
@@ -50,4 +50,7 @@
<string name="multiple_labels_with_escape_surrounded_by_spaces">" \\abc , d\\ef , gh\\i "</string>
<string name="multiple_labels_with_comma_and_escape">"ab\\\\,d\\\\\\,,g\\,i"</string>
<string name="multiple_labels_with_comma_and_escape_surrounded_by_spaces">" ab\\\\ , d\\\\\\, , g\\,i "</string>
+ <string name="indirect_string">@string/multiple_chars</string>
+ <string name="indirect_string_with_literal">x,@string/multiple_chars,y</string>
+ <string name="infinite_indirection">infinite,@string/infinite_indirection,loop</string>
</resources>
diff --git a/tests/src/com/android/inputmethod/keyboard/internal/KeySpecParserCsvTests.java b/tests/src/com/android/inputmethod/keyboard/internal/KeySpecParserCsvTests.java
index a0ce86d1c..e090031e4 100644
--- a/tests/src/com/android/inputmethod/keyboard/internal/KeySpecParserCsvTests.java
+++ b/tests/src/com/android/inputmethod/keyboard/internal/KeySpecParserCsvTests.java
@@ -288,4 +288,16 @@ public class KeySpecParserCsvTests extends AndroidTestCase {
"abc@string/multiple_labels",
"abcabc", "def", "ghi");
}
+
+ public void testParseIndirectReference() {
+ assertTextArray("Indirect",
+ "@string/indirect_string", "a", "b", "c");
+ assertTextArray("Indirect with literal",
+ "1,@string/indirect_string_with_literal,2", "1", "x", "a", "b", "c", "y", "2");
+ }
+
+ public void testParseInfiniteIndirectReference() {
+ assertError("Infinite indirection",
+ "1,@string/infinite_indirection,2", "1", "infinite", "<infinite>", "loop", "2");
+ }
}