1 19 20 package jode.obfuscator; 21 22 import java.io.BufferedReader ; 23 import java.io.IOException ; 24 import java.io.Reader ; 25 26 import java.util.Collection ; 27 import java.util.LinkedList ; 28 29 public class ScriptParser { 30 static int NO_TOKEN = -2; 31 static int EOF_TOKEN = -1; 32 static int STRING_TOKEN = 0; 33 static int NEW_TOKEN = 1; 34 static int EQUALS_TOKEN = 2; 35 static int COMMA_TOKEN = 3; 36 static int OPENBRACE_TOKEN = 4; 37 static int CLOSEBRACE_TOKEN = 5; 38 static int IDENTIFIER_TOKEN = 6; 39 static int NUMBER_TOKEN = 7; 40 Scanner scanner; 41 42 class Scanner { 43 BufferedReader input; 44 String value; 45 String line; 46 int column; 47 int linenr; 48 int pushback = NO_TOKEN; 49 50 public Scanner(Reader i) { 51 input = new BufferedReader (i); 52 } 53 54 public void readString() throws ParseException { 55 StringBuffer val = new StringBuffer (); 56 while (column < line.length()) { 57 char c = line.charAt(column++); 58 if (c == '"') { 59 value = val.toString(); 60 return; 61 } 62 if (c == '\\') { 63 c = line.charAt(column++); 64 switch (c) { 65 case 'n': 66 val.append('\n'); 67 break; 68 case 't': 69 val.append('\t'); 70 break; 71 case 'r': 72 val.append('\r'); 73 break; 74 case 'u': 75 if (column+4 <= line.length()) { 76 try { 77 char uni = (char) Integer.parseInt 78 (line.substring(column, column+4), 16); 79 column += 4; 80 val.append(uni); 81 } catch (NumberFormatException ex) { 82 throw new ParseException 83 (linenr, 84 "Invalid unicode escape character"); 85 } 86 } else 87 throw new ParseException 88 (linenr, 89 "Invalid unicode escape character"); 90 break; 91 default: 92 val.append(c); 93 } 94 } else 95 val.append(c); 96 } 97 throw new ParseException(linenr, 98 "String spans over multiple lines"); 99 } 100 public void readIdentifier() { 101 int start = column-1; 102 while (column < line.length() 103 && Character.isUnicodeIdentifierPart(line.charAt(column))) 104 column++; 105 value = line.substring(start, column); 106 } 107 108 public void readNumber() { 109 boolean hex = false; 110 int start = column-1; 111 112 if (line.charAt(start) == '0' && line.charAt(column) == 'x') { 113 column++; 114 hex = true; 115 } 116 while (column < line.length()) { 117 char c = line.charAt(column); 118 if (!Character.isDigit(c)) { 119 if (!hex) 120 break; 121 if ((c < 'A' || c > 'F') && (c < 'a' || c > 'f')) 122 break; 123 } 124 column++; 125 } 126 value = line.substring(start, column); 127 } 128 129 public void pushbackToken(int token) { 130 if (pushback != NO_TOKEN) 131 throw new IllegalStateException 132 ("Can only handle one pushback"); 133 pushback = token; 134 } 135 136 public int getToken() throws ParseException, IOException { 137 if (pushback != NO_TOKEN) { 138 int result = pushback; 139 pushback = NO_TOKEN; 140 return result; 141 } 142 value = null; 143 while (true) { 144 if (line == null) { 145 line = input.readLine(); 146 if (line == null) 147 return EOF_TOKEN; 148 linenr++; 149 column = 0; 150 } 151 while (column < line.length()) { 152 char c = line.charAt(column++); 153 if (Character.isWhitespace(c)) 154 continue; 155 if (c == '#') 156 break; 158 if (c == '=') 159 return EQUALS_TOKEN; 160 if (c == ',') 161 return COMMA_TOKEN; 162 if (c == '{') 163 return OPENBRACE_TOKEN; 164 if (c == '}') 165 return CLOSEBRACE_TOKEN; 166 if (c == '"') { 167 readString(); 168 return STRING_TOKEN; 169 } 170 if (Character.isDigit(c) || c == '+' || c == '-') { 171 readNumber(); 172 return NUMBER_TOKEN; 173 } 174 if (Character.isUnicodeIdentifierStart(c)) { 175 readIdentifier(); 176 if (value.equals("new")) 177 return NEW_TOKEN; 178 return IDENTIFIER_TOKEN; 179 } 180 throw new ParseException 181 (linenr, "Illegal character `"+c+"'"); 182 } 183 line = null; 184 } 185 } 186 187 public String getValue() { 188 return value; 189 } 190 191 public int getLineNr() { 192 return linenr; 193 } 194 } 195 196 public ScriptParser(Reader reader) { 197 this.scanner = new Scanner(reader); 198 } 199 200 public Object parseClass() throws ParseException, IOException { 201 int linenr = scanner.getLineNr(); 202 int token = scanner.getToken(); 203 if (token != IDENTIFIER_TOKEN) 204 throw new ParseException(linenr, "Class name expected"); 205 Object instance; 206 try { 207 Class clazz = Class.forName("jode.obfuscator.modules." 208 +scanner.getValue()); 209 instance = clazz.newInstance(); 210 } catch (ClassNotFoundException ex) { 211 throw new ParseException(scanner.getLineNr(), 212 "Class `"+scanner.getValue() 213 +"' not found"); 214 } catch (Exception ex) { 215 throw new ParseException(scanner.getLineNr(), 216 "Class `"+scanner.getValue() 217 +"' not valid: "+ex.getMessage()); 218 } 219 220 token = scanner.getToken(); 221 if (token == OPENBRACE_TOKEN) { 222 if (!(instance instanceof OptionHandler)) 223 throw new ParseException 224 (scanner.getLineNr(), 225 "Class `"+instance.getClass().getName() 226 +"' doesn't handle options."); 227 parseOptions((OptionHandler) instance); 228 if (scanner.getToken() != CLOSEBRACE_TOKEN) 229 throw new ParseException(scanner.getLineNr(), "`}' expected"); 230 } else 231 scanner.pushbackToken(token); 232 return instance; 233 } 234 235 public void parseOptions(OptionHandler optionHandler) 236 throws ParseException, IOException 237 { 238 int token = scanner.getToken(); 239 while (true) { 240 if (token == EOF_TOKEN || token == CLOSEBRACE_TOKEN) { 241 scanner.pushbackToken(token); 242 return; 243 } 244 if (token != IDENTIFIER_TOKEN) 245 throw new ParseException(scanner.getLineNr(), 246 "identifier expected"); 247 String ident = scanner.getValue(); 248 if (scanner.getToken() != EQUALS_TOKEN) 249 throw new ParseException(scanner.getLineNr(), 250 "equal sign expected"); 251 252 int linenr = scanner.getLineNr(); 253 Collection values = new LinkedList (); 254 do { 255 token = scanner.getToken(); 256 if (token == NEW_TOKEN) { 257 values.add(parseClass()); 258 } else if (token == STRING_TOKEN) { 259 values.add(scanner.getValue()); 260 } else if (token == NUMBER_TOKEN) { 261 values.add(new Integer (scanner.getValue())); 262 } 263 token = scanner.getToken(); 264 } while (token == COMMA_TOKEN); 265 try { 266 optionHandler.setOption(ident, values); 267 } catch (IllegalArgumentException ex) { 268 throw new ParseException(linenr, 269 optionHandler.getClass().getName() 270 +": "+ex.getMessage()); 271 } catch (RuntimeException ex) { 272 throw new ParseException(linenr, 273 optionHandler.getClass().getName() 274 +": Illegal value: " 275 +ex.getClass().getName() 276 +": "+ex.getMessage()); 277 } 278 } 279 } 280 } 281 | Popular Tags |