Example #1
0
		/// <param name="indent">How much to indent the decompiled result</param>
		/// <param name="flags">Flags specifying format of decompilation output</param>
		internal sealed override string Decompile(int indent, int flags)
		{
			string encodedSource = GetEncodedSource();
			if (encodedSource == null)
			{
				return base.Decompile(indent, flags);
			}
			else
			{
				UintMap properties = new UintMap(1);
				properties.Put(Decompiler.INITIAL_INDENT_PROP, indent);
				return Decompiler.Decompile(encodedSource, flags, properties);
			}
		}
Example #2
0
		internal static int[] GetLineNumbers(InterpreterData data)
		{
			UintMap presentLines = new UintMap();
			byte[] iCode = data.itsICode;
			int iCodeLength = iCode.Length;
			for (int pc = 0; pc != iCodeLength; )
			{
				int bytecode = iCode[pc];
				int span = BytecodeSpan(bytecode);
				if (bytecode == Icode_LINE)
				{
					if (span != 3)
					{
						Kit.CodeBug();
					}
					int line = GetIndex(iCode, pc + 1);
					presentLines.Put(line, 0);
				}
				pc += span;
			}
			return presentLines.GetKeys();
		}
Example #3
0
		/// <summary>Add a method and begin adding code.</summary>
		/// <remarks>
		/// Add a method and begin adding code.
		/// This method must be called before other methods for adding code,
		/// exception tables, etc. can be invoked.
		/// </remarks>
		/// <param name="methodName">the name of the method</param>
		/// <param name="type">a string representing the type</param>
		/// <param name="flags">
		/// the attributes of the field, such as ACC_PUBLIC, etc.
		/// bitwise or'd together
		/// </param>
		public virtual void StartMethod(string methodName, string type, short flags)
		{
			short methodNameIndex = itsConstantPool.AddUtf8(methodName);
			short typeIndex = itsConstantPool.AddUtf8(type);
			itsCurrentMethod = new ClassFileMethod(methodName, methodNameIndex, type, typeIndex, flags);
			itsJumpFroms = new UintMap();
			itsMethods.Add(itsCurrentMethod);
			AddSuperBlockStart(0);
		}
Example #4
0
		/// <summary>
		/// Decompile the source information associated with this js
		/// function/script back into a string.
		/// </summary>
		/// <remarks>
		/// Decompile the source information associated with this js
		/// function/script back into a string.  For the most part, this
		/// just means translating tokens back to their string
		/// representations; there's a little bit of lookahead logic to
		/// decide the proper spacing/indentation.  Most of the work in
		/// mapping the original source to the prettyprinted decompiled
		/// version is done by the parser.
		/// </remarks>
		/// <param name="source">encoded source tree presentation</param>
		/// <param name="flags">flags to select output format</param>
		/// <param name="properties">indentation properties</param>
		public static string Decompile(string source, int flags, UintMap properties)
		{
			int length = source.Length;
			if (length == 0)
			{
				return string.Empty;
			}
			int indent = properties.GetInt(INITIAL_INDENT_PROP, 0);
			if (indent < 0)
			{
				throw new ArgumentException();
			}
			int indentGap = properties.GetInt(INDENT_GAP_PROP, 4);
			if (indentGap < 0)
			{
				throw new ArgumentException();
			}
			int caseGap = properties.GetInt(CASE_GAP_PROP, 2);
			if (caseGap < 0)
			{
				throw new ArgumentException();
			}
			StringBuilder result = new StringBuilder();
			bool justFunctionBody = (0 != (flags & Decompiler.ONLY_BODY_FLAG));
			bool toSource = (0 != (flags & Decompiler.TO_SOURCE_FLAG));
			// Spew tokens in source, for debugging.
			// as TYPE number char
			// Note that tokenToName will fail unless Context.printTrees
			// is true.
			int braceNesting = 0;
			bool afterFirstEOL = false;
			int i = 0;
			int topFunctionType;
			if (source[i] == Token.SCRIPT)
			{
				++i;
				topFunctionType = -1;
			}
			else
			{
				topFunctionType = source[i + 1];
			}
			if (!toSource)
			{
				// add an initial newline to exactly match js.
				result.Append('\n');
				for (int j = 0; j < indent; j++)
				{
					result.Append(' ');
				}
			}
			else
			{
				if (topFunctionType == FunctionNode.FUNCTION_EXPRESSION)
				{
					result.Append('(');
				}
			}
			while (i < length)
			{
				switch ((int)source[i])
				{
					case Token.GET:
					case Token.SET:
					{
						result.Append(source[i] == Token.GET ? "get " : "set ");
						++i;
						i = PrintSourceString(source, i + 1, false, result);
						// Now increment one more to get past the FUNCTION token
						++i;
						break;
					}

					case Token.NAME:
					case Token.REGEXP:
					{
						// re-wrapped in '/'s in parser...
						i = PrintSourceString(source, i + 1, false, result);
						continue;
					}

					case Token.STRING:
					{
						i = PrintSourceString(source, i + 1, true, result);
						continue;
					}

					case Token.NUMBER:
					{
						i = PrintSourceNumber(source, 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
						result.Append("function ");
						break;
					}

					case FUNCTION_END:
					{
						// Do nothing
						break;
					}

					case Token.COMMA:
					{
						result.Append(", ");
						break;
					}

					case Token.LC:
					{
						++braceNesting;
						if (Token.EOL == GetNext(source, length, i))
						{
							indent += indentGap;
						}
						result.Append('{');
						break;
					}

					case Token.RC:
					{
						--braceNesting;
						if (justFunctionBody && braceNesting == 0)
						{
							break;
						}
						result.Append('}');
						switch (GetNext(source, length, i))
						{
							case Token.EOL:
							case FUNCTION_END:
							{
								indent -= indentGap;
								break;
							}

							case Token.WHILE:
							case Token.ELSE:
							{
								indent -= indentGap;
								result.Append(' ');
								break;
							}
						}
						break;
					}

					case Token.LP:
					{
						result.Append('(');
						break;
					}

					case Token.RP:
					{
						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;
						}
						bool newLine = true;
						if (!afterFirstEOL)
						{
							afterFirstEOL = true;
							if (justFunctionBody)
							{
								result.Length = 0;
								indent -= indentGap;
								newLine = false;
							}
						}
						if (newLine)
						{
							result.Append('\n');
						}
						if (i + 1 < length)
						{
							int less = 0;
							int nextToken = source[i + 1];
							if (nextToken == Token.CASE || nextToken == Token.DEFAULT)
							{
								less = indentGap - caseGap;
							}
							else
							{
								if (nextToken == Token.RC)
								{
									less = indentGap;
								}
								else
								{
									if (nextToken == Token.NAME)
									{
										int afterName = GetSourceStringEnd(source, i + 2);
										if (source[afterName] == Token.COLON)
										{
											less = indentGap;
										}
									}
								}
							}
							for (; less < indent; less++)
							{
								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(source, length, i))
						{
							result.Append(' ');
						}
						break;
					}

					case Token.CONTINUE:
					{
						result.Append("continue");
						if (Token.NAME == GetNext(source, 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(source, length, i))
						{
							result.Append(' ');
						}
						break;
					}

					case Token.VAR:
					{
						result.Append("var ");
						break;
					}

					case Token.LET:
					{
						result.Append("let ");
						break;
					}

					case Token.SEMI:
					{
						result.Append(';');
						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(source, 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:
					{
						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.CONST:
					{
						result.Append("const ");
						break;
					}

					case Token.YIELD:
					{
						result.Append("yield ");
						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:
					{
						result.Append("++");
						break;
					}

					case Token.DEC:
					{
						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.DOTQUERY:
					{
						result.Append(".(");
						break;
					}

					case Token.XMLATTR:
					{
						result.Append('@');
						break;
					}

					case Token.DEBUGGER:
					{
						result.Append("debugger;\n");
						break;
					}

					default:
					{
						// If we don't know how to decompile it, raise an exception.
						throw new Exception("Token: " + Token.Name(source[i]));
					}
				}
				++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();
		}