Issue #698 Allowing unicode letters in identifiers

This commit is contained in:
Jindra Petřík
2014-11-05 18:29:54 +01:00
parent e19562fefd
commit fba15b21f7
3 changed files with 741 additions and 735 deletions

View File

@@ -39,25 +39,27 @@ public class IdentifiersDeobfuscation {
public HashSet<String> allVariableNamesStr = new HashSet<>();
private final HashMap<String, Integer> typeCounts = new HashMap<>();
public static final String VALID_FIRST_CHARACTERS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_";
public static final String VALID_NEXT_CHARACTERS = VALID_FIRST_CHARACTERS + "0123456789";
public static final String VALID_FIRST_CHARACTERS = "\\p{Lu}\\p{Ll}\\p{Lt}\\p{Lm}\\p{Lo}_$";
public static final String VALID_NEXT_CHARACTERS = VALID_FIRST_CHARACTERS + "\\p{Nl}\\p{Mn}\\p{Mc}\\p{Nd}\\p{Pc}";
public static final Pattern IDENTIFIER_PATTERN = Pattern.compile("^[" + VALID_FIRST_CHARACTERS + "][" + VALID_NEXT_CHARACTERS + "]*$");
public static final String FOO_CHARACTERS = "bcdfghjklmnpqrstvwz";
public static final String FOO_JOIN_CHARACTERS = "aeiouy";
//http://help.adobe.com/en_US/AS2LCR/Flash_10.0/help.html?content=00000477.html
public static final String[] reservedWordsAS2= {
public static final String[] reservedWordsAS2 = {
//is "add" really a keyword? documentation says yes, but I can create "add" variable in CS6...
//"add",
"and","break","case","catch","class","continue","default","delete","do","dynamic","else",
"eq","extends","false","finally","for","function","ge","get","gt","if","ifFrameLoaded","implements",
"import","in","instanceof","interface","intrinsic","le",
"and", "break", "case", "catch", "class", "continue", "default", "delete", "do", "dynamic", "else",
"eq", "extends", "false", "finally", "for", "function", "ge", "get", "gt", "if", "ifFrameLoaded", "implements",
"import", "in", "instanceof", "interface", "intrinsic", "le",
//is "it" really a keyword? documentation says yes, but I can create "it" variable in CS6...
//"it",
"ne","new","not","null","on","onClipEvent",
"or","private","public","return","set","static","super","switch","tellTarget","this","throw","try",
"typeof","undefined","var","void","while","with"
"ne", "new", "not", "null", "on", "onClipEvent",
"or", "private", "public", "return", "set", "static", "super", "switch", "tellTarget", "this", "throw", "try",
"typeof", "undefined", "var", "void", "while", "with"
};
//http://www.adobe.com/devnet/actionscript/learning/as3-fundamentals/syntax.html
public static final String[] reservedWordsAS3 = {
"as", "break", "case", "catch", "class", "const", "continue", "default", "delete", "do", "else",
@@ -67,16 +69,16 @@ public class IdentifiersDeobfuscation {
//is "to" really a keyword? documentation says yes, but I can create "to" variable...
// "to",
"true", "try", "typeof", "use", "var",
"void","while","with"
"void", "while", "with"
};
//syntactic keywords - can be used as identifiers, but that have special meaning in certain contexts
public static final String[] syntacticKeywordsAS3= {"each", "get", "set", "namespace", "include", "dynamic", "final", "native", "override", "static"};
public static final String[] syntacticKeywordsAS3 = {"each", "get", "set", "namespace", "include", "dynamic", "final", "native", "override", "static"};
public static boolean isReservedWord(String s,boolean as3) {
public static boolean isReservedWord(String s, boolean as3) {
if (s == null) {
return false;
}
String reservedWords[] = as3?reservedWordsAS3:reservedWordsAS2;
String reservedWords[] = as3 ? reservedWordsAS3 : reservedWordsAS2;
for (String rw : reservedWords) {
if (rw.equals(s.trim())) {
return true;
@@ -84,8 +86,8 @@ public class IdentifiersDeobfuscation {
}
return false;
}
private String fooString(boolean as3,HashMap<String, String> deobfuscated, String orig, boolean firstUppercase, int rndSize) {
private String fooString(boolean as3, HashMap<String, String> deobfuscated, String orig, boolean firstUppercase, int rndSize) {
boolean exists;
String ret;
loopfoo:
@@ -110,7 +112,7 @@ public class IdentifiersDeobfuscation {
rndSize += 1;
continue loopfoo;
}
if (isReservedWord(ret,as3)) {
if (isReservedWord(ret, as3)) {
exists = true;
rndSize += 1;
continue;
@@ -124,16 +126,16 @@ public class IdentifiersDeobfuscation {
return ret;
}
public void deobfuscateInstanceNames(boolean as3,HashMap<String, String> namesMap, RenameType renameType, List<Tag> tags, Map<String, String> selected) {
public void deobfuscateInstanceNames(boolean as3, HashMap<String, String> namesMap, RenameType renameType, List<Tag> tags, Map<String, String> selected) {
for (Tag t : tags) {
if (t instanceof DefineSpriteTag) {
deobfuscateInstanceNames(as3,namesMap, renameType, ((DefineSpriteTag) t).subTags, selected);
deobfuscateInstanceNames(as3, namesMap, renameType, ((DefineSpriteTag) t).subTags, selected);
}
if (t instanceof PlaceObjectTypeTag) {
PlaceObjectTypeTag po = (PlaceObjectTypeTag) t;
String name = po.getInstanceName();
if (name != null) {
String changedName = deobfuscateName(as3,name, false, "instance", namesMap, renameType, selected);
String changedName = deobfuscateName(as3, name, false, "instance", namesMap, renameType, selected);
if (changedName != null) {
po.setInstanceName(changedName);
((Tag) po).setModified(true);
@@ -141,7 +143,7 @@ public class IdentifiersDeobfuscation {
}
String className = po.getClassName();
if (className != null) {
String changedClassName = deobfuscateNameWithPackage(as3,className, namesMap, renameType, selected);
String changedClassName = deobfuscateNameWithPackage(as3, className, namesMap, renameType, selected);
if (changedClassName != null) {
po.setClassName(changedClassName);
((Tag) po).setModified(true);
@@ -151,7 +153,7 @@ public class IdentifiersDeobfuscation {
}
}
public String deobfuscatePackage(boolean as3,String pkg, HashMap<String, String> namesMap, RenameType renameType, Map<String, String> selected) {
public String deobfuscatePackage(boolean as3, String pkg, HashMap<String, String> namesMap, RenameType renameType, Map<String, String> selected) {
if (namesMap.containsKey(pkg)) {
return namesMap.get(pkg);
}
@@ -167,7 +169,7 @@ public class IdentifiersDeobfuscation {
if (p > 0) {
ret += ".";
}
String partChanged = deobfuscateName(as3,parts[p], false, "package", namesMap, renameType, selected);
String partChanged = deobfuscateName(as3, parts[p], false, "package", namesMap, renameType, selected);
if (partChanged != null) {
ret += partChanged;
isChanged = true;
@@ -182,7 +184,7 @@ public class IdentifiersDeobfuscation {
return null;
}
public String deobfuscateNameWithPackage(boolean as3,String n, HashMap<String, String> namesMap, RenameType renameType, Map<String, String> selected) {
public String deobfuscateNameWithPackage(boolean as3, String n, HashMap<String, String> namesMap, RenameType renameType, Map<String, String> selected) {
String pkg = null;
String name = "";
if (n.contains(".")) {
@@ -193,13 +195,13 @@ public class IdentifiersDeobfuscation {
}
boolean changed = false;
if ((pkg != null) && (!pkg.isEmpty())) {
String changedPkg = deobfuscatePackage(as3,pkg, namesMap, renameType, selected);
String changedPkg = deobfuscatePackage(as3, pkg, namesMap, renameType, selected);
if (changedPkg != null) {
changed = true;
pkg = changedPkg;
}
}
String changedName = deobfuscateName(as3,name, true, "class", namesMap, renameType, selected);
String changedName = deobfuscateName(as3, name, true, "class", namesMap, renameType, selected);
if (changedName != null) {
changed = true;
name = changedName;
@@ -216,38 +218,29 @@ public class IdentifiersDeobfuscation {
return null;
}
public static boolean isValidName(boolean as3,String s, String... exceptions) {
boolean isValid = true;
public static boolean isValidName(boolean as3, String s, String... exceptions) {
for (String e : exceptions) {
if (e.equals(s)) {
return true;
}
}
if (isReservedWord(s,as3)) {
isValid = false;
if (isReservedWord(s, as3)) {
return false;
}
if (isValid) {
for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) > 127) {
isValid = false;
break;
}
}
//simple fast test
if (s.matches("^[a-zA-Z_\\$][a-zA-Z0-9_\\$]*$")) {
return true;
}
if (isValid) {
Pattern pat = Pattern.compile("^[" + Pattern.quote(VALID_FIRST_CHARACTERS) + "]" + "[" + Pattern.quote(VALID_FIRST_CHARACTERS + VALID_NEXT_CHARACTERS) + "]*$");
if (!pat.matcher(s).matches()) {
isValid = false;
}
//unicode test
if (IDENTIFIER_PATTERN.matcher(s).matches()) {
return true;
}
return isValid;
return false;
}
public String deobfuscateName(boolean as3,String s, boolean firstUppercase, String usageType, HashMap<String, String> namesMap, RenameType renameType, Map<String, String> selected) {
public String deobfuscateName(boolean as3, String s, boolean firstUppercase, String usageType, HashMap<String, String> namesMap, RenameType renameType, Map<String, String> selected) {
boolean isValid = true;
if (usageType == null) {
usageType = "name";
@@ -259,7 +252,7 @@ public class IdentifiersDeobfuscation {
}
}
isValid = isValidName(as3,s);
isValid = isValidName(as3, s);
if (!isValid) {
if (namesMap.containsKey(s)) {
return namesMap.get(s);
@@ -281,7 +274,7 @@ public class IdentifiersDeobfuscation {
} while (found);
typeCounts.put(usageType, cnt);
} else if (renameType == RenameType.RANDOMWORD) {
ret = fooString(as3,namesMap, s, firstUppercase, DEFAULT_FOO_SIZE);
ret = fooString(as3, namesMap, s, firstUppercase, DEFAULT_FOO_SIZE);
}
namesMap.put(s, ret);
return ret;
@@ -320,7 +313,7 @@ public class IdentifiersDeobfuscation {
return ret;
}
public static String printNamespace(boolean as3,String pkg, String... validNameExceptions) {
public static String printNamespace(boolean as3, String pkg, String... validNameExceptions) {
if (nameCache.containsKey(pkg)) {
return nameCache.get(pkg);
}
@@ -339,7 +332,7 @@ public class IdentifiersDeobfuscation {
if (i > 0) {
ret += ".";
}
ret += printIdentifier(as3,parts[i], validNameExceptions);
ret += printIdentifier(as3, parts[i], validNameExceptions);
}
nameCache.put(pkg, ret);
return ret;