1730 lines
58 KiB
Diff
1730 lines
58 KiB
Diff
|
Index: src/org/mozilla/javascript/BaseFunction.java
|
||
|
===================================================================
|
||
|
--- src/org/mozilla/javascript/BaseFunction.java.orig 2009-11-16 15:55:50.222561412 +0100
|
||
|
+++ src/org/mozilla/javascript/BaseFunction.java 2009-11-16 15:56:40.070560339 +0100
|
||
|
@@ -401,6 +401,28 @@
|
||
|
return sb.toString();
|
||
|
}
|
||
|
|
||
|
+ String compress(int indent, int flags)
|
||
|
+ {
|
||
|
+ StringBuffer sb = new StringBuffer();
|
||
|
+ String FuncName = null;
|
||
|
+ boolean justbody = (0 != (flags & Decompiler.ONLY_BODY_FLAG));
|
||
|
+ if (!justbody) {
|
||
|
+ sb.append("function");
|
||
|
+ FuncName = getFunctionName();
|
||
|
+ if(FuncName.length()>0){
|
||
|
+ sb.append(" "+FuncName);
|
||
|
+ }
|
||
|
+ sb.append("(){");
|
||
|
+ }
|
||
|
+ sb.append("[native code, arity=");
|
||
|
+ sb.append(getArity());
|
||
|
+ sb.append("]");
|
||
|
+ if (!justbody) {
|
||
|
+ sb.append("}");
|
||
|
+ }
|
||
|
+ return sb.toString();
|
||
|
+ }
|
||
|
+
|
||
|
public int getArity() { return 0; }
|
||
|
|
||
|
public int getLength() { return 0; }
|
||
|
Index: src/org/mozilla/javascript/Context.java
|
||
|
===================================================================
|
||
|
--- src/org/mozilla/javascript/Context.java.orig 2009-11-16 15:55:50.222561412 +0100
|
||
|
+++ src/org/mozilla/javascript/Context.java 2009-11-16 15:56:40.070560339 +0100
|
||
|
@@ -1241,6 +1241,33 @@
|
||
|
this, scope, args);
|
||
|
}
|
||
|
|
||
|
+ public final String decompileReader(Scriptable scope, Reader in,
|
||
|
+ String sourceName, int lineno,
|
||
|
+ Object securityDomain)
|
||
|
+ throws IOException
|
||
|
+ {
|
||
|
+ Script script = compileReader(scope, in, sourceName, lineno,
|
||
|
+ securityDomain);
|
||
|
+ if (script != null) {
|
||
|
+ // System.err.println(script);
|
||
|
+ return decompileScript(script, 0);
|
||
|
+ } else {
|
||
|
+ return null;
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ public final String compressReader(Scriptable scope, Script script, String source,
|
||
|
+ String sourceName, int lineno, Object securityDomain){
|
||
|
+
|
||
|
+ if (script != null) {
|
||
|
+ // System.err.println(script);
|
||
|
+ return compressScript(script, 0, source,lineno);
|
||
|
+ } else {
|
||
|
+ return null;
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+
|
||
|
/**
|
||
|
* Check whether a string is ready to be compiled.
|
||
|
* <p>
|
||
|
@@ -1424,6 +1451,27 @@
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
+ * Compress the script.
|
||
|
+ * <p>
|
||
|
+ * Compressed script is returned.
|
||
|
+ *
|
||
|
+ * @param script the script object
|
||
|
+ * @param indent the number of spaces to indent the result
|
||
|
+ * @return a string representing the script source
|
||
|
+ */
|
||
|
+ public final String compressScript(Script script, int indent, String source,int lineno)
|
||
|
+ {
|
||
|
+ NativeFunction scriptImpl = (NativeFunction) script;
|
||
|
+
|
||
|
+ CompilerEnvirons compilerEnv = new CompilerEnvirons();
|
||
|
+
|
||
|
+ Parser parser = new Parser(compilerEnv, compilerEnv.getErrorReporter());
|
||
|
+
|
||
|
+ ScriptOrFnNode tree = parser.parse(source, null, lineno);
|
||
|
+
|
||
|
+ return scriptImpl.compress( tree,indent, 0);
|
||
|
+ }
|
||
|
+ /**
|
||
|
* Decompile a JavaScript Function.
|
||
|
* <p>
|
||
|
* Decompiles a previously compiled JavaScript function object to
|
||
|
@@ -2358,7 +2406,6 @@
|
||
|
sourceReader = null;
|
||
|
}
|
||
|
}
|
||
|
-
|
||
|
Parser p = new Parser(compilerEnv, compilationErrorReporter);
|
||
|
if (returnFunction) {
|
||
|
p.calledByCompileFunction = true;
|
||
|
@@ -2369,6 +2416,7 @@
|
||
|
} else {
|
||
|
tree = p.parse(sourceReader, sourceName, lineno);
|
||
|
}
|
||
|
+
|
||
|
if (returnFunction) {
|
||
|
if (!(tree.getFunctionCount() == 1
|
||
|
&& tree.getFirstChild() != null
|
||
|
Index: src/org/mozilla/javascript/Decompiler.java
|
||
|
===================================================================
|
||
|
--- src/org/mozilla/javascript/Decompiler.java.orig 2009-11-16 15:55:50.222561412 +0100
|
||
|
+++ src/org/mozilla/javascript/Decompiler.java 2009-11-16 15:56:40.082560417 +0100
|
||
|
@@ -41,6 +41,11 @@
|
||
|
|
||
|
package org.mozilla.javascript;
|
||
|
|
||
|
+import java.util.ArrayList;
|
||
|
+import java.util.Arrays;
|
||
|
+import java.util.HashMap;
|
||
|
+import java.util.List;
|
||
|
+
|
||
|
/**
|
||
|
* The following class save decompilation information about the source.
|
||
|
* Source information is returned from the parser as a String
|
||
|
@@ -74,6 +79,264 @@
|
||
|
* the final constant pool entry from information available at parse
|
||
|
* time.
|
||
|
*/
|
||
|
+
|
||
|
+class TokenMapper {
|
||
|
+ private ArrayList functionBracePositions = new ArrayList();
|
||
|
+
|
||
|
+ /**
|
||
|
+ * Map of all replaced tokens
|
||
|
+ */
|
||
|
+ private ArrayList replacedTokens = new ArrayList();
|
||
|
+
|
||
|
+ /**
|
||
|
+ * Collection of Function nodes
|
||
|
+ */
|
||
|
+ private static ObjArray funcObjects = new ObjArray();
|
||
|
+
|
||
|
+ /**
|
||
|
+ * Map of each Function node and all the variables in its current function
|
||
|
+ * scope, other variables found while traversing the prototype chain and
|
||
|
+ * variables found in the top-level scope.
|
||
|
+ */
|
||
|
+ private static ArrayList functionVarMappings = new ArrayList();
|
||
|
+
|
||
|
+ public int functionNum = 0;
|
||
|
+
|
||
|
+ private int parentScope = 0;
|
||
|
+
|
||
|
+ private int lastTokenCount = 0;
|
||
|
+
|
||
|
+ /**
|
||
|
+ * Generate new compressed tokens
|
||
|
+ * <p>
|
||
|
+ *
|
||
|
+ * @param token
|
||
|
+ * value of the string token
|
||
|
+ * @param hasNewMapping
|
||
|
+ * boolean value indicating a new variable binding
|
||
|
+ * @return compressed token
|
||
|
+ */
|
||
|
+ private String getMappedToken(String token, boolean hasNewMapping) {
|
||
|
+ String newToken = null;
|
||
|
+ HashMap tokens = null;
|
||
|
+ String blank = new String("");
|
||
|
+ int localScope = functionBracePositions.size() - 1;
|
||
|
+
|
||
|
+ String oldToken = getPreviousTokenMapping(token, hasNewMapping);
|
||
|
+
|
||
|
+ if (!oldToken.equalsIgnoreCase(blank)) {
|
||
|
+ return oldToken;
|
||
|
+ } else if ((hasNewMapping || isInScopeChain(token))) {
|
||
|
+ lastTokenCount++;
|
||
|
+ newToken = new String("_" + Integer.toHexString(lastTokenCount));
|
||
|
+ if (newToken.length() >= token.length()) {
|
||
|
+ newToken = token;
|
||
|
+ }
|
||
|
+ if (hasNewMapping) {
|
||
|
+ tokens = (HashMap) replacedTokens.get(localScope);
|
||
|
+ } else {
|
||
|
+ tokens = (HashMap) replacedTokens.get(parentScope);
|
||
|
+ }
|
||
|
+
|
||
|
+ tokens.put(token, newToken);
|
||
|
+ return newToken;
|
||
|
+ }
|
||
|
+ return token;
|
||
|
+ }
|
||
|
+
|
||
|
+ /**
|
||
|
+ * Checks for variable names in prototype chain
|
||
|
+ * <p>
|
||
|
+ *
|
||
|
+ * @param token
|
||
|
+ * value of the string token
|
||
|
+ * @return boolean value indicating if the token is present in the chained
|
||
|
+ * scope
|
||
|
+ */
|
||
|
+ private boolean isInScopeChain(String token) {
|
||
|
+ int scope = functionBracePositions.size();
|
||
|
+ HashMap chainedScopeVars = (HashMap) functionVarMappings
|
||
|
+ .get(functionNum);
|
||
|
+ if (!chainedScopeVars.isEmpty()) {
|
||
|
+ for (int i = scope; i > 0; i--) {
|
||
|
+ if (chainedScopeVars.containsKey(new Integer(i))) {
|
||
|
+ parentScope = i - 1;
|
||
|
+ List temp = Arrays.asList((String[]) chainedScopeVars
|
||
|
+ .get(new Integer(i)));
|
||
|
+ if (temp.indexOf(token) != -1) {
|
||
|
+ return true;
|
||
|
+ }
|
||
|
+ }
|
||
|
+ }
|
||
|
+ }
|
||
|
+ return false;
|
||
|
+ }
|
||
|
+
|
||
|
+ /**
|
||
|
+ * Checks previous token mapping
|
||
|
+ * <p>
|
||
|
+ *
|
||
|
+ * @param token
|
||
|
+ * value of the string token
|
||
|
+ * @param hasNewMapping
|
||
|
+ * boolean value indicating a new variable binding
|
||
|
+ * @return string value of the previous token or blank string
|
||
|
+ */
|
||
|
+ private String getPreviousTokenMapping(String token, boolean hasNewMapping) {
|
||
|
+ String result = new String("");
|
||
|
+ int scope = replacedTokens.size() - 1;
|
||
|
+
|
||
|
+ if (scope < 0) {
|
||
|
+ return result;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (hasNewMapping) {
|
||
|
+ HashMap tokens = (HashMap) (replacedTokens.get(scope));
|
||
|
+ if (tokens.containsKey(token)) {
|
||
|
+ result = (String) tokens.get(token);
|
||
|
+ return result;
|
||
|
+ }
|
||
|
+ } else {
|
||
|
+ for (int i = scope; i > -1; i--) {
|
||
|
+ HashMap tokens = (HashMap) (replacedTokens.get(i));
|
||
|
+ if (tokens.containsKey(token)) {
|
||
|
+ result = (String) tokens.get(token);
|
||
|
+ return result;
|
||
|
+ }
|
||
|
+ }
|
||
|
+ }
|
||
|
+ return result;
|
||
|
+ }
|
||
|
+
|
||
|
+ /**
|
||
|
+ * Generate mappings for each Function node and parameters and variables
|
||
|
+ * names associated with it.
|
||
|
+ * <p>
|
||
|
+ *
|
||
|
+ * @param parseTree
|
||
|
+ * Mapping for each function node and corresponding parameters &
|
||
|
+ * variables names
|
||
|
+ */
|
||
|
+ private void collectFunctionMappings(ScriptOrFnNode parseTree) {
|
||
|
+ int level = -1;
|
||
|
+ collectFuncNodes(parseTree, level);
|
||
|
+ }
|
||
|
+
|
||
|
+ /**
|
||
|
+ * Recursive method to traverse all Function nodes
|
||
|
+ * <p>
|
||
|
+ *
|
||
|
+ * @param parseTree
|
||
|
+ * Mapping for each function node and corresponding parameters &
|
||
|
+ * variables names
|
||
|
+ * @param level
|
||
|
+ * scoping level
|
||
|
+ */
|
||
|
+ private static void collectFuncNodes(ScriptOrFnNode parseTree, int level) {
|
||
|
+ level++;
|
||
|
+ functionVarMappings.add(new HashMap());
|
||
|
+
|
||
|
+ HashMap bindingNames = (HashMap) functionVarMappings
|
||
|
+ .get(functionVarMappings.size() - 1);
|
||
|
+ bindingNames.put(new Integer(level), parseTree.getParamAndVarNames());
|
||
|
+ funcObjects.add(parseTree);
|
||
|
+
|
||
|
+ int nestedCount = parseTree.getFunctionCount();
|
||
|
+ for (int i = 0; i != nestedCount; ++i) {
|
||
|
+ collectFuncNodes(parseTree.getFunctionNode(i), level);
|
||
|
+ bindingNames = (HashMap) functionVarMappings
|
||
|
+ .get(functionVarMappings.size() - 1);
|
||
|
+ bindingNames.put(new Integer(level), parseTree
|
||
|
+ .getParamAndVarNames());
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ /**
|
||
|
+ * Compress the script
|
||
|
+ * <p>
|
||
|
+ *
|
||
|
+ * @param encodedSource
|
||
|
+ * encoded source string
|
||
|
+ * @param offset
|
||
|
+ * position within the encoded source
|
||
|
+ * @param asQuotedString
|
||
|
+ * boolean value indicating a quoted string
|
||
|
+ * @param sb
|
||
|
+ * String buffer reference
|
||
|
+ * @param prevToken
|
||
|
+ * Previous token in encoded source
|
||
|
+ * @param inArgsList
|
||
|
+ * boolean value indicating position inside arguments list
|
||
|
+ * @param currentLevel
|
||
|
+ * embeded function level
|
||
|
+ * @param parseTree
|
||
|
+ * Mapping of each function node and corresponding parameters &
|
||
|
+ * variables names
|
||
|
+ * @return compressed script
|
||
|
+ */
|
||
|
+ public int sourceCompress(String encodedSource, int offset,
|
||
|
+ boolean asQuotedString, StringBuffer sb, int prevToken,
|
||
|
+ boolean inArgsList, int currentLevel, ScriptOrFnNode parseTree) {
|
||
|
+
|
||
|
+ boolean hasNewMapping = false;
|
||
|
+
|
||
|
+ if (functionVarMappings.isEmpty())
|
||
|
+ collectFunctionMappings(parseTree);
|
||
|
+
|
||
|
+ int length = encodedSource.charAt(offset);
|
||
|
+ ++offset;
|
||
|
+ if ((0x8000 & length) != 0) {
|
||
|
+ length = ((0x7FFF & length) << 16) | encodedSource.charAt(offset);
|
||
|
+ ++offset;
|
||
|
+ }
|
||
|
+ if (sb != null) {
|
||
|
+ String str = encodedSource.substring(offset, offset + length);
|
||
|
+ String sourceStr = new String(str);
|
||
|
+ if ((prevToken == Token.VAR) || (inArgsList)) {
|
||
|
+ hasNewMapping = true;
|
||
|
+ }
|
||
|
+ if (((functionBracePositions.size() > 0) && (currentLevel >= (((Integer) functionBracePositions
|
||
|
+ .get(functionBracePositions.size() - 1)).intValue())))
|
||
|
+ || (inArgsList)) {
|
||
|
+ if (prevToken != Token.DOT) {
|
||
|
+ str = this.getMappedToken(str, hasNewMapping);
|
||
|
+ }
|
||
|
+ }
|
||
|
+ if ((!inArgsList) && (asQuotedString)) {
|
||
|
+ if ((prevToken == Token.LC) || (prevToken == Token.COMMA)) {
|
||
|
+ str = sourceStr;
|
||
|
+ }
|
||
|
+ }
|
||
|
+ if (!asQuotedString) {
|
||
|
+ sb.append(str);
|
||
|
+ } else {
|
||
|
+ sb.append('"');
|
||
|
+ sb.append(ScriptRuntime.escapeString(str));
|
||
|
+ sb.append('"');
|
||
|
+ }
|
||
|
+ }
|
||
|
+ return offset + length;
|
||
|
+ }
|
||
|
+
|
||
|
+ public void enterNestingLevel(int braceNesting) {
|
||
|
+ functionBracePositions.add(new Integer(braceNesting + 1));
|
||
|
+ replacedTokens.add(new HashMap());
|
||
|
+ }
|
||
|
+
|
||
|
+ public void leaveNestingLevel(int braceNesting) {
|
||
|
+ Integer bn = new Integer(braceNesting);
|
||
|
+
|
||
|
+ if ((functionBracePositions.contains(bn))
|
||
|
+ && (replacedTokens.size() > 0)) {
|
||
|
+ // remove our mappings now!
|
||
|
+ int scopedSize = replacedTokens.size();
|
||
|
+ replacedTokens.remove(scopedSize - 1);
|
||
|
+ functionBracePositions.remove(bn);
|
||
|
+ }
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
+
|
||
|
public class Decompiler
|
||
|
{
|
||
|
/**
|
||
|
@@ -270,6 +533,512 @@
|
||
|
return new String(sourceBuffer, offset, sourceTop - offset);
|
||
|
}
|
||
|
|
||
|
+ private static TokenMapper tm = new TokenMapper();
|
||
|
+
|
||
|
+ /**
|
||
|
+ * Compress the script
|
||
|
+ * <p>
|
||
|
+ *
|
||
|
+ * @param encodedSource encoded source string
|
||
|
+ * @param flags Flags specifying format of decompilation output
|
||
|
+ * @param properties Decompilation properties
|
||
|
+ * @param parseTree Mapping for each function node and corresponding parameters & variables names
|
||
|
+ * @return compressed script
|
||
|
+ */
|
||
|
+ public static String compress(String encodedSource, int flags,
|
||
|
+ UintMap properties, ScriptOrFnNode parseTree){
|
||
|
+
|
||
|
+ int length = encodedSource.length();
|
||
|
+ if (length == 0) { return ""; }
|
||
|
+ int indent = properties.getInt(INITIAL_INDENT_PROP, 0);
|
||
|
+ if (indent < 0) throw new IllegalArgumentException();
|
||
|
+ int indentGap = properties.getInt(INDENT_GAP_PROP, 4);
|
||
|
+ if (indentGap < 0) throw new IllegalArgumentException();
|
||
|
+ int caseGap = properties.getInt(CASE_GAP_PROP, 2);
|
||
|
+ if (caseGap < 0) throw new IllegalArgumentException();
|
||
|
+ StringBuffer result = new StringBuffer();
|
||
|
+ boolean justFunctionBody = (0 != (flags & Decompiler.ONLY_BODY_FLAG));
|
||
|
+ boolean toSource = (0 != (flags & Decompiler.TO_SOURCE_FLAG));
|
||
|
+ // Spew tokens in source, for debugging.
|
||
|
+ // as TYPE number char
|
||
|
+ if (printSource) {
|
||
|
+ System.err.println("length:" + length);
|
||
|
+ for (int i = 0; i < length; ++i) {
|
||
|
+ // Note that tokenToName will fail unless Context.printTrees
|
||
|
+ // is true.
|
||
|
+ String tokenname = null;
|
||
|
+ if (Token.printNames) {
|
||
|
+ tokenname = Token.name(encodedSource.charAt(i));
|
||
|
+ }
|
||
|
+ if (tokenname == null) {
|
||
|
+ tokenname = "---";
|
||
|
+ }
|
||
|
+ String pad = tokenname.length() > 7
|
||
|
+ ? "\t"
|
||
|
+ : "\t\t";
|
||
|
+ System.err.println
|
||
|
+ (tokenname
|
||
|
+ + pad + (int)encodedSource.charAt(i)
|
||
|
+ + "\t'" + ScriptRuntime.escapeString
|
||
|
+ (encodedSource.substring(i, i+1))
|
||
|
+ + "'");
|
||
|
+ }
|
||
|
+ System.err.println();
|
||
|
+ }
|
||
|
+ int braceNesting = 0;
|
||
|
+ boolean afterFirstEOL = false;
|
||
|
+ int i = 0;
|
||
|
+ int prevToken = 0;
|
||
|
+ boolean primeFunctionNesting = false;
|
||
|
+ boolean inArgsList = false;
|
||
|
+ boolean primeInArgsList = false;
|
||
|
+ int topFunctionType;
|
||
|
+ if (encodedSource.charAt(i) == Token.SCRIPT) {
|
||
|
+ ++i;
|
||
|
+ topFunctionType = -1;
|
||
|
+ } else {
|
||
|
+ topFunctionType = encodedSource.charAt(i + 1);
|
||
|
+ }
|
||
|
+ if (!toSource) {
|
||
|
+ // add an initial newline to exactly match js.
|
||
|
+ // result.append('\n');
|
||
|
+ for (int j = 0; j < indent; j++){
|
||
|
+ // result.append(' ');
|
||
|
+ result.append("");
|
||
|
+ }
|
||
|
+ } else {
|
||
|
+ if (topFunctionType == FunctionNode.FUNCTION_EXPRESSION) {
|
||
|
+ result.append('(');
|
||
|
+ }
|
||
|
+ }
|
||
|
+ while (i < length) {
|
||
|
+ if(i>0){
|
||
|
+ prevToken = encodedSource.charAt(i-1);
|
||
|
+ }
|
||
|
+ // System.out.println(Token.name(getNext(source, length, i)));
|
||
|
+ switch(encodedSource.charAt(i)) {
|
||
|
+ case Token.NAME:
|
||
|
+ case Token.REGEXP: // re-wrapped in '/'s in parser...
|
||
|
+ int jumpPos = getSourceStringEnd(encodedSource, i+1);
|
||
|
+ if(Token.OBJECTLIT == encodedSource.charAt(jumpPos)){
|
||
|
+ i = printSourceString(encodedSource, i + 1, false, result);
|
||
|
+ }else{
|
||
|
+ i = tm.sourceCompress( encodedSource, i + 1, false, result, prevToken,
|
||
|
+ inArgsList, braceNesting, parseTree);
|
||
|
+ }
|
||
|
+ continue;
|
||
|
+ case Token.STRING:
|
||
|
+ i = printSourceString(encodedSource, i + 1, true, result);
|
||
|
+ continue;
|
||
|
+ case Token.NUMBER:
|
||
|
+ i = printSourceNumber(encodedSource, i + 1, result);
|
||
|
+ continue;
|
||
|
+ case Token.TRUE:
|
||
|
+ result.append("true");
|
||
|
+ break;
|
||
|
+ case Token.FALSE:
|
||
|
+ result.append("false");
|
||
|
+ break;
|
||
|
+ case Token.NULL:
|
||
|
+ result.append("null");
|
||
|
+ break;
|
||
|
+ case Token.THIS:
|
||
|
+ result.append("this");
|
||
|
+ break;
|
||
|
+ case Token.FUNCTION:
|
||
|
+ ++i; // skip function type
|
||
|
+ tm.functionNum++;
|
||
|
+ primeInArgsList = true;
|
||
|
+ primeFunctionNesting = true;
|
||
|
+ result.append("function");
|
||
|
+ if (Token.LP != getNext(encodedSource, length, i)) {
|
||
|
+ result.append(' ');
|
||
|
+ }
|
||
|
+ break;
|
||
|
+ case FUNCTION_END:
|
||
|
+ // Do nothing
|
||
|
+ break;
|
||
|
+ case Token.COMMA:
|
||
|
+ result.append(",");
|
||
|
+ break;
|
||
|
+ case Token.LC:
|
||
|
+ ++braceNesting;
|
||
|
+ if (Token.EOL == getNext(encodedSource, length, i)){
|
||
|
+ indent += indentGap;
|
||
|
+ }
|
||
|
+ result.append('{');
|
||
|
+ // // result.append('\n');
|
||
|
+ break;
|
||
|
+ case Token.RC: {
|
||
|
+ tm.leaveNestingLevel(braceNesting);
|
||
|
+ --braceNesting;
|
||
|
+ /* don't print the closing RC if it closes the
|
||
|
+ * toplevel function and we're called from
|
||
|
+ * decompileFunctionBody.
|
||
|
+ */
|
||
|
+ if(justFunctionBody && braceNesting == 0){
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ // // result.append('\n');
|
||
|
+ result.append('}');
|
||
|
+ // // result.append(' ');
|
||
|
+ switch (getNext(encodedSource, length, i)) {
|
||
|
+ case Token.EOL:
|
||
|
+ case FUNCTION_END:
|
||
|
+ indent -= indentGap;
|
||
|
+ break;
|
||
|
+ case Token.WHILE:
|
||
|
+ case Token.ELSE:
|
||
|
+ indent -= indentGap;
|
||
|
+ // result.append(' ');
|
||
|
+ result.append("");
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ case Token.LP:
|
||
|
+ if(primeInArgsList){
|
||
|
+ inArgsList = true;
|
||
|
+ primeInArgsList = false;
|
||
|
+ }
|
||
|
+ if(primeFunctionNesting){
|
||
|
+ tm.enterNestingLevel(braceNesting);
|
||
|
+ primeFunctionNesting = false;
|
||
|
+ }
|
||
|
+ result.append('(');
|
||
|
+ break;
|
||
|
+ case Token.RP:
|
||
|
+ if(inArgsList){
|
||
|
+ inArgsList = false;
|
||
|
+ }
|
||
|
+ result.append(')');
|
||
|
+ /*
|
||
|
+ if (Token.LC == getNext(source, length, i)){
|
||
|
+ result.append(' ');
|
||
|
+ }
|
||
|
+ */
|
||
|
+ break;
|
||
|
+ case Token.LB:
|
||
|
+ result.append('[');
|
||
|
+ break;
|
||
|
+ case Token.RB:
|
||
|
+ result.append(']');
|
||
|
+ break;
|
||
|
+ case Token.EOL: {
|
||
|
+ if (toSource) break;
|
||
|
+ boolean newLine = true;
|
||
|
+ if (!afterFirstEOL) {
|
||
|
+ afterFirstEOL = true;
|
||
|
+ if (justFunctionBody) {
|
||
|
+ /* throw away just added 'function name(...) {'
|
||
|
+ * and restore the original indent
|
||
|
+ */
|
||
|
+ result.setLength(0);
|
||
|
+ indent -= indentGap;
|
||
|
+ newLine = false;
|
||
|
+ }
|
||
|
+ }
|
||
|
+ if (newLine) {
|
||
|
+ result.append('\n');
|
||
|
+ }
|
||
|
+ /*
|
||
|
+ */
|
||
|
+ /* add indent if any tokens remain,
|
||
|
+ * less setback if next token is
|
||
|
+ * a label, case or default.
|
||
|
+ */
|
||
|
+ if (i + 1 < length) {
|
||
|
+ int less = 0;
|
||
|
+ int nextToken = encodedSource.charAt(i + 1);
|
||
|
+ if (nextToken == Token.CASE
|
||
|
+ || nextToken == Token.DEFAULT)
|
||
|
+ {
|
||
|
+ less = indentGap - caseGap;
|
||
|
+ } else if (nextToken == Token.RC) {
|
||
|
+ less = indentGap;
|
||
|
+ }
|
||
|
+ /* elaborate check against label... skip past a
|
||
|
+ * following inlined NAME and look for a COLON.
|
||
|
+ */
|
||
|
+ else if (nextToken == Token.NAME) {
|
||
|
+ int afterName = getSourceStringEnd(encodedSource, i + 2);
|
||
|
+ if (encodedSource.charAt(afterName) == Token.COLON)
|
||
|
+ less = indentGap;
|
||
|
+ }
|
||
|
+ for (; less < indent; less++){
|
||
|
+ // result.append(' ');
|
||
|
+ result.append("");
|
||
|
+ }
|
||
|
+ }
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ case Token.DOT:
|
||
|
+ result.append('.');
|
||
|
+ break;
|
||
|
+ case Token.NEW:
|
||
|
+ result.append("new ");
|
||
|
+ break;
|
||
|
+ case Token.DELPROP:
|
||
|
+ result.append("delete ");
|
||
|
+ break;
|
||
|
+ case Token.IF:
|
||
|
+ result.append("if");
|
||
|
+ break;
|
||
|
+ case Token.ELSE:
|
||
|
+ result.append("else");
|
||
|
+ break;
|
||
|
+ case Token.FOR:
|
||
|
+ result.append("for");
|
||
|
+ break;
|
||
|
+ case Token.IN:
|
||
|
+ result.append(" in ");
|
||
|
+ break;
|
||
|
+ case Token.WITH:
|
||
|
+ result.append("with");
|
||
|
+ break;
|
||
|
+ case Token.WHILE:
|
||
|
+ result.append("while");
|
||
|
+ break;
|
||
|
+ case Token.DO:
|
||
|
+ result.append("do");
|
||
|
+ break;
|
||
|
+ case Token.TRY:
|
||
|
+ result.append("try");
|
||
|
+ break;
|
||
|
+ case Token.CATCH:
|
||
|
+ result.append("catch");
|
||
|
+ break;
|
||
|
+ case Token.FINALLY:
|
||
|
+ result.append("finally");
|
||
|
+ break;
|
||
|
+ case Token.THROW:
|
||
|
+ result.append("throw ");
|
||
|
+ break;
|
||
|
+ case Token.SWITCH:
|
||
|
+ result.append("switch");
|
||
|
+ break;
|
||
|
+ case Token.BREAK:
|
||
|
+ result.append("break");
|
||
|
+ if(Token.NAME == getNext(encodedSource, length, i)){
|
||
|
+ result.append(' ');
|
||
|
+ }
|
||
|
+ break;
|
||
|
+ case Token.CONTINUE:
|
||
|
+ result.append("continue");
|
||
|
+ if(Token.NAME == getNext(encodedSource, length, i)){
|
||
|
+ result.append(' ');
|
||
|
+ }
|
||
|
+ break;
|
||
|
+ case Token.CASE:
|
||
|
+ result.append("case ");
|
||
|
+ break;
|
||
|
+ case Token.DEFAULT:
|
||
|
+ result.append("default");
|
||
|
+ break;
|
||
|
+ case Token.RETURN:
|
||
|
+ result.append("return");
|
||
|
+ if(Token.SEMI != getNext(encodedSource, length, i)){
|
||
|
+ result.append(' ');
|
||
|
+ }
|
||
|
+ break;
|
||
|
+ case Token.VAR:
|
||
|
+ result.append("var ");
|
||
|
+ break;
|
||
|
+ case Token.SEMI:
|
||
|
+ result.append(';');
|
||
|
+ // result.append('\n');
|
||
|
+ /*
|
||
|
+ if (Token.EOL != getNext(source, length, i)) {
|
||
|
+ // separators in FOR
|
||
|
+ result.append(' ');
|
||
|
+ }
|
||
|
+ */
|
||
|
+ break;
|
||
|
+ case Token.ASSIGN:
|
||
|
+ result.append("=");
|
||
|
+ break;
|
||
|
+ case Token.ASSIGN_ADD:
|
||
|
+ result.append("+=");
|
||
|
+ break;
|
||
|
+ case Token.ASSIGN_SUB:
|
||
|
+ result.append("-=");
|
||
|
+ break;
|
||
|
+ case Token.ASSIGN_MUL:
|
||
|
+ result.append("*=");
|
||
|
+ break;
|
||
|
+ case Token.ASSIGN_DIV:
|
||
|
+ result.append("/=");
|
||
|
+ break;
|
||
|
+ case Token.ASSIGN_MOD:
|
||
|
+ result.append("%=");
|
||
|
+ break;
|
||
|
+ case Token.ASSIGN_BITOR:
|
||
|
+ result.append("|=");
|
||
|
+ break;
|
||
|
+ case Token.ASSIGN_BITXOR:
|
||
|
+ result.append("^=");
|
||
|
+ break;
|
||
|
+ case Token.ASSIGN_BITAND:
|
||
|
+ result.append("&=");
|
||
|
+ break;
|
||
|
+ case Token.ASSIGN_LSH:
|
||
|
+ result.append("<<=");
|
||
|
+ break;
|
||
|
+ case Token.ASSIGN_RSH:
|
||
|
+ result.append(">>=");
|
||
|
+ break;
|
||
|
+ case Token.ASSIGN_URSH:
|
||
|
+ result.append(">>>=");
|
||
|
+ break;
|
||
|
+ case Token.HOOK:
|
||
|
+ result.append("?");
|
||
|
+ break;
|
||
|
+ case Token.OBJECTLIT:
|
||
|
+ // pun OBJECTLIT to mean colon in objlit property
|
||
|
+ // initialization.
|
||
|
+ // This needs to be distinct from COLON in the general case
|
||
|
+ // to distinguish from the colon in a ternary... which needs
|
||
|
+ // different spacing.
|
||
|
+ result.append(':');
|
||
|
+ break;
|
||
|
+ case Token.COLON:
|
||
|
+ if (Token.EOL == getNext(encodedSource, length, i))
|
||
|
+ // it's the end of a label
|
||
|
+ result.append(':');
|
||
|
+ else
|
||
|
+ // it's the middle part of a ternary
|
||
|
+ result.append(":");
|
||
|
+ break;
|
||
|
+ case Token.OR:
|
||
|
+ result.append("||");
|
||
|
+ break;
|
||
|
+ case Token.AND:
|
||
|
+ result.append("&&");
|
||
|
+ break;
|
||
|
+ case Token.BITOR:
|
||
|
+ result.append("|");
|
||
|
+ break;
|
||
|
+ case Token.BITXOR:
|
||
|
+ result.append("^");
|
||
|
+ break;
|
||
|
+ case Token.BITAND:
|
||
|
+ result.append("&");
|
||
|
+ break;
|
||
|
+ case Token.SHEQ:
|
||
|
+ result.append("===");
|
||
|
+ break;
|
||
|
+ case Token.SHNE:
|
||
|
+ result.append("!==");
|
||
|
+ break;
|
||
|
+ case Token.EQ:
|
||
|
+ result.append("==");
|
||
|
+ break;
|
||
|
+ case Token.NE:
|
||
|
+ result.append("!=");
|
||
|
+ break;
|
||
|
+ case Token.LE:
|
||
|
+ result.append("<=");
|
||
|
+ break;
|
||
|
+ case Token.LT:
|
||
|
+ result.append("<");
|
||
|
+ break;
|
||
|
+ case Token.GE:
|
||
|
+ result.append(">=");
|
||
|
+ break;
|
||
|
+ case Token.GT:
|
||
|
+ result.append(">");
|
||
|
+ break;
|
||
|
+ case Token.INSTANCEOF:
|
||
|
+ // FIXME: does this really need leading space?
|
||
|
+ result.append(" instanceof ");
|
||
|
+ break;
|
||
|
+ case Token.LSH:
|
||
|
+ result.append("<<");
|
||
|
+ break;
|
||
|
+ case Token.RSH:
|
||
|
+ result.append(">>");
|
||
|
+ break;
|
||
|
+ case Token.URSH:
|
||
|
+ result.append(">>>");
|
||
|
+ break;
|
||
|
+ case Token.TYPEOF:
|
||
|
+ result.append("typeof ");
|
||
|
+ break;
|
||
|
+ case Token.VOID:
|
||
|
+ result.append("void ");
|
||
|
+ break;
|
||
|
+ case Token.NOT:
|
||
|
+ result.append('!');
|
||
|
+ break;
|
||
|
+ case Token.BITNOT:
|
||
|
+ result.append('~');
|
||
|
+ break;
|
||
|
+ case Token.POS:
|
||
|
+ result.append('+');
|
||
|
+ break;
|
||
|
+ case Token.NEG:
|
||
|
+ result.append('-');
|
||
|
+ break;
|
||
|
+ case Token.INC:
|
||
|
+ if(Token.ADD == prevToken){
|
||
|
+ result.append(' ');
|
||
|
+ }
|
||
|
+ result.append("++");
|
||
|
+ if(Token.ADD == getNext(encodedSource, length, i)){
|
||
|
+ result.append(' ');
|
||
|
+ }
|
||
|
+ break;
|
||
|
+ case Token.DEC:
|
||
|
+ if(Token.SUB == prevToken){
|
||
|
+ result.append(' ');
|
||
|
+ }
|
||
|
+ result.append("--");
|
||
|
+ if(Token.SUB == getNext(encodedSource, length, i)){
|
||
|
+ result.append(' ');
|
||
|
+ }
|
||
|
+ break;
|
||
|
+ case Token.ADD:
|
||
|
+ result.append("+");
|
||
|
+ break;
|
||
|
+ case Token.SUB:
|
||
|
+ result.append("-");
|
||
|
+ break;
|
||
|
+ case Token.MUL:
|
||
|
+ result.append("*");
|
||
|
+ break;
|
||
|
+ case Token.DIV:
|
||
|
+ result.append("/");
|
||
|
+ break;
|
||
|
+ case Token.MOD:
|
||
|
+ result.append("%");
|
||
|
+ break;
|
||
|
+ case Token.COLONCOLON:
|
||
|
+ result.append("::");
|
||
|
+ break;
|
||
|
+ case Token.DOTDOT:
|
||
|
+ result.append("..");
|
||
|
+ break;
|
||
|
+ case Token.XMLATTR:
|
||
|
+ result.append('@');
|
||
|
+ break;
|
||
|
+ default:
|
||
|
+ // If we don't know how to decompile it, raise an exception.
|
||
|
+ throw new RuntimeException();
|
||
|
+ }
|
||
|
+ ++i;
|
||
|
+ }
|
||
|
+ if (!toSource) {
|
||
|
+ // add that trailing newline if it's an outermost function.
|
||
|
+ // if (!justFunctionBody){
|
||
|
+ // result.append('\n');
|
||
|
+ // }
|
||
|
+ } else {
|
||
|
+ if (topFunctionType == FunctionNode.FUNCTION_EXPRESSION) {
|
||
|
+ result.append(')');
|
||
|
+ }
|
||
|
+ }
|
||
|
+ return result.toString();
|
||
|
+ }
|
||
|
/**
|
||
|
* Decompile the source information associated with this js
|
||
|
* function/script back into a string. For the most part, this
|
||
|
Index: src/org/mozilla/javascript/NativeFunction.java
|
||
|
===================================================================
|
||
|
--- src/org/mozilla/javascript/NativeFunction.java.orig 2009-11-16 15:55:50.222561412 +0100
|
||
|
+++ src/org/mozilla/javascript/NativeFunction.java 2009-11-16 15:56:40.118560586 +0100
|
||
|
@@ -75,6 +75,27 @@
|
||
|
}
|
||
|
}
|
||
|
|
||
|
+ /**
|
||
|
+ * Compress the script.
|
||
|
+ * <p>
|
||
|
+ *
|
||
|
+ * @param parseTree Mapping for each function node and corresponding parameters & variables names
|
||
|
+ * @param indent How much to indent the decompiled result
|
||
|
+ * @param flags Flags specifying format of decompilation output
|
||
|
+ * @return compressed script
|
||
|
+ */
|
||
|
+ final String compress(ScriptOrFnNode parseTree, int indent, int flags)
|
||
|
+ {
|
||
|
+ String encodedSource = getEncodedSource();
|
||
|
+ if (encodedSource == null) {
|
||
|
+ return super.compress(indent, flags);
|
||
|
+ } else {
|
||
|
+ UintMap properties = new UintMap(1);
|
||
|
+ properties.put(Decompiler.INITIAL_INDENT_PROP, indent);
|
||
|
+ return Decompiler.compress(encodedSource, flags, properties, parseTree);
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
@Override
|
||
|
public int getLength()
|
||
|
{
|
||
|
Index: src/org/mozilla/javascript/TokenStream.java
|
||
|
===================================================================
|
||
|
--- src/org/mozilla/javascript/TokenStream.java.orig 2009-11-16 15:55:50.222561412 +0100
|
||
|
+++ src/org/mozilla/javascript/TokenStream.java 2009-11-16 15:56:40.138561046 +0100
|
||
|
@@ -68,9 +68,12 @@
|
||
|
private final static int
|
||
|
EOF_CHAR = -1;
|
||
|
|
||
|
+ public StringBuffer lastComment;
|
||
|
+
|
||
|
TokenStream(Parser parser, Reader sourceReader, String sourceString,
|
||
|
int lineno)
|
||
|
{
|
||
|
+ this.lastComment = new StringBuffer();
|
||
|
this.parser = parser;
|
||
|
this.lineno = lineno;
|
||
|
if (sourceReader != null) {
|
||
|
@@ -754,6 +757,8 @@
|
||
|
|
||
|
case '/':
|
||
|
// is it a // comment?
|
||
|
+ // FIXME: RAR: comment, need to set config to optionally keep
|
||
|
+ // instead of skipping!
|
||
|
if (matchChar('/')) {
|
||
|
skipLine();
|
||
|
continue retry;
|
||
|
Index: toolsrc/org/mozilla/javascript/tools/debugger/downloaded/AbstractCellEditor.java
|
||
|
===================================================================
|
||
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
||
|
+++ toolsrc/org/mozilla/javascript/tools/debugger/downloaded/AbstractCellEditor.java 2009-11-16 15:56:40.194560334 +0100
|
||
|
@@ -0,0 +1,63 @@
|
||
|
+
|
||
|
+ package org.mozilla.javascript.tools.debugger.downloaded;
|
||
|
+ import java.awt.Component;
|
||
|
+
|
||
|
+import java.awt.event.*;
|
||
|
+import java.awt.AWTEvent;
|
||
|
+import javax.swing.*;
|
||
|
+import javax.swing.event.*;
|
||
|
+import java.util.EventObject;
|
||
|
+import java.io.Serializable;
|
||
|
+
|
||
|
+public class AbstractCellEditor implements CellEditor {
|
||
|
+
|
||
|
+ protected EventListenerList listenerList = new EventListenerList();
|
||
|
+
|
||
|
+ public Object getCellEditorValue() { return null; }
|
||
|
+ public boolean isCellEditable(EventObject e) { return true; }
|
||
|
+ public boolean shouldSelectCell(EventObject anEvent) { return false; }
|
||
|
+ public boolean stopCellEditing() { return true; }
|
||
|
+ public void cancelCellEditing() {}
|
||
|
+
|
||
|
+ public void addCellEditorListener(CellEditorListener l) {
|
||
|
+ listenerList.add(CellEditorListener.class, l);
|
||
|
+ }
|
||
|
+
|
||
|
+ public void removeCellEditorListener(CellEditorListener l) {
|
||
|
+ listenerList.remove(CellEditorListener.class, l);
|
||
|
+ }
|
||
|
+
|
||
|
+ /*
|
||
|
+ * Notify all listeners that have registered interest for
|
||
|
+ * notification on this event type.
|
||
|
+ * @see EventListenerList
|
||
|
+ */
|
||
|
+ protected void fireEditingStopped() {
|
||
|
+ // Guaranteed to return a non-null array
|
||
|
+ Object[] listeners = listenerList.getListenerList();
|
||
|
+ // Process the listeners last to first, notifying
|
||
|
+ // those that are interested in this event
|
||
|
+ for (int i = listeners.length-2; i>=0; i-=2) {
|
||
|
+ if (listeners[i]==CellEditorListener.class) {
|
||
|
+ ((CellEditorListener)listeners[i+1]).editingStopped(new ChangeEvent(this));
|
||
|
+ }
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ /*
|
||
|
+ * Notify all listeners that have registered interest for
|
||
|
+ * notification on this event type.
|
||
|
+ * @see EventListenerList
|
||
|
+ */
|
||
|
+ protected void fireEditingCanceled() {
|
||
|
+ // Guaranteed to return a non-null array
|
||
|
+ Object[] listeners = listenerList.getListenerList();
|
||
|
+ // Process the listeners last to first, notifying
|
||
|
+ // those that are interested in this event
|
||
|
+ for (int i = listeners.length-2; i>=0; i-=2) {
|
||
|
+ if (listeners[i]==CellEditorListener.class) {
|
||
|
+ ((CellEditorListener)listeners[i+1]).editingCanceled(new ChangeEvent(this));
|
||
|
+ }
|
||
|
+ }
|
||
|
+ }
|
||
|
+}
|
||
|
Index: toolsrc/org/mozilla/javascript/tools/debugger/downloaded/JTreeTable.java
|
||
|
===================================================================
|
||
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
||
|
+++ toolsrc/org/mozilla/javascript/tools/debugger/downloaded/JTreeTable.java 2009-11-16 15:56:40.210560494 +0100
|
||
|
@@ -0,0 +1,356 @@
|
||
|
+/*
|
||
|
+ * @(#)JTreeTable.java 1.2 98/10/27
|
||
|
+ *
|
||
|
+ * Copyright 1997, 1998 by Sun Microsystems, Inc.,
|
||
|
+ * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
|
||
|
+ * All rights reserved.
|
||
|
+ *
|
||
|
+ * This software is the confidential and proprietary information
|
||
|
+ * of Sun Microsystems, Inc. ("Confidential Information"). You
|
||
|
+ * shall not disclose such Confidential Information and shall use
|
||
|
+ * it only in accordance with the terms of the license agreement
|
||
|
+ * you entered into with Sun.
|
||
|
+ */
|
||
|
+
|
||
|
+
|
||
|
+ package org.mozilla.javascript.tools.debugger.downloaded;
|
||
|
+ import javax.swing.*;
|
||
|
+
|
||
|
+import javax.swing.event.*;
|
||
|
+import javax.swing.tree.*;
|
||
|
+import javax.swing.table.*;
|
||
|
+
|
||
|
+import java.awt.Dimension;
|
||
|
+import java.awt.Component;
|
||
|
+import java.awt.Graphics;
|
||
|
+import java.awt.Rectangle;
|
||
|
+
|
||
|
+import java.awt.event.MouseEvent;
|
||
|
+
|
||
|
+import java.util.EventObject;
|
||
|
+
|
||
|
+/**
|
||
|
+ * This example shows how to create a simple JTreeTable component,
|
||
|
+ * by using a JTree as a renderer (and editor) for the cells in a
|
||
|
+ * particular column in the JTable.
|
||
|
+ *
|
||
|
+ * @version 1.2 10/27/98
|
||
|
+ *
|
||
|
+ * @author Philip Milne
|
||
|
+ * @author Scott Violet
|
||
|
+ */
|
||
|
+public class JTreeTable extends JTable {
|
||
|
+ /** A subclass of JTree. */
|
||
|
+ protected TreeTableCellRenderer tree;
|
||
|
+
|
||
|
+ public JTreeTable(TreeTableModel treeTableModel) {
|
||
|
+ super();
|
||
|
+
|
||
|
+ // Create the tree. It will be used as a renderer and editor.
|
||
|
+ tree = new TreeTableCellRenderer(treeTableModel);
|
||
|
+
|
||
|
+ // Install a tableModel representing the visible rows in the tree.
|
||
|
+ super.setModel(new TreeTableModelAdapter(treeTableModel, tree));
|
||
|
+
|
||
|
+ // Force the JTable and JTree to share their row selection models.
|
||
|
+ ListToTreeSelectionModelWrapper selectionWrapper = new
|
||
|
+ ListToTreeSelectionModelWrapper();
|
||
|
+ tree.setSelectionModel(selectionWrapper);
|
||
|
+ setSelectionModel(selectionWrapper.getListSelectionModel());
|
||
|
+
|
||
|
+ // Install the tree editor renderer and editor.
|
||
|
+ setDefaultRenderer(TreeTableModel.class, tree);
|
||
|
+ setDefaultEditor(TreeTableModel.class, new TreeTableCellEditor());
|
||
|
+
|
||
|
+ // No grid.
|
||
|
+ setShowGrid(false);
|
||
|
+
|
||
|
+ // No intercell spacing
|
||
|
+ setIntercellSpacing(new Dimension(0, 0));
|
||
|
+
|
||
|
+ // And update the height of the trees row to match that of
|
||
|
+ // the table.
|
||
|
+ if (tree.getRowHeight() < 1) {
|
||
|
+ // Metal looks better like this.
|
||
|
+ setRowHeight(18);
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ /**
|
||
|
+ * Overridden to message super and forward the method to the tree.
|
||
|
+ * Since the tree is not actually in the component hieachy it will
|
||
|
+ * never receive this unless we forward it in this manner.
|
||
|
+ */
|
||
|
+ public void updateUI() {
|
||
|
+ super.updateUI();
|
||
|
+ if(tree != null) {
|
||
|
+ tree.updateUI();
|
||
|
+ }
|
||
|
+ // Use the tree's default foreground and background colors in the
|
||
|
+ // table.
|
||
|
+ LookAndFeel.installColorsAndFont(this, "Tree.background",
|
||
|
+ "Tree.foreground", "Tree.font");
|
||
|
+ }
|
||
|
+
|
||
|
+ /* Workaround for BasicTableUI anomaly. Make sure the UI never tries to
|
||
|
+ * paint the editor. The UI currently uses different techniques to
|
||
|
+ * paint the renderers and editors and overriding setBounds() below
|
||
|
+ * is not the right thing to do for an editor. Returning -1 for the
|
||
|
+ * editing row in this case, ensures the editor is never painted.
|
||
|
+ */
|
||
|
+ public int getEditingRow() {
|
||
|
+ return (getColumnClass(editingColumn) == TreeTableModel.class) ? -1 :
|
||
|
+ editingRow;
|
||
|
+ }
|
||
|
+
|
||
|
+ /**
|
||
|
+ * Overridden to pass the new rowHeight to the tree.
|
||
|
+ */
|
||
|
+ public void setRowHeight(int rowHeight) {
|
||
|
+ super.setRowHeight(rowHeight);
|
||
|
+ if (tree != null && tree.getRowHeight() != rowHeight) {
|
||
|
+ tree.setRowHeight(getRowHeight());
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ /**
|
||
|
+ * Returns the tree that is being shared between the model.
|
||
|
+ */
|
||
|
+ public JTree getTree() {
|
||
|
+ return tree;
|
||
|
+ }
|
||
|
+
|
||
|
+ /**
|
||
|
+ * A TreeCellRenderer that displays a JTree.
|
||
|
+ */
|
||
|
+ public class TreeTableCellRenderer extends JTree implements
|
||
|
+ TableCellRenderer {
|
||
|
+ /** Last table/tree row asked to renderer. */
|
||
|
+ protected int visibleRow;
|
||
|
+
|
||
|
+ public TreeTableCellRenderer(TreeModel model) {
|
||
|
+ super(model);
|
||
|
+ }
|
||
|
+
|
||
|
+ /**
|
||
|
+ * updateUI is overridden to set the colors of the Tree's renderer
|
||
|
+ * to match that of the table.
|
||
|
+ */
|
||
|
+ public void updateUI() {
|
||
|
+ super.updateUI();
|
||
|
+ // Make the tree's cell renderer use the table's cell selection
|
||
|
+ // colors.
|
||
|
+ TreeCellRenderer tcr = getCellRenderer();
|
||
|
+ if (tcr instanceof DefaultTreeCellRenderer) {
|
||
|
+ DefaultTreeCellRenderer dtcr = ((DefaultTreeCellRenderer)tcr);
|
||
|
+ // For 1.1 uncomment this, 1.2 has a bug that will cause an
|
||
|
+ // exception to be thrown if the border selection color is
|
||
|
+ // null.
|
||
|
+ // dtcr.setBorderSelectionColor(null);
|
||
|
+ dtcr.setTextSelectionColor(UIManager.getColor
|
||
|
+ ("Table.selectionForeground"));
|
||
|
+ dtcr.setBackgroundSelectionColor(UIManager.getColor
|
||
|
+ ("Table.selectionBackground"));
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ /**
|
||
|
+ * Sets the row height of the tree, and forwards the row height to
|
||
|
+ * the table.
|
||
|
+ */
|
||
|
+ public void setRowHeight(int rowHeight) {
|
||
|
+ if (rowHeight > 0) {
|
||
|
+ super.setRowHeight(rowHeight);
|
||
|
+ if (JTreeTable.this != null &&
|
||
|
+ JTreeTable.this.getRowHeight() != rowHeight) {
|
||
|
+ JTreeTable.this.setRowHeight(getRowHeight());
|
||
|
+ }
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ /**
|
||
|
+ * This is overridden to set the height to match that of the JTable.
|
||
|
+ */
|
||
|
+ public void setBounds(int x, int y, int w, int h) {
|
||
|
+ super.setBounds(x, 0, w, JTreeTable.this.getHeight());
|
||
|
+ }
|
||
|
+
|
||
|
+ /**
|
||
|
+ * Sublcassed to translate the graphics such that the last visible
|
||
|
+ * row will be drawn at 0,0.
|
||
|
+ */
|
||
|
+ public void paint(Graphics g) {
|
||
|
+ g.translate(0, -visibleRow * getRowHeight());
|
||
|
+ super.paint(g);
|
||
|
+ }
|
||
|
+
|
||
|
+ /**
|
||
|
+ * TreeCellRenderer method. Overridden to update the visible row.
|
||
|
+ */
|
||
|
+ public Component getTableCellRendererComponent(JTable table,
|
||
|
+ Object value,
|
||
|
+ boolean isSelected,
|
||
|
+ boolean hasFocus,
|
||
|
+ int row, int column) {
|
||
|
+ if(isSelected)
|
||
|
+ setBackground(table.getSelectionBackground());
|
||
|
+ else
|
||
|
+ setBackground(table.getBackground());
|
||
|
+
|
||
|
+ visibleRow = row;
|
||
|
+ return this;
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+
|
||
|
+ /**
|
||
|
+ * TreeTableCellEditor implementation. Component returned is the
|
||
|
+ * JTree.
|
||
|
+ */
|
||
|
+ public class TreeTableCellEditor extends AbstractCellEditor implements
|
||
|
+ TableCellEditor {
|
||
|
+ public Component getTableCellEditorComponent(JTable table,
|
||
|
+ Object value,
|
||
|
+ boolean isSelected,
|
||
|
+ int r, int c) {
|
||
|
+ return tree;
|
||
|
+ }
|
||
|
+
|
||
|
+ /**
|
||
|
+ * Overridden to return false, and if the event is a mouse event
|
||
|
+ * it is forwarded to the tree.<p>
|
||
|
+ * The behavior for this is debatable, and should really be offered
|
||
|
+ * as a property. By returning false, all keyboard actions are
|
||
|
+ * implemented in terms of the table. By returning true, the
|
||
|
+ * tree would get a chance to do something with the keyboard
|
||
|
+ * events. For the most part this is ok. But for certain keys,
|
||
|
+ * such as left/right, the tree will expand/collapse where as
|
||
|
+ * the table focus should really move to a different column. Page
|
||
|
+ * up/down should also be implemented in terms of the table.
|
||
|
+ * By returning false this also has the added benefit that clicking
|
||
|
+ * outside of the bounds of the tree node, but still in the tree
|
||
|
+ * column will select the row, whereas if this returned true
|
||
|
+ * that wouldn't be the case.
|
||
|
+ * <p>By returning false we are also enforcing the policy that
|
||
|
+ * the tree will never be editable (at least by a key sequence).
|
||
|
+ */
|
||
|
+ public boolean isCellEditable(EventObject e) {
|
||
|
+ if (e instanceof MouseEvent) {
|
||
|
+ for (int counter = getColumnCount() - 1; counter >= 0;
|
||
|
+ counter--) {
|
||
|
+ if (getColumnClass(counter) == TreeTableModel.class) {
|
||
|
+ MouseEvent me = (MouseEvent)e;
|
||
|
+ MouseEvent newME = new MouseEvent(tree, me.getID(),
|
||
|
+ me.getWhen(), me.getModifiers(),
|
||
|
+ me.getX() - getCellRect(0, counter, true).x,
|
||
|
+ me.getY(), me.getClickCount(),
|
||
|
+ me.isPopupTrigger());
|
||
|
+ tree.dispatchEvent(newME);
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ }
|
||
|
+ }
|
||
|
+ return false;
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+
|
||
|
+ /**
|
||
|
+ * ListToTreeSelectionModelWrapper extends DefaultTreeSelectionModel
|
||
|
+ * to listen for changes in the ListSelectionModel it maintains. Once
|
||
|
+ * a change in the ListSelectionModel happens, the paths are updated
|
||
|
+ * in the DefaultTreeSelectionModel.
|
||
|
+ */
|
||
|
+ public class ListToTreeSelectionModelWrapper extends DefaultTreeSelectionModel {
|
||
|
+ /** Set to true when we are updating the ListSelectionModel. */
|
||
|
+ protected boolean updatingListSelectionModel;
|
||
|
+
|
||
|
+ public ListToTreeSelectionModelWrapper() {
|
||
|
+ super();
|
||
|
+ getListSelectionModel().addListSelectionListener
|
||
|
+ (createListSelectionListener());
|
||
|
+ }
|
||
|
+
|
||
|
+ /**
|
||
|
+ * Returns the list selection model. ListToTreeSelectionModelWrapper
|
||
|
+ * listens for changes to this model and updates the selected paths
|
||
|
+ * accordingly.
|
||
|
+ */
|
||
|
+ public ListSelectionModel getListSelectionModel() {
|
||
|
+ return listSelectionModel;
|
||
|
+ }
|
||
|
+
|
||
|
+ /**
|
||
|
+ * This is overridden to set <code>updatingListSelectionModel</code>
|
||
|
+ * and message super. This is the only place DefaultTreeSelectionModel
|
||
|
+ * alters the ListSelectionModel.
|
||
|
+ */
|
||
|
+ public void resetRowSelection() {
|
||
|
+ if(!updatingListSelectionModel) {
|
||
|
+ updatingListSelectionModel = true;
|
||
|
+ try {
|
||
|
+ super.resetRowSelection();
|
||
|
+ }
|
||
|
+ finally {
|
||
|
+ updatingListSelectionModel = false;
|
||
|
+ }
|
||
|
+ }
|
||
|
+ // Notice how we don't message super if
|
||
|
+ // updatingListSelectionModel is true. If
|
||
|
+ // updatingListSelectionModel is true, it implies the
|
||
|
+ // ListSelectionModel has already been updated and the
|
||
|
+ // paths are the only thing that needs to be updated.
|
||
|
+ }
|
||
|
+
|
||
|
+ /**
|
||
|
+ * Creates and returns an instance of ListSelectionHandler.
|
||
|
+ */
|
||
|
+ protected ListSelectionListener createListSelectionListener() {
|
||
|
+ return new ListSelectionHandler();
|
||
|
+ }
|
||
|
+
|
||
|
+ /**
|
||
|
+ * If <code>updatingListSelectionModel</code> is false, this will
|
||
|
+ * reset the selected paths from the selected rows in the list
|
||
|
+ * selection model.
|
||
|
+ */
|
||
|
+ protected void updateSelectedPathsFromSelectedRows() {
|
||
|
+ if(!updatingListSelectionModel) {
|
||
|
+ updatingListSelectionModel = true;
|
||
|
+ try {
|
||
|
+ // This is way expensive, ListSelectionModel needs an
|
||
|
+ // enumerator for iterating.
|
||
|
+ int min = listSelectionModel.getMinSelectionIndex();
|
||
|
+ int max = listSelectionModel.getMaxSelectionIndex();
|
||
|
+
|
||
|
+ clearSelection();
|
||
|
+ if(min != -1 && max != -1) {
|
||
|
+ for(int counter = min; counter <= max; counter++) {
|
||
|
+ if(listSelectionModel.isSelectedIndex(counter)) {
|
||
|
+ TreePath selPath = tree.getPathForRow
|
||
|
+ (counter);
|
||
|
+
|
||
|
+ if(selPath != null) {
|
||
|
+ addSelectionPath(selPath);
|
||
|
+ }
|
||
|
+ }
|
||
|
+ }
|
||
|
+ }
|
||
|
+ }
|
||
|
+ finally {
|
||
|
+ updatingListSelectionModel = false;
|
||
|
+ }
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ /**
|
||
|
+ * Class responsible for calling updateSelectedPathsFromSelectedRows
|
||
|
+ * when the selection of the list changse.
|
||
|
+ */
|
||
|
+ class ListSelectionHandler implements ListSelectionListener {
|
||
|
+ public void valueChanged(ListSelectionEvent e) {
|
||
|
+ updateSelectedPathsFromSelectedRows();
|
||
|
+ }
|
||
|
+ }
|
||
|
+ }
|
||
|
+}
|
||
|
Index: toolsrc/org/mozilla/javascript/tools/debugger/downloaded/TreeTableModel.java
|
||
|
===================================================================
|
||
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
||
|
+++ toolsrc/org/mozilla/javascript/tools/debugger/downloaded/TreeTableModel.java 2009-11-16 15:56:40.226560347 +0100
|
||
|
@@ -0,0 +1,71 @@
|
||
|
+/*
|
||
|
+ * TreeTableModel.java
|
||
|
+ *
|
||
|
+ * Copyright (c) 1998 Sun Microsystems, Inc. All Rights Reserved.
|
||
|
+ *
|
||
|
+ * This software is the confidential and proprietary information of Sun
|
||
|
+ * Microsystems, Inc. ("Confidential Information"). You shall not
|
||
|
+ * disclose such Confidential Information and shall use it only in
|
||
|
+ * accordance with the terms of the license agreement you entered into
|
||
|
+ * with Sun.
|
||
|
+ *
|
||
|
+ * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
|
||
|
+ * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
||
|
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||
|
+ * PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES
|
||
|
+ * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
|
||
|
+ * THIS SOFTWARE OR ITS DERIVATIVES.
|
||
|
+ *
|
||
|
+ */
|
||
|
+
|
||
|
+
|
||
|
+ package org.mozilla.javascript.tools.debugger.downloaded;
|
||
|
+ import javax.swing.tree.TreeModel;
|
||
|
+
|
||
|
+
|
||
|
+/**
|
||
|
+ * TreeTableModel is the model used by a JTreeTable. It extends TreeModel
|
||
|
+ * to add methods for getting inforamtion about the set of columns each
|
||
|
+ * node in the TreeTableModel may have. Each column, like a column in
|
||
|
+ * a TableModel, has a name and a type associated with it. Each node in
|
||
|
+ * the TreeTableModel can return a value for each of the columns and
|
||
|
+ * set that value if isCellEditable() returns true.
|
||
|
+ *
|
||
|
+ * @author Philip Milne
|
||
|
+ * @author Scott Violet
|
||
|
+ */
|
||
|
+public interface TreeTableModel extends TreeModel
|
||
|
+{
|
||
|
+ /**
|
||
|
+ * Returns the number ofs availible column.
|
||
|
+ */
|
||
|
+ public int getColumnCount();
|
||
|
+
|
||
|
+ /**
|
||
|
+ * Returns the name for column number <code>column</code>.
|
||
|
+ */
|
||
|
+ public String getColumnName(int column);
|
||
|
+
|
||
|
+ /**
|
||
|
+ * Returns the type for column number <code>column</code>.
|
||
|
+ */
|
||
|
+ public Class getColumnClass(int column);
|
||
|
+
|
||
|
+ /**
|
||
|
+ * Returns the value to be displayed for node <code>node</code>,
|
||
|
+ * at column number <code>column</code>.
|
||
|
+ */
|
||
|
+ public Object getValueAt(Object node, int column);
|
||
|
+
|
||
|
+ /**
|
||
|
+ * Indicates whether the the value for node <code>node</code>,
|
||
|
+ * at column number <code>column</code> is editable.
|
||
|
+ */
|
||
|
+ public boolean isCellEditable(Object node, int column);
|
||
|
+
|
||
|
+ /**
|
||
|
+ * Sets the value for node <code>node</code>,
|
||
|
+ * at column number <code>column</code>.
|
||
|
+ */
|
||
|
+ public void setValueAt(Object aValue, Object node, int column);
|
||
|
+}
|
||
|
Index: toolsrc/org/mozilla/javascript/tools/debugger/downloaded/TreeTableModelAdapter.java
|
||
|
===================================================================
|
||
|
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
||
|
+++ toolsrc/org/mozilla/javascript/tools/debugger/downloaded/TreeTableModelAdapter.java 2009-11-16 15:56:40.246560362 +0100
|
||
|
@@ -0,0 +1,128 @@
|
||
|
+/*
|
||
|
+ * @(#)TreeTableModelAdapter.java 1.2 98/10/27
|
||
|
+ *
|
||
|
+ * Copyright 1997, 1998 by Sun Microsystems, Inc.,
|
||
|
+ * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
|
||
|
+ * All rights reserved.
|
||
|
+ *
|
||
|
+ * This software is the confidential and proprietary information
|
||
|
+ * of Sun Microsystems, Inc. ("Confidential Information"). You
|
||
|
+ * shall not disclose such Confidential Information and shall use
|
||
|
+ * it only in accordance with the terms of the license agreement
|
||
|
+ * you entered into with Sun.
|
||
|
+ */
|
||
|
+
|
||
|
+
|
||
|
+ package org.mozilla.javascript.tools.debugger.downloaded;
|
||
|
+ import javax.swing.JTree;
|
||
|
+
|
||
|
+import javax.swing.SwingUtilities;
|
||
|
+import javax.swing.table.AbstractTableModel;
|
||
|
+import javax.swing.tree.TreePath;
|
||
|
+import javax.swing.event.TreeExpansionEvent;
|
||
|
+import javax.swing.event.TreeExpansionListener;
|
||
|
+import javax.swing.event.TreeModelEvent;
|
||
|
+import javax.swing.event.TreeModelListener;
|
||
|
+
|
||
|
+/**
|
||
|
+ * This is a wrapper class takes a TreeTableModel and implements
|
||
|
+ * the table model interface. The implementation is trivial, with
|
||
|
+ * all of the event dispatching support provided by the superclass:
|
||
|
+ * the AbstractTableModel.
|
||
|
+ *
|
||
|
+ * @version 1.2 10/27/98
|
||
|
+ *
|
||
|
+ * @author Philip Milne
|
||
|
+ * @author Scott Violet
|
||
|
+ */
|
||
|
+public class TreeTableModelAdapter extends AbstractTableModel
|
||
|
+{
|
||
|
+ JTree tree;
|
||
|
+ TreeTableModel treeTableModel;
|
||
|
+
|
||
|
+ public TreeTableModelAdapter(TreeTableModel treeTableModel, JTree tree) {
|
||
|
+ this.tree = tree;
|
||
|
+ this.treeTableModel = treeTableModel;
|
||
|
+
|
||
|
+ tree.addTreeExpansionListener(new TreeExpansionListener() {
|
||
|
+ // Don't use fireTableRowsInserted() here; the selection model
|
||
|
+ // would get updated twice.
|
||
|
+ public void treeExpanded(TreeExpansionEvent event) {
|
||
|
+ fireTableDataChanged();
|
||
|
+ }
|
||
|
+ public void treeCollapsed(TreeExpansionEvent event) {
|
||
|
+ fireTableDataChanged();
|
||
|
+ }
|
||
|
+ });
|
||
|
+
|
||
|
+ // Install a TreeModelListener that can update the table when
|
||
|
+ // tree changes. We use delayedFireTableDataChanged as we can
|
||
|
+ // not be guaranteed the tree will have finished processing
|
||
|
+ // the event before us.
|
||
|
+ treeTableModel.addTreeModelListener(new TreeModelListener() {
|
||
|
+ public void treeNodesChanged(TreeModelEvent e) {
|
||
|
+ delayedFireTableDataChanged();
|
||
|
+ }
|
||
|
+
|
||
|
+ public void treeNodesInserted(TreeModelEvent e) {
|
||
|
+ delayedFireTableDataChanged();
|
||
|
+ }
|
||
|
+
|
||
|
+ public void treeNodesRemoved(TreeModelEvent e) {
|
||
|
+ delayedFireTableDataChanged();
|
||
|
+ }
|
||
|
+
|
||
|
+ public void treeStructureChanged(TreeModelEvent e) {
|
||
|
+ delayedFireTableDataChanged();
|
||
|
+ }
|
||
|
+ });
|
||
|
+ }
|
||
|
+
|
||
|
+ // Wrappers, implementing TableModel interface.
|
||
|
+
|
||
|
+ public int getColumnCount() {
|
||
|
+ return treeTableModel.getColumnCount();
|
||
|
+ }
|
||
|
+
|
||
|
+ public String getColumnName(int column) {
|
||
|
+ return treeTableModel.getColumnName(column);
|
||
|
+ }
|
||
|
+
|
||
|
+ public Class getColumnClass(int column) {
|
||
|
+ return treeTableModel.getColumnClass(column);
|
||
|
+ }
|
||
|
+
|
||
|
+ public int getRowCount() {
|
||
|
+ return tree.getRowCount();
|
||
|
+ }
|
||
|
+
|
||
|
+ protected Object nodeForRow(int row) {
|
||
|
+ TreePath treePath = tree.getPathForRow(row);
|
||
|
+ return treePath.getLastPathComponent();
|
||
|
+ }
|
||
|
+
|
||
|
+ public Object getValueAt(int row, int column) {
|
||
|
+ return treeTableModel.getValueAt(nodeForRow(row), column);
|
||
|
+ }
|
||
|
+
|
||
|
+ public boolean isCellEditable(int row, int column) {
|
||
|
+ return treeTableModel.isCellEditable(nodeForRow(row), column);
|
||
|
+ }
|
||
|
+
|
||
|
+ public void setValueAt(Object value, int row, int column) {
|
||
|
+ treeTableModel.setValueAt(value, nodeForRow(row), column);
|
||
|
+ }
|
||
|
+
|
||
|
+ /**
|
||
|
+ * Invokes fireTableDataChanged after all the pending events have been
|
||
|
+ * processed. SwingUtilities.invokeLater is used to handle this.
|
||
|
+ */
|
||
|
+ protected void delayedFireTableDataChanged() {
|
||
|
+ SwingUtilities.invokeLater(new Runnable() {
|
||
|
+ public void run() {
|
||
|
+ fireTableDataChanged();
|
||
|
+ }
|
||
|
+ });
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
Index: toolsrc/org/mozilla/javascript/tools/resources/Messages.properties
|
||
|
===================================================================
|
||
|
--- toolsrc/org/mozilla/javascript/tools/resources/Messages.properties.orig 2009-11-16 15:55:50.222561412 +0100
|
||
|
+++ toolsrc/org/mozilla/javascript/tools/resources/Messages.properties 2009-11-16 15:56:40.262560311 +0100
|
||
|
@@ -68,6 +68,8 @@
|
||
|
\ -opt [-1|0-9] Set optimization level.\n\
|
||
|
\ -f script-filename Execute script file, or "-" for interactive.\n\
|
||
|
\ -e script-source Evaluate inline script.\n\
|
||
|
+ \ -o output-filename Set the output filename.\n\
|
||
|
+ \ -c script-filename Set the script filename.\n\
|
||
|
\ -debug Generate debug code.\n\
|
||
|
\ -strict Enable strict mode warnings.\n\
|
||
|
\ -fatal-warnings Treat warnings as errors.\n\
|
||
|
Index: toolsrc/org/mozilla/javascript/tools/shell/Main.java
|
||
|
===================================================================
|
||
|
--- toolsrc/org/mozilla/javascript/tools/shell/Main.java.orig 2009-11-16 15:56:33.234061036 +0100
|
||
|
+++ toolsrc/org/mozilla/javascript/tools/shell/Main.java 2009-11-16 15:56:40.278560563 +0100
|
||
|
@@ -89,6 +89,9 @@
|
||
|
static private final int EXITCODE_RUNTIME_ERROR = 3;
|
||
|
static private final int EXITCODE_FILE_NOT_FOUND = 4;
|
||
|
static boolean processStdin = true;
|
||
|
+ static boolean outputCompressed = false;
|
||
|
+ static String outputFileName = "dojo.js.compressed.js";
|
||
|
+ static boolean isOutputFileSet = false;
|
||
|
static List<String> fileList = new ArrayList<String>();
|
||
|
private static SecurityProxy securityImpl;
|
||
|
|
||
|
@@ -296,6 +299,20 @@
|
||
|
shellContextFactory.call(iproxy);
|
||
|
continue;
|
||
|
}
|
||
|
+ if (arg.equals("-c")) {
|
||
|
+ outputCompressed = true;
|
||
|
+ continue;
|
||
|
+ }
|
||
|
+ if (arg.equals("-o") && ++i < args.length) {
|
||
|
+ if (args[i].startsWith("-") || args[i].length() == 0)
|
||
|
+ {
|
||
|
+ usageError = arg;
|
||
|
+ break goodUsage;
|
||
|
+ }
|
||
|
+ isOutputFileSet = true;
|
||
|
+ outputFileName = args[i];
|
||
|
+ continue;
|
||
|
+ }
|
||
|
if (arg.equals("-w")) {
|
||
|
errorReporter.setIsReportingWarnings(true);
|
||
|
continue;
|
||
|
@@ -462,10 +479,12 @@
|
||
|
String path, Object securityDomain)
|
||
|
{
|
||
|
Script script;
|
||
|
+ String cout = null;
|
||
|
+ String source = null;
|
||
|
if (path.endsWith(".class")) {
|
||
|
script = loadCompiledScript(cx, path, securityDomain);
|
||
|
} else {
|
||
|
- String source = (String)readFileOrUrl(path, true);
|
||
|
+ source = (String)readFileOrUrl(path, true);
|
||
|
if (source == null) {
|
||
|
exitCode = EXITCODE_FILE_NOT_FOUND;
|
||
|
return;
|
||
|
@@ -485,9 +504,58 @@
|
||
|
}
|
||
|
script = loadScriptFromSource(cx, source, path, 1, securityDomain);
|
||
|
}
|
||
|
- if (script != null) {
|
||
|
- evaluateScript(script, cx, scope);
|
||
|
- }
|
||
|
+ if ((script != null) && (source != null)) {
|
||
|
+ if (outputCompressed) {
|
||
|
+ cout = compressScript(cx, scope, script, source, path, 1,
|
||
|
+ securityDomain);
|
||
|
+ if (isOutputFileSet) {
|
||
|
+ try {
|
||
|
+ BufferedWriter out = new BufferedWriter(new FileWriter(
|
||
|
+ outputFileName));
|
||
|
+ out.write(cout);
|
||
|
+ out.close();
|
||
|
+ } catch (IOException ex) {
|
||
|
+ Context.reportError(ex.toString());
|
||
|
+ }
|
||
|
+ System.out.println("Compressed file stored in '" + outputFileName + "'");
|
||
|
+ } else {
|
||
|
+ global.getOut().println(cout);
|
||
|
+ }
|
||
|
+
|
||
|
+ }else{
|
||
|
+ evaluateScript(script, cx, scope);
|
||
|
+ }
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ public static String compressScript(Context cx, Scriptable scope, Script script, String source, String sourceName, int lineno, Object securityDomain)
|
||
|
+ {
|
||
|
+ String compressedSource = null;
|
||
|
+ try {
|
||
|
+ if (script != null) {
|
||
|
+ compressedSource = cx.compressReader(scope, script, source, sourceName,
|
||
|
+ lineno, securityDomain);
|
||
|
+ } else {
|
||
|
+ compressedSource = source;
|
||
|
+ }
|
||
|
+ } catch (WrappedException we) {
|
||
|
+ global.getErr().println(we.getWrappedException().toString());
|
||
|
+ we.printStackTrace();
|
||
|
+ } catch (EvaluatorException ee) {
|
||
|
+ // Already printed message.
|
||
|
+ exitCode = EXITCODE_RUNTIME_ERROR;
|
||
|
+ } catch (RhinoException rex) {
|
||
|
+ errorReporter.reportException(rex);
|
||
|
+ exitCode = EXITCODE_RUNTIME_ERROR;
|
||
|
+ } catch (VirtualMachineError ex) {
|
||
|
+ // Treat StackOverflow and OutOfMemory as runtime errors
|
||
|
+ ex.printStackTrace();
|
||
|
+ String msg = ToolErrorReporter.getMessage(
|
||
|
+ "msg.uncaughtJSException", ex.toString());
|
||
|
+ exitCode = EXITCODE_RUNTIME_ERROR;
|
||
|
+ Context.reportError(msg);
|
||
|
+ }
|
||
|
+ return compressedSource;
|
||
|
}
|
||
|
|
||
|
public static Script loadScriptFromSource(Context cx, String scriptSource,
|