Mirror of the JODE repository
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
jode/jode/jode/obfuscator/ScriptParser.java

282 lines
7.3 KiB

/* ScriptParser Copyright (C) 1999 Jochen Hoenicke.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id$
*/
package jode.obfuscator;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.Reader;
///#def COLLECTIONS java.util
import java.util.Collection;
import java.util.LinkedList;
///#enddef
public class ScriptParser {
static int NO_TOKEN = -2;
static int EOF_TOKEN = -1;
static int STRING_TOKEN = 0;
static int NEW_TOKEN = 1;
static int EQUALS_TOKEN = 2;
static int COMMA_TOKEN = 3;
static int OPENBRACE_TOKEN = 4;
static int CLOSEBRACE_TOKEN = 5;
static int IDENTIFIER_TOKEN = 6;
static int NUMBER_TOKEN = 7;
Scanner scanner;
class Scanner {
BufferedReader input;
String value;
String line;
int column;
int linenr;
int pushback = NO_TOKEN;
public Scanner(Reader i) {
input = new BufferedReader(i);
}
public void readString() throws ParseException {
StringBuffer val = new StringBuffer();
while (column < line.length()) {
char c = line.charAt(column++);
if (c == '"') {
value = val.toString();
return;
}
if (c == '\\') {
c = line.charAt(column++);
switch (c) {
case 'n':
val.append('\n');
break;
case 't':
val.append('\t');
break;
case 'r':
val.append('\r');
break;
case 'u':
if (column+4 <= line.length()) {
try {
char uni = (char) Integer.parseInt
(line.substring(column, column+4), 16);
column += 4;
val.append(uni);
} catch (NumberFormatException ex) {
throw new ParseException
(linenr,
"Invalid unicode escape character");
}
} else
throw new ParseException
(linenr,
"Invalid unicode escape character");
break;
default:
val.append(c);
}
} else
val.append(c);
}
throw new ParseException(linenr,
"String spans over multiple lines");
}
public void readIdentifier() {
int start = column-1;
while (column < line.length()
&& Character.isUnicodeIdentifierPart(line.charAt(column)))
column++;
value = line.substring(start, column);
}
public void readNumber() {
boolean hex = false;
int start = column-1;
/* special case for hex numbers */
if (line.charAt(start) == '0' && line.charAt(column) == 'x') {
column++;
hex = true;
}
while (column < line.length()) {
char c = line.charAt(column);
if (!Character.isDigit(c)) {
if (!hex)
break;
if ((c < 'A' || c > 'F') && (c < 'a' || c > 'f'))
break;
}
column++;
}
value = line.substring(start, column);
}
public void pushbackToken(int token) {
if (pushback != NO_TOKEN)
throw new IllegalStateException
("Can only handle one pushback");
pushback = token;
}
public int getToken() throws ParseException, IOException {
if (pushback != NO_TOKEN) {
int result = pushback;
pushback = NO_TOKEN;
return result;
}
value = null;
while (true) {
if (line == null) {
line = input.readLine();
if (line == null)
return EOF_TOKEN;
linenr++;
column = 0;
}
while (column < line.length()) {
char c = line.charAt(column++);
if (Character.isWhitespace(c))
continue;
if (c == '#')
// this is a comment, skip this line
break;
if (c == '=')
return EQUALS_TOKEN;
if (c == ',')
return COMMA_TOKEN;
if (c == '{')
return OPENBRACE_TOKEN;
if (c == '}')
return CLOSEBRACE_TOKEN;
if (c == '"') {
readString();
return STRING_TOKEN;
}
if (Character.isDigit(c) || c == '+' || c == '-') {
readNumber();
return NUMBER_TOKEN;
}
if (Character.isUnicodeIdentifierStart(c)) {
readIdentifier();
if (value.equals("new"))
return NEW_TOKEN;
return IDENTIFIER_TOKEN;
}
throw new ParseException
(linenr, "Illegal character `"+c+"'");
}
line = null;
}
}
public String getValue() {
return value;
}
public int getLineNr() {
return linenr;
}
}
public ScriptParser(Reader reader) {
this.scanner = new Scanner(reader);
}
public Object parseClass() throws ParseException, IOException {
int linenr = scanner.getLineNr();
int token = scanner.getToken();
if (token != IDENTIFIER_TOKEN)
throw new ParseException(linenr, "Class name expected");
Object instance;
try {
Class clazz = Class.forName("jode.obfuscator.modules."
+scanner.getValue());
instance = clazz.newInstance();
} catch (ClassNotFoundException ex) {
throw new ParseException(scanner.getLineNr(),
"Class `"+scanner.getValue()
+"' not found");
} catch (Exception ex) {
throw new ParseException(scanner.getLineNr(),
"Class `"+scanner.getValue()
+"' not valid: "+ex.getMessage());
}
token = scanner.getToken();
if (token == OPENBRACE_TOKEN) {
if (!(instance instanceof OptionHandler))
throw new ParseException
(scanner.getLineNr(),
"Class `"+instance.getClass().getName()
+"' doesn't handle options.");
parseOptions((OptionHandler) instance);
if (scanner.getToken() != CLOSEBRACE_TOKEN)
throw new ParseException(scanner.getLineNr(), "`}' expected");
} else
scanner.pushbackToken(token);
return instance;
}
public void parseOptions(OptionHandler optionHandler)
throws ParseException, IOException
{
int token = scanner.getToken();
while (true) {
if (token == EOF_TOKEN || token == CLOSEBRACE_TOKEN) {
scanner.pushbackToken(token);
return;
}
if (token != IDENTIFIER_TOKEN)
throw new ParseException(scanner.getLineNr(),
"identifier expected");
String ident = scanner.getValue();
if (scanner.getToken() != EQUALS_TOKEN)
throw new ParseException(scanner.getLineNr(),
"equal sign expected");
int linenr = scanner.getLineNr();
Collection values = new LinkedList();
do {
token = scanner.getToken();
if (token == NEW_TOKEN) {
values.add(parseClass());
} else if (token == STRING_TOKEN) {
values.add(scanner.getValue());
} else if (token == NUMBER_TOKEN) {
values.add(new Integer(scanner.getValue()));
}
token = scanner.getToken();
} while (token == COMMA_TOKEN);
try {
optionHandler.setOption(ident, values);
} catch (IllegalArgumentException ex) {
throw new ParseException(linenr,
optionHandler.getClass().getName()
+": "+ex.getMessage());
} catch (RuntimeException ex) {
throw new ParseException(linenr,
optionHandler.getClass().getName()
+": Illegal value: "
+ex.getClass().getName()
+": "+ex.getMessage());
}
}
}
}