am f6cf387e: Merge "Recursively resolve @string/resource reference in key key spec parsing"
* commit 'f6cf387edc5e70dd578790c2625c50ed00a5dbf0': Recursively resolve @string/resource reference in key key spec parsingmain
commit
2cce593b60
|
@ -43,6 +43,8 @@ import java.util.Arrays;
|
||||||
public class KeySpecParser {
|
public class KeySpecParser {
|
||||||
private static final boolean DEBUG = LatinImeLogger.sDBG;
|
private static final boolean DEBUG = LatinImeLogger.sDBG;
|
||||||
|
|
||||||
|
private static final int MAX_STRING_REFERENCE_INDIRECTION = 10;
|
||||||
|
|
||||||
// Constants for parsing.
|
// Constants for parsing.
|
||||||
private static int COMMA = ',';
|
private static int COMMA = ',';
|
||||||
private static final char ESCAPE_CHAR = '\\';
|
private static final char ESCAPE_CHAR = '\\';
|
||||||
|
@ -274,35 +276,51 @@ public class KeySpecParser {
|
||||||
return resId;
|
return resId;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String resolveStringResource(String text, Resources res, int packageNameResId) {
|
private static String resolveStringResource(String rawText, Resources res,
|
||||||
final int size = text.length();
|
int packageNameResId) {
|
||||||
if (size < PREFIX_STRING.length()) {
|
int level = 0;
|
||||||
return text;
|
String text = rawText;
|
||||||
}
|
StringBuilder sb;
|
||||||
|
do {
|
||||||
StringBuilder sb = null;
|
level++;
|
||||||
for (int pos = 0; pos < size; pos++) {
|
if (level >= MAX_STRING_REFERENCE_INDIRECTION) {
|
||||||
final char c = text.charAt(pos);
|
throw new RuntimeException("too many @string/resource indirection: " + text);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return (sb == null) ? text : sb.toString();
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sb != null) {
|
||||||
|
text = sb.toString();
|
||||||
|
}
|
||||||
|
} while (sb != null);
|
||||||
|
|
||||||
|
return text;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int searchResourceNameEnd(String text, int start) {
|
private static int searchResourceNameEnd(String text, int start) {
|
||||||
|
|
|
@ -50,4 +50,7 @@
|
||||||
<string name="multiple_labels_with_escape_surrounded_by_spaces">" \\abc , d\\ef , gh\\i "</string>
|
<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">"ab\\\\,d\\\\\\,,g\\,i"</string>
|
||||||
<string name="multiple_labels_with_comma_and_escape_surrounded_by_spaces">" 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>
|
</resources>
|
||||||
|
|
|
@ -288,4 +288,16 @@ public class KeySpecParserCsvTests extends AndroidTestCase {
|
||||||
"abc@string/multiple_labels",
|
"abc@string/multiple_labels",
|
||||||
"abcabc", "def", "ghi");
|
"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");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue