mirror of
https://github.com/Anuken/Mindustry.git
synced 2026-10-01 18:50:27 +03:00
Logic \uXXXX escape support
This commit is contained in:
@@ -81,7 +81,7 @@ public class LAssembler{
|
||||
}
|
||||
}
|
||||
|
||||
/** Decodes \n, \" and \\ escape sequences in a string literal's contents (quotes already stripped). */
|
||||
/** Decodes \n, \", \\ and uXXXX escape sequences in a string literal's contents (quotes already stripped). */
|
||||
static String unescape(String s){
|
||||
if(s.indexOf('\\') == -1) return s;
|
||||
|
||||
@@ -98,6 +98,10 @@ public class LAssembler{
|
||||
out.append(next);
|
||||
i ++;
|
||||
continue;
|
||||
}else if(next == 'u' && i + 5 < s.length()){
|
||||
out.append((char)Integer.parseInt(s.substring(i + 2, i + 6), 16));
|
||||
i += 5;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
out.append(c);
|
||||
|
||||
@@ -56,6 +56,17 @@ public class LParser{
|
||||
continue;
|
||||
}
|
||||
|
||||
//uXXXX: validate 4 hex digits
|
||||
if(c == '\\' && pos + 1 < chars.length && chars[pos + 1] == 'u'){
|
||||
if(pos + 5 >= chars.length) error("Invalid \\u escape; expected 4 hex digits.");
|
||||
for(int j = pos + 2; j <= pos + 5; j++){
|
||||
if(Character.digit(chars[j], 16) == -1) error("Invalid \\u escape; expected 4 hex digits.");
|
||||
}
|
||||
utflen += 3; //decoded char may take up to 3 bytes in modified UTF-8
|
||||
pos += 5; //consume u and the 4 hex digits
|
||||
continue;
|
||||
}
|
||||
|
||||
if(c == '\n'){
|
||||
error("Missing closing quote \" before end of line.");
|
||||
}else if(c == '"'){
|
||||
|
||||
@@ -99,13 +99,17 @@ public abstract class LStatement{
|
||||
//escape characters that would otherwise break out of the string or corrupt it.
|
||||
for(int i = 1; i < value.length() - 1; i++){
|
||||
char c = value.charAt(i);
|
||||
//exception: allow escape sequences in strings: \n, \", \\
|
||||
//exception: allow escape sequences in strings: \n, \", \\, uXXXX
|
||||
if(c == '\\' && i + 1 < value.length() - 1){
|
||||
char next = value.charAt(i + 1);
|
||||
if(next == '"' || next == '\\' || next == 'n'){
|
||||
res.append(c).append(next);
|
||||
i ++; //consumed the escape target too
|
||||
continue;
|
||||
}else if(next == 'u' && i + 5 < value.length() - 1 && isHex(value, i + 2)){
|
||||
res.append(value, i, i + 6);
|
||||
i += 5; //consumed u and the 4 hex digits too
|
||||
continue;
|
||||
}
|
||||
}
|
||||
switch(c){
|
||||
@@ -136,6 +140,14 @@ public abstract class LStatement{
|
||||
return value;
|
||||
}
|
||||
|
||||
/** True if the 4 characters at value[from..from+3] are all hex digits. */
|
||||
private static boolean isHex(String value, int from){
|
||||
for(int i = from; i < from + 4; i++){
|
||||
if(Character.digit(value.charAt(i), 16) == -1) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected static boolean logicLocalization(){
|
||||
return Core.settings.getBool("logiclocalization", true);
|
||||
}
|
||||
|
||||
@@ -83,6 +83,21 @@ public class LogicTests{
|
||||
"escaped backslash sitting right before the closing quote",
|
||||
"set result \"end\\\\\"",
|
||||
"end\\"
|
||||
),
|
||||
Arguments.of(
|
||||
"\\u0041 decodes to the corresponding unicode character",
|
||||
"set result \"\\u0041\"",
|
||||
"A"
|
||||
),
|
||||
Arguments.of(
|
||||
"\\uf8ff decodes to the corresponding unicode character",
|
||||
"set result \"\\uf8ff\\uf8ff\"",
|
||||
""
|
||||
),
|
||||
Arguments.of(
|
||||
"\\u escapes combined with other escapes in one string",
|
||||
"set result \"\\u0041\\n\\u0042\\\\end\"",
|
||||
"A\nB\\end"
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -140,7 +155,32 @@ public class LogicTests{
|
||||
Arguments.of("a raw '#' in an unquoted value gets neutralized so it can't start a comment", "a#b", "a_b"),
|
||||
Arguments.of("a lone newline character is invalid on its own, same as a lone space", "\n", "invalid"),
|
||||
Arguments.of("a lone tab character is invalid on its own, same as a lone space", "\t", "invalid"),
|
||||
Arguments.of("a lone '#' character is invalid on its own, same as a lone space", "#", "invalid")
|
||||
Arguments.of("a lone '#' character is invalid on its own, same as a lone space", "#", "invalid"),
|
||||
Arguments.of(
|
||||
"a well-formed \\uXXXX escape inside a quoted value passes through untouched",
|
||||
"\"\\u0041\"",
|
||||
"\"\\u0041\""
|
||||
),
|
||||
Arguments.of(
|
||||
"\\uXXXX combined with other escapes inside a quoted value",
|
||||
"\"\\u0041\\n\\u0042\\\\end\"",
|
||||
"\"\\u0041\\n\\u0042\\\\end\""
|
||||
),
|
||||
Arguments.of(
|
||||
"a malformed \\u escape with too few digits still escapes the backslash instead of throwing",
|
||||
"\"\\u12\"",
|
||||
"\"\\\\u12\""
|
||||
),
|
||||
Arguments.of(
|
||||
"a malformed \\u escape with non-hex digits still escapes the backslash instead of throwing",
|
||||
"\"\\u12zz\"",
|
||||
"\"\\\\u12zz\""
|
||||
),
|
||||
Arguments.of(
|
||||
"a \\u escape truncated by the closing quote still escapes the backslash instead of throwing",
|
||||
"\"a\\u123\"",
|
||||
"\"a\\\\u123\""
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -232,6 +272,22 @@ public class LogicTests{
|
||||
Arguments.of(
|
||||
"a string that never closes before the line ends, with trailing content after it",
|
||||
"set result \"asd\nset bar 5"
|
||||
),
|
||||
Arguments.of(
|
||||
"a \\u escape with non-hex digits is rejected",
|
||||
"set result \"\\u12zz\""
|
||||
),
|
||||
Arguments.of(
|
||||
"a \\u escape with non-hex digits is rejected",
|
||||
"set result \"\\u1h23\""
|
||||
),
|
||||
Arguments.of(
|
||||
"a \\u escape with non-hex digits is rejected",
|
||||
"set result \"\\uhh23\""
|
||||
),
|
||||
Arguments.of(
|
||||
"a \\u escape truncated by the closing quote is rejected",
|
||||
"set result \"\\u12\""
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user