jreversepro.runtime.JRunTimeFrame Maven / Gradle / Ivy
/*
@(#)JRunTimeFrame.java JReversePro - Java Decompiler / Disassembler.
* Copyright (C) 2000 2001 Karthik Kumar.
* EMail: [email protected]
*
* 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 of the License,
* 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.If not, write to
* The Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
package jreversepro.runtime;
import jreversepro.common.Helper;
import jreversepro.common.JJvmOpcodes;
import jreversepro.common.KeyWords;
import jreversepro.parser.ClassParserException;
import jreversepro.reflect.JConstantPool;
import jreversepro.reflect.JImport;
import jreversepro.reflect.JInstruction;
import jreversepro.revengine.BranchConstants;
import jreversepro.revengine.RevEngineException;
import java.util.ArrayList;
import java.util.List;
/**
* This contains the Stack operations of the JVM opcodes.
*
* @author Karthik Kumar
*/
public class JRunTimeFrame implements KeyWords, OperandConstants, BranchConstants, JJvmOpcodes {
/**
* ConstantPool reference
*/
final JConstantPool cpInfo;
/**
* Information related to imported classes.
*/
final JImport importInfo;
/**
* Return type of the method that is decompiled
* currently
*/
final String returnType;
/**
* SymbolTable reference.
*/
final JSymbolTable symLocal;
/**
* Operand of the object invoked. aMainly in the case
* of invokestatic invokespecial invokeinterface
* invokevirtual opcodes.
*/
Operand invokedObject;
/**
* Precedence
*/
int precedence;
/**
* Opcode that was previously examined in this frame.
*/
int prevCode;
/**
* Appends the source code that is necessary for this.
*/
String statement;
/**
* One of the operands in case of a if condition.
*/
String strOp1;
/**
* Second operand in case of a if condition.
*/
String strOp2;
/**
* @param rhsCpInfo ConstantPool Information
* @param rhsSymTable Symbol Table reference.
* @param rhsReturnType Return type of the method.
*/
public JRunTimeFrame(JConstantPool rhsCpInfo, JSymbolTable rhsSymTable, String rhsReturnType) {
cpInfo = rhsCpInfo;
symLocal = rhsSymTable;
returnType = rhsReturnType;
this.importInfo = rhsCpInfo.getImportedClasses();
}
/**
* @return Returns object that is invoked.
*/
public Operand getInvokedObject() {
return invokedObject;
}
/**
* @return Returns Operand 1
*/
public String getOpr1() {
return strOp1;
}
/**
* @return Returns Operand 2.
*/
public String getOpr2() {
return strOp2;
}
/**
* @return Statement that is being appended inside.
*/
public String getStatement() {
return statement;
}
/**
* @param thisIns Current Instruction that is to be
* operated on the JVM stack.
* @param myStack The JVM OperandStack of the current method
* that is under reference.
* @throws RevEngineException Thrown in case we get any error
* while operating the current instruction on the current
* JVM stack.
* @throws ClassParserException Thrown in case of an invalid
* constantpool reference.
*/
public void operateStack(final JInstruction thisIns, JOperandStack myStack)
throws RevEngineException, ClassParserException {
int opcode = thisIns.opcode;
if (opcode >= 0 && opcode < 32) {
opr0to31(thisIns, myStack);
} else if (opcode >= 32 && opcode < 54) {
opr32to53(thisIns, myStack);
} else if (opcode >= 54 && opcode < 87) {
opr54to86(thisIns, myStack);
} else if (opcode >= 87 && opcode < 101) {
opr87to100(thisIns, myStack);
} else if (opcode >= 101 && opcode < 128) {
opr101to127(thisIns, myStack);
} else if (opcode >= 128 && opcode < 148) {
opr128to147(thisIns, myStack);
} else if (opcode >= 148 && opcode < 172) {
opr148to171(thisIns, myStack);
} else if (opcode >= 172 && opcode < 187) {
opr172to186(thisIns, myStack);
} else if (opcode >= 187 && opcode < 202) {
opr187to201(thisIns, myStack);
} else if (opcode >= 202) {
opr202to255(thisIns, myStack);
}
prevCode = opcode;
}
/**
* Executes the JVM Opcodes from 0 - 31
*
* @param thisIns Current Instruction that is to be
* operated on the JVM stack.
* @param myStack The JVM OperandStack of the current method
* that is under reference.
* @throws ClassParserException Thrown in case of any error
* in constantpool reference.
*/
void opr0to31(final JInstruction thisIns, JOperandStack myStack)
throws ClassParserException {
switch (thisIns.opcode) {
case 0: { // null
// Doesn't affect stack.
break;
}
case 1: { // aconst_null
myStack.push(NULL, REFERENCE, VALUE);
break;
}
case 2: // iconst_ml
case 3: // iconst_0
case 4: // iconst_1
case 5: // iconst_2
case 6: // iconst_3
case 7: // iconst_4
case 8: // iconst_5
{
int val = thisIns.opcode - 3;
myStack.push(val, INT, VALUE);
break;
}
case 9: // lconst_0
case 10: // lconst_1
{
int val = thisIns.opcode - 9;
myStack.push(val, LONG, VALUE);
break;
}
case 11: { //fconst_0
myStack.push("0.0", FLOAT, VALUE);
break;
}
case 12: { //fconst_1
myStack.push("1.0", FLOAT, VALUE);
break;
}
case 13: { //fconst_2
myStack.push("2.0", FLOAT, VALUE);
break;
}
case 14: { // dconst_0
myStack.push("0.0", DOUBLE, VALUE);
break;
}
case 15: { //dconst_1
myStack.push("1.0", DOUBLE, VALUE);
break;
}
case 16: { //bipush
myStack.push(thisIns.getArgByte(), BYTE, VALUE);
break;
}
case 17: { //sipush
//Sign Extend This
myStack.push(thisIns.getArgShort(), SHORT, VALUE);
break;
}
case 18: { //ldc
// Utf8 Value is referred to here.
int ldcIndex = thisIns.getArgUnsignedByte();
String ldcString = cpInfo.getLdcString(ldcIndex);
myStack.push(ldcString, cpInfo.getDataType(ldcIndex), VALUE);
break;
}
case 19: { //ldc_w
int ldcIndex = thisIns.getArgUnsignedShort();
myStack.push(cpInfo.getLdcString(ldcIndex), CLASS_STRING, VALUE);
break;
}
case 20: { // ldc2_w
int ldcIndex = thisIns.getArgUnsignedShort();
myStack.push(cpInfo.getCpValue(ldcIndex), cpInfo.getDataType(ldcIndex), VALUE);
break;
}
case 21: { //iload
String localVar = symLocal.getName(thisIns.getArgUnsignedWide(), thisIns.index);
String dataType = symLocal.getDataType(thisIns.getArgUnsignedWide(), thisIns.index);
if (dataType == null) {
dataType = INT;
}
Operand op1 = (myStack.size() == 0) ? null : myStack.peek();
pushVariable(myStack, localVar, dataType, op1);
break;
}
case 22: { //lload
String localVar = symLocal.getName(thisIns.getArgUnsignedWide(), thisIns.index);
myStack.push(localVar, LONG, VALUE);
break;
}
case 23: { //fload
String localVar = symLocal.getName(thisIns.getArgUnsignedWide(), thisIns.index);
myStack.push(localVar, FLOAT, VALUE);
break;
}
case 24: { //dload
String localVar = symLocal.getName(thisIns.getArgUnsignedWide(), thisIns.index);
myStack.push(localVar, DOUBLE, VALUE);
break;
}
case 25: { //aload
String localVar = symLocal.getName(thisIns.getArgUnsignedWide(), thisIns.index);
String localType = symLocal.getDataType(thisIns.getArgUnsignedWide(), thisIns.index);
myStack.push(localVar, localType, VALUE);
break;
}
case 26: // iload_0
case 27: // iload_1
case 28: // iload_2
case 29: // iload_3
{
int regnum = thisIns.opcode - 26;
String localVar = symLocal.getName(regnum, thisIns.index);
String datatype = symLocal.getDataType(regnum, thisIns.index);
if (datatype == null) {
datatype = INT;
}
Operand op1 = (myStack.size() == 0) ? null : myStack.peek();
pushVariable(myStack, localVar, datatype, op1);
break;
}
case 30: // lload_0
case 31: // lload_1
{
int regnum = thisIns.opcode - 30;
String localVar = symLocal.getName(regnum, thisIns.index);
myStack.push(localVar, LONG, VALUE);
break;
}
}
}
/**
* Executes the JVM Opcodes from 32 - 53
*
* @param thisIns Current Instruction that is to be
* operated on the JVM stack.
* @param myStack The JVM OperandStack of the current method
* that is under reference.
*/
void opr32to53(final JInstruction thisIns, JOperandStack myStack) {
switch (thisIns.opcode) {
case 32: { //lload_2
String localVar = symLocal.getName(2, thisIns.index);
myStack.push(localVar, LONG, VALUE);
break;
}
case 33: { //lload_3
String localVar = symLocal.getName(3, thisIns.index);
myStack.push(localVar, LONG, VALUE);
break;
}
case 34: { //fload_0
String localVar = symLocal.getName(0, thisIns.index);
myStack.push(localVar, FLOAT, VALUE);
break;
}
case 35: { //fload_1
String localVar = symLocal.getName(1, thisIns.index);
myStack.push(localVar, FLOAT, VALUE);
break;
}
case 36: { //fload_2
String localVar = symLocal.getName(2, thisIns.index);
myStack.push(localVar, FLOAT, VALUE);
break;
}
case 37: { //fload_3
String localVar = symLocal.getName(3, thisIns.index);
myStack.push(localVar, FLOAT, VALUE);
break;
}
case 38: { //dload_0
String localVar = symLocal.getName(0, thisIns.index);
myStack.push(localVar, DOUBLE, VALUE);
break;
}
case 39: { //dload_1
String localVar = symLocal.getName(1, thisIns.index);
myStack.push(localVar, DOUBLE, VALUE);
break;
}
case 40: { //dload_2
String localVar = symLocal.getName(2, thisIns.index);
myStack.push(localVar, DOUBLE, VALUE);
break;
}
case 41: { //dload_3
String localVar = symLocal.getName(3, thisIns.index);
myStack.push(localVar, DOUBLE, VALUE);
break;
}
case 42: { //aload_0
String localVar = symLocal.getName(0, thisIns.index);
String localType = symLocal.getDataType(0, thisIns.index);
myStack.push(localVar, localType, VALUE);
break;
}
case 43: { //aload_1
String localVar = symLocal.getName(1, thisIns.index);
String localType = symLocal.getDataType(1, thisIns.index);
myStack.push(localVar, localType, VALUE);
break;
}
case 44: { //aload_2
String localVar = symLocal.getName(2, thisIns.index);
String localType = symLocal.getDataType(2, thisIns.index);
myStack.push(localVar, localType, VALUE);
break;
}
case 45: { //aload_3
String localVar = symLocal.getName(3, thisIns.index);
String localType = symLocal.getDataType(3, thisIns.index);
myStack.push(localVar, localType, VALUE);
break;
}
case 46: { //iaload
Operand op2 = myStack.pop();
Operand op1 = myStack.pop();
myStack.push(op1.getValue() + "[" + op2.getValue() + "]", INT, VALUE);
break;
}
case 47: { //laload
Operand op2 = myStack.pop();
Operand op1 = myStack.pop();
myStack.push(op1.getValue() + OPEN_BRACKET + op2.getValue() + CLOSE_BRACKET, LONG, VALUE);
break;
}
case 48: { //faload
Operand op2 = myStack.pop();
Operand op1 = myStack.pop();
myStack.push(op1.getValue() + OPEN_BRACKET + op2.getValue() + CLOSE_BRACKET, FLOAT, VALUE);
break;
}
case 49: { //daload
Operand op2 = myStack.pop();
Operand op1 = myStack.pop();
myStack.push(op1.getValue() + OPEN_BRACKET + op2.getValue() + CLOSE_BRACKET, DOUBLE, VALUE);
break;
}
case 50: { //aaload
Operand op2 = myStack.pop();
Operand op1 = myStack.pop();
myStack.push(op1.getValue() + OPEN_BRACKET + op2.getValue() + CLOSE_BRACKET, REFERENCE, VALUE);
break;
}
case 51: { //baload
Operand op2 = myStack.pop();
Operand op1 = myStack.pop();
myStack.push(op1.getValue() + OPEN_BRACKET + op2.getValue() + CLOSE_BRACKET, BOOLEAN, VALUE);
// byte only
break;
}
case 52: { //caload
Operand op2 = myStack.pop();
Operand op1 = myStack.pop();
myStack.push(op1.getValue() + OPEN_BRACKET + op2.getValue() + CLOSE_BRACKET, CHAR, VALUE);
break;
}
case 53: { //saload
Operand op2 = myStack.pop();
Operand op1 = myStack.pop();
myStack.push(op1.getValue() + OPEN_BRACKET + op2.getValue() + CLOSE_BRACKET, SHORT, VALUE);
break;
}
}
}
/**
* Executes the JVM Opcodes from 54 - 86
*
* @param thisIns Current Instruction that is to be
* operated on the JVM stack.
* @param myStack The JVM OperandStack of the current method
* that is under reference.
*/
void opr54to86(final JInstruction thisIns, JOperandStack myStack) {
switch (thisIns.opcode) {
case 54: // istore
{
Operand op1 = myStack.pop();
dealIntegerStore(op1.getValue(), thisIns.getArgUnsignedWide(), thisIns.index);
break;
}
case 55: // lstore
case 56: // fstore
case 57: // dstore
{
String localVar = symLocal.getName(thisIns.getArgUnsignedWide(), thisIns.index);
Operand op1 = myStack.pop();
statement = localVar + " = " + op1.getValue();
precedence = L_EVAL;
break;
}
case 58: // astore
{
Operand op1 = myStack.pop();
String localVar = symLocal.getName(thisIns.getArgUnsignedWide(), thisIns.index);
String varValue = op1.getValue();
if (op1.getDatatype().contains("[")) {
List constants = myStack.getConstants();
if (constants.size() != 0) {
varValue = myStack.getConstantValues();
myStack.removeAllConstants();
}
}
statement = localVar + " = " + varValue;
precedence = L_EVAL;
break;
}
case 59: // istore_0
{
Operand op1 = myStack.pop();
dealIntegerStore(op1.getValue(), 0, thisIns.index);
break;
}
case 63: // lstore_0
case 67: // fstore_0
case 71: // dstore_0
case 75: // astore_0
{
String localVar = symLocal.getName(0, thisIns.index);
Operand op1 = myStack.pop();
statement = localVar + " = " + op1.getValue();
precedence = L_EVAL;
break;
}
case 60: // istore_1
{
Operand op1 = myStack.pop();
dealIntegerStore(op1.getValue(), 1, thisIns.index);
break;
}
case 64: // lstore_1
case 68: // fstore_1
case 72: // dstore_1
case 76: // astore_1
{
String localVar = symLocal.getName(1, thisIns.index);
Operand op1 = myStack.pop();
statement = localVar + " = " + op1.getValue();
precedence = L_EVAL;
break;
}
case 61: // istore_2
{
Operand op1 = myStack.pop();
dealIntegerStore(op1.getValue(), 2, thisIns.index);
break;
}
case 65: // lstore_2
case 69: // fstore_2
case 73: // dstore_2
case 77: // astore_2
{
String localVar = symLocal.getName(2, thisIns.index);
Operand op1 = myStack.pop();
statement = localVar + " = " + op1.getValue();
precedence = L_EVAL;
break;
}
case 62: // istore_3
{
Operand op1 = myStack.pop();
dealIntegerStore(op1.getValue(), 3, thisIns.index);
break;
}
case 66: // lstore_3
case 70: // fstore_3
case 74: // dstore_3
case 78: // astore_3
{
String localVar = symLocal.getName(3, thisIns.index);
Operand op1 = myStack.pop();
statement = localVar + " = " + op1.getValue();
precedence = L_EVAL;
break;
}
case 79: // iastore
case 80: // lastore
case 81: // fastore
case 82: // dastore
case 83: // aastore
case 84: // bastore
case 85: // castore
case 86: // sastore
{
Operand op3 = myStack.pop();
Operand op2 = myStack.pop();
Operand op1 = myStack.pop();
String value = op3.getValue();
String index = op2.getValue();
String arrayRef = op1.getValue();
if (!arrayRef.contains("new")) {
statement = arrayRef + OPEN_BRACKET + index + CLOSE_BRACKET + EQUALTO + value;
} else {
statement = "";
myStack.addConstant(value);
}
precedence = L_EVAL;
break;
}
}
}
/**
* Executes the JVM Opcodes from 87 - 100
*
* @param thisIns Current Instruction that is to be
* operated on the JVM stack.
* @param myStack The JVM OperandStack of the current method
* that is under reference.
*/
@SuppressWarnings("Duplicates")
void opr87to100(final JInstruction thisIns, JOperandStack myStack) {
switch (thisIns.opcode) {
case OPCODE_POP: { //pop
Operand op1 = myStack.pop();
String popVal = op1.getValue();
if (popVal != null && !popVal.equals(FOREIGN_OBJ)) {
statement = popVal;
precedence = op1.getPrecedence();
} else {
statement = "";
precedence = VALUE;
}
break;
}
case OPCODE_POP2: { //pop2
//To Assess its use properly.
Operand op1 = myStack.pop();
if (op1.isCategory1()) {
//noinspection UnusedAssignment
op1 = myStack.pop();
}
break;
}
case OPCODE_DUP: { //dup
myStack.push(myStack.peek());
break;
}
case OPCODE_DUP_X1: { //dup_x1
Operand op1 = myStack.pop();
Operand op2 = myStack.pop();
myStack.push(op1);
myStack.push(op2);
myStack.push(op1);
break;
}
case OPCODE_DUP_X2: { // dup_x2
Operand op1 = myStack.pop();
Operand op2 = myStack.pop();
if (op2.isCategory1()) {
// Cat.1
Operand op3 = myStack.pop();
myStack.push(op1);
myStack.push(op3);
} else {
// Cat.2
myStack.push(op1);
}
myStack.push(op2);
myStack.push(op1);
break;
}
case 92: { // dup2
Operand op1 = myStack.pop();
if (op1.isCategory1()) {
// Cat.1
Operand op2 = myStack.pop();
myStack.push(op2);
myStack.push(op1);
myStack.push(op2);
} else {
// Cat.2
myStack.push(op1);
}
myStack.push(op1);
break;
}
case 93: { //dup2_x1
Operand op1 = myStack.pop();
Operand op2 = myStack.pop();
if (op1.isCategory1()) {
// Cat.1
Operand op3 = myStack.pop();
myStack.push(op2);
myStack.push(op1);
myStack.push(op3);
} else {
// Cat.2
myStack.push(op1);
}
myStack.push(op2);
myStack.push(op1);
break;
}
case 94: { //dup2_x2
Operand op1 = myStack.pop();
Operand op2 = myStack.pop();
if (op1.isCategory1()) {
// value1-Cat1
Operand op3 = myStack.pop();
if (op2.isCategory1()) {
// value2-Cat1
Operand op4 = myStack.pop();
myStack.push(op2);
myStack.push(op1);
myStack.push(op4);
// Form 1.
} else {
// value2-Cat2
myStack.push(op2);
myStack.push(op1);
// Form. 3
}
myStack.push(op3);
} else {
// value1-Cat2
pushOperands(myStack, op1, op2);
}
myStack.push(op2);
myStack.push(op1);
break;
}
case 95: { //swap
Operand op1 = myStack.pop();
Operand op2 = myStack.pop();
myStack.push(op1);
myStack.push(op2);
break;
}
case 96: { //iadd
Operand op2 = myStack.pop();
Operand op1 = myStack.pop();
myStack.push(op1.getValueEx(L_ADD) + " + " + op2.getValueEx(L_ADD), INT, L_ADD);
break;
}
case 97: { //ladd
Operand op2 = myStack.pop();
Operand op1 = myStack.pop();
myStack.push(op1.getValueEx(L_ADD) + " + " + op2.getValueEx(L_ADD), LONG, L_ADD);
break;
}
case 98: { //fadd
Operand op2 = myStack.pop();
Operand op1 = myStack.pop();
myStack.push(op1.getValueEx(L_ADD) + " + " + op2.getValueEx(L_ADD), FLOAT, L_ADD);
break;
}
case 99: { //dadd
Operand op2 = myStack.pop();
Operand op1 = myStack.pop();
myStack.push(op1.getValueEx(L_ADD) + " + " + op2.getValueEx(L_ADD), DOUBLE, L_ADD);
break;
}
case 100: { //isub
Operand op2 = myStack.pop();
Operand op1 = myStack.pop();
myStack.push(op1.getValueEx(L_SUB) + " - " + op2.getValueEx(L_SUB + 1), INT, L_SUB);
break;
}
}
}
/**
* Executes the JVM Opcodes from 101 - 127
*
* @param thisIns Current Instruction that is to be
* operated on the JVM stack.
* @param myStack The JVM OperandStack of the current method
* that is under reference.
*/
void opr101to127(final JInstruction thisIns, JOperandStack myStack) {
switch (thisIns.opcode) {
case 101: { //lsub
Operand op2 = myStack.pop();
Operand op1 = myStack.pop();
myStack.push(op1.getValueEx(L_SUB) + " - " + op2.getValueEx(L_SUB + 1), LONG, L_SUB);
break;
}
case 102: { //fsub
Operand op2 = myStack.pop();
Operand op1 = myStack.pop();
myStack.push(op1.getValueEx(L_SUB) + " - " + op2.getValueEx(L_SUB + 1), FLOAT, L_SUB);
break;
}
case 103: { //dsub
Operand op2 = myStack.pop();
Operand op1 = myStack.pop();
myStack.push(op1.getValueEx(L_SUB) + " - " + op2.getValueEx(L_SUB + 1), DOUBLE, L_SUB);
break;
}
case 104: { //imul
Operand op2 = myStack.pop();
Operand op1 = myStack.pop();
myStack.push(op1.getValueEx(L_MUL) + " * " + op2.getValueEx(L_MUL), INT, L_MUL);
break;
}
case 105: { //lmul
Operand op2 = myStack.pop();
Operand op1 = myStack.pop();
myStack.push(op1.getValueEx(L_MUL) + " * " + op2.getValueEx(L_MUL), LONG, L_MUL);
break;
}
case 106: { //fmul
Operand op2 = myStack.pop();
Operand op1 = myStack.pop();
myStack.push(op1.getValueEx(L_MUL) + " * " + op2.getValueEx(L_MUL), FLOAT, L_MUL);
break;
}
case 107: { //dmul
Operand op2 = myStack.pop();
Operand op1 = myStack.pop();
myStack.push(op1.getValueEx(L_MUL) + " * " + op2.getValueEx(L_MUL), DOUBLE, L_MUL);
break;
}
case 108: { //idiv
Operand op2 = myStack.pop();
Operand op1 = myStack.pop();
myStack.push(op1.getValueEx(L_DIV) + " / " + op2.getValueEx(L_DIV), INT, L_DIV);
break;
}
case 109: { //ldiv
Operand op2 = myStack.pop();
Operand op1 = myStack.pop();
myStack.push(op1.getValueEx(L_DIV) + " / " + op2.getValueEx(L_DIV), LONG, L_DIV);
break;
}
case 110: { //fdiv
Operand op2 = myStack.pop();
Operand op1 = myStack.pop();
myStack.push(op1.getValueEx(L_DIV) + " / " + op2.getValueEx(L_DIV), FLOAT, L_DIV);
break;
}
case 111: { //ddiv
Operand op2 = myStack.pop();
Operand op1 = myStack.pop();
myStack.push(op1.getValueEx(L_DIV) + " / " + op2.getValueEx(L_DIV), DOUBLE, L_DIV);
break;
}
case 112: { //irem
Operand op2 = myStack.pop();
Operand op1 = myStack.pop();
myStack.push(op1.getValueEx(L_MOD) + " % " + op2.getValueEx(L_MOD), INT, L_MOD);
break;
}
case 113: { //lrem
Operand op2 = myStack.pop();
Operand op1 = myStack.pop();
myStack.push(op1.getValueEx(L_MOD) + " % " + op2.getValueEx(L_MOD), LONG, L_MOD);
break;
}
case 114: { //frem
Operand op2 = myStack.pop();
Operand op1 = myStack.pop();
myStack.push(op1.getValueEx(L_MOD) + " % " + op2.getValueEx(L_MOD), FLOAT, L_MOD);
break;
}
case 115: { //drem
Operand op2 = myStack.pop();
Operand op1 = myStack.pop();
myStack.push(op1.getValueEx(L_MOD) + " % " + op2.getValueEx(L_MOD), DOUBLE, L_MOD);
break;
}
case 116: { //ineg
Operand op1 = myStack.pop();
myStack.push("-" + op1.getValueEx(L_UNARY), INT, L_UNARY);
break;
}
case 117: { //lneg
Operand op1 = myStack.pop();
myStack.push("-" + op1.getValueEx(L_UNARY), LONG, L_UNARY);
break;
}
case 118: { //fneg
Operand op1 = myStack.pop();
myStack.push("-" + op1.getValueEx(L_UNARY), FLOAT, L_UNARY);
break;
}
case 119: { //dneg
Operand op1 = myStack.pop();
myStack.push("-" + op1.getValueEx(L_UNARY), DOUBLE, L_UNARY);
break;
}
case 120: { // ishl
Operand op2 = myStack.pop();
Operand op1 = myStack.pop();
myStack.push(op1.getValueEx(L_SHIFT) + "<<" + op2.getValueEx(L_SHIFT), INT, L_SHIFT);
break;
}
case 121: { // lshl
Operand op2 = myStack.pop();
Operand op1 = myStack.pop();
myStack.push(op1.getValueEx(L_SHIFT) + "<<" + op2.getValueEx(L_SHIFT), LONG, L_SHIFT);
break;
}
case 122: // ishr
case 124: // iushr
{
Operand op2 = myStack.pop();
Operand op1 = myStack.pop();
myStack.push(op1.getValueEx(L_SHIFT) + ">>" + op2.getValueEx(L_SHIFT), INT, L_SHIFT);
break;
}
case 123: // lshr
case 125: // lushr
{
Operand op2 = myStack.pop();
Operand op1 = myStack.pop();
myStack.push(op1.getValueEx(L_SHIFT) + ">>" + op2.getValueEx(L_SHIFT), LONG, L_SHIFT);
break;
}
case 126: { //iand
Operand op2 = myStack.pop();
Operand op1 = myStack.pop();
myStack.push(op1.getValueEx(L_BITAND) + " & " + op2.getValueEx(L_BITAND), INT, L_BITAND);
break;
}
case 127: { //land
Operand op2 = myStack.pop();
Operand op1 = myStack.pop();
myStack.push(op1.getValueEx(L_BITAND) + " & " + op2.getValueEx(L_BITAND), LONG, L_BITAND);
break;
}
}
}
/**
* Executes the JVM Opcodes from 128 - 147
*
* @param thisIns Current Instruction that is to be
* operated on the JVM stack.
* @param myStack The JVM OperandStack of the current method
* that is under reference.
*/
void opr128to147(final JInstruction thisIns, JOperandStack myStack) {
switch (thisIns.opcode) {
case 128: { //ior
Operand op2 = myStack.pop();
Operand op1 = myStack.pop();
myStack.push(op1.getValueEx(L_BITOR) + " | " + op2.getValueEx(L_BITOR), INT, L_BITOR);
break;
}
case 129: { //lor
Operand op2 = myStack.pop();
Operand op1 = myStack.pop();
myStack.push(op1.getValueEx(L_BITOR) + " | " + op2.getValueEx(L_BITOR), LONG, L_BITOR);
break;
}
case 130: { //ixor
Operand op2 = myStack.pop();
Operand op1 = myStack.pop();
myStack.push(op1.getValueEx(L_BITXOR) + " ^ " + op2.getValueEx(L_BITXOR), INT, L_BITXOR);
break;
}
case 131: { //lxor
Operand op2 = myStack.pop();
Operand op1 = myStack.pop();
myStack.push(op1.getValueEx(L_BITXOR) + " ^ " + op2.getValueEx(L_BITXOR), LONG, L_BITXOR);
break;
}
case 132: //iinc
String localVar = symLocal.getName(thisIns.getArgUnsignedWide(), thisIns.index);
int constant = thisIns.getArgWide(1);
if (constant == -1) {
Operand op1 = (myStack.size() == 0) ? null : myStack.peek();
if (op1 != null) {
if (op1.getValue().equals(localVar)) {
op1 = myStack.pop();
myStack.push(op1.getValueEx(L_UNARY) + "--", INT, L_UNARY);
} else {
myStack.push("--", INT, L_UNARY);
}
statement = "";
precedence = VALUE;
} else {
statement = localVar + "--";
precedence = L_UNARY;
}
} else if (constant == 1) {
Operand op1 = (myStack.size() == 0) ? null : myStack.peek();
if (op1 != null) {
if (op1.getValue().equals(localVar)) {
op1 = myStack.pop();
myStack.push(op1.getValueEx(L_UNARY) + "++", INT, L_UNARY);
} else {
myStack.push("++", INT, L_UNARY);
}
statement = "";
precedence = VALUE;
} else {
statement = localVar + "++";
precedence = L_UNARY;
}
} else if (constant < 0) {
statement = localVar + " -= " + (-constant);
precedence = L_EVAL;
} else {
statement = localVar + " += " + constant;
precedence = L_EVAL;
}
break;
case 133: // i2l
case 140: // f2l
case 143: // d2l
{
Operand op1 = myStack.pop();
myStack.push("(long)" + op1.getValueEx(L_CAST), LONG, L_CAST);
break;
}
case 134: // i2f
case 137: // l2f
case 144: // d2f
{
Operand op1 = myStack.pop();
myStack.push("(float)" + op1.getValueEx(L_CAST), FLOAT, L_CAST);
break;
}
case 135: // i2d
case 138: // l2d
case 141: // f2d
{
Operand op1 = myStack.pop();
myStack.push("(double)" + op1.getValueEx(L_CAST), DOUBLE, L_CAST);
break;
}
case 136: // l2i
case 139: // f2i
case 142: // d2i
{
Operand op1 = myStack.pop();
myStack.push("(int)" + op1.getValueEx(L_CAST), INT, L_CAST);
break;
}
case 145: // i2b
{
Operand op1 = myStack.pop();
myStack.push("(byte)" + op1.getValueEx(L_CAST), BYTE, L_CAST);
break;
}
case 146: // i2c
{
Operand op1 = myStack.pop();
myStack.push("(char)" + op1.getValueEx(L_CAST), CHAR, L_CAST);
break;
}
case 147: { // i2s
Operand op1 = myStack.pop();
myStack.push("(short)" + op1.getValueEx(L_CAST), SHORT, L_CAST);
break;
}
}
}
/**
* Executes the JVM Opcodes from 148 - 171
*
* @param thisIns Current Instruction that is to be
* operated on the JVM stack.
* @param myStack The JVM OperandStack of the current method
* that is under reference.
*/
void opr148to171(final JInstruction thisIns, JOperandStack myStack) {
switch (thisIns.opcode) {
case 148: // lcmp
case 149: // fcmpl
case 150: // fcmpg
case 151: // dcmpl
case 152: // dcmpg
{
Operand op2 = myStack.pop();
Operand op1 = myStack.pop();
strOp1 = op1.getValue();
strOp2 = op2.getValue();
myStack.push("1", INT, VALUE);
// Value being pushed here is irrelevant
// But the data Type is.
break;
}
case 153: { // if_eq
Operand op1 = myStack.pop();
statement = OPR_EQ;
precedence = L_LOGEQ;
if (prevCode < 148 || prevCode > 152) {
// To be compared with 0
strOp1 = op1.getValue();
strOp2 = Helper.getValue("0", op1.getDatatype());
}
break;
}
case 154: { // if_ne
Operand op1 = myStack.pop();
statement = OPR_NE;
precedence = L_LOGNEQ;
if (prevCode < 148 || prevCode > 152) {
// To be compared with 0
strOp1 = op1.getValue();
strOp2 = Helper.getValue("0", op1.getDatatype());
}
break;
}
case 155: { // if_lt
Operand op1 = myStack.pop();
statement = OPR_LT;
precedence = L_LOGREL;
if (prevCode < 148 || prevCode > 152) {
// To be compared with 0
strOp1 = op1.getValue();
strOp2 = "0";
}
break;
}
case 156: { // if_ge
Operand op1 = myStack.pop();
statement = OPR_GE;
precedence = L_LOGREL;
if (prevCode < 148 || prevCode > 152) {
// To be compared with 0
strOp1 = op1.getValue();
strOp2 = "0";
}
break;
}
case 157: { // if_gt
Operand op1 = myStack.pop();
statement = OPR_GT;
precedence = L_LOGREL;
if (prevCode < 148 || prevCode > 152) {
// To be compared with 0
strOp1 = op1.getValue();
strOp2 = "0";
}
break;
}
case 158: { // if_le
Operand op1 = myStack.pop();
statement = OPR_LE;
precedence = L_LOGREL;
if (prevCode < 148 || prevCode > 152) {
// To be compared with 0
strOp1 = op1.getValue();
strOp2 = "0";
}
break;
}
case 159: // if_icmpeq
{
Operand op2 = myStack.pop();
Operand op1 = myStack.pop();
strOp1 = op1.getValue();
strOp2 = Helper.getValue(op2.getValue(), op1.getDatatype());
statement = OPR_EQ;
precedence = L_LOGEQ;
break;
}
case 165: // if_acmpeq
{
Operand op2 = myStack.pop();
Operand op1 = myStack.pop();
strOp2 = op2.getValue();
strOp1 = op1.getValue();
statement = OPR_EQ;
precedence = L_LOGEQ;
break;
}
case 160: // if_icmpne
{
Operand op2 = myStack.pop();
Operand op1 = myStack.pop();
strOp1 = op1.getValue();
strOp2 = Helper.getValue(op2.getValue(), op1.getDatatype());
statement = OPR_NE;
precedence = L_LOGNEQ;
break;
}
case 166: // if_acmpne
{
Operand op2 = myStack.pop();
Operand op1 = myStack.pop();
strOp2 = op2.getValue();
strOp1 = op1.getValue();
statement = OPR_NE;
precedence = L_LOGNEQ;
break;
}
case 161: { // if_icmplt
Operand op2 = myStack.pop();
Operand op1 = myStack.pop();
strOp2 = op2.getValue();
strOp1 = op1.getValue();
statement = OPR_LT;
precedence = L_LOGREL;
break;
}
case 162: { // if_icmpge
Operand op2 = myStack.pop();
Operand op1 = myStack.pop();
strOp2 = op2.getValue();
strOp1 = op1.getValue();
statement = OPR_GE;
precedence = L_LOGREL;
break;
}
case 163: { // if_icmpgt
Operand op2 = myStack.pop();
Operand op1 = myStack.pop();
strOp2 = op2.getValue();
strOp1 = op1.getValue();
statement = OPR_GT;
precedence = L_LOGREL;
break;
}
case 164: { // if_icmple
Operand op2 = myStack.pop();
Operand op1 = myStack.pop();
strOp2 = op2.getValue();
strOp1 = op1.getValue();
statement = OPR_LE;
precedence = L_LOGREL;
break;
}
case 167: // goto
//No Change to stack
break;
case 168:
case 169: { // jsr
// Address of the immediately following instruction
/*
myStack.push(String.valueOf(thisIns.index +3) ,
RET_ADDR);
*/
// Represents finally
break;
}// ret
// No change
case 170: // tableswitch
case 171: // lookupswitch
{
Operand op1 = myStack.pop();
strOp1 = op1.getValue();
break;
}
}
}
/**
* Executes the JVM Opcodes from 172- 186
*
* @param thisIns Current Instruction that is to be
* operated on the JVM stack.
* @param myStack The JVM OperandStack of the current method
* that is under reference.
* @throws RevEngineException Thrown in case we get any error
* while operating the current instruction on the current
* JVM stack.
*/
void opr172to186(final JInstruction thisIns, JOperandStack myStack)
throws RevEngineException {
switch (thisIns.opcode) {
case 172: //ireturn
{
Operand op1 = myStack.pop();
statement = RETURN + " (" + Helper.getValue(op1.getValue(), returnType) + ")";
precedence = VALUE;
break;
}
case 173: //lreturn
case 174: //freturn
case 175: //dreturn
case 176: //areturn
{
Operand op1 = myStack.pop();
statement = RETURN + " (" + op1.getValue() + ")";
precedence = VALUE;
break;
}
case 177: { //return
// Make the stack empty here
statement = RETURN;
precedence = VALUE;
break;
}
case 178: { //getstatic
int offset = thisIns.getArgUnsignedShort();
int classPtr = cpInfo.getPtr1(offset);
int fieldPtr = cpInfo.getPtr2(offset);
String classType = Helper.getJavaDataType(cpInfo.getClassName(classPtr), false);
classType = JImport.getClassName(classType);
String fieldName = cpInfo.getFieldName(fieldPtr);
String fieldType = cpInfo.getFieldType(fieldPtr);
// FieldType = Helper.formatDataType(FieldType);
myStack.push(classType + "." + fieldName, fieldType, VALUE);
break;
}
case 179: { // putstatic
int offset = thisIns.getArgUnsignedShort();
int classPtr = cpInfo.getPtr1(offset);
int fieldPtr = cpInfo.getPtr2(offset);
String classType = Helper.getJavaDataType(cpInfo.getClassName(classPtr), false);
classType = JImport.getClassName(classType);
String fieldName = cpInfo.getFieldName(fieldPtr);
Operand op1 = myStack.pop();
statement = classType + "." + fieldName + " = " + op1.getValueEx(L_EVAL);
precedence = L_EVAL;
break;
}
case 180: { // getfield
Operand op1 = myStack.pop();
String objName = op1.getValue();
int offset = thisIns.getArgUnsignedShort();
int fieldPtr = cpInfo.getPtr2(offset);
String fieldName = cpInfo.getFieldName(fieldPtr);
String fieldType = cpInfo.getFieldType(fieldPtr);
//Field Name and Type respectively
if (objName.equals(THIS)) {
myStack.push(fieldName, fieldType, VALUE);
} else {
myStack.push(objName + "." + fieldName, fieldType, VALUE);
}
break;
}
case 181: { // putfield
// End of an instruction
Operand op2 = myStack.pop();
Operand op1 = myStack.pop();
String fieldValue = op2.getValue();
String objname = op1.getValue();
int offset = thisIns.getArgUnsignedShort();
int fieldPtr = cpInfo.getPtr2(offset);
String fieldName = cpInfo.getFieldName(fieldPtr);
String fieldType = cpInfo.getFieldType(fieldPtr);
if (objname.equals(THIS)) {
statement = fieldName + " = " + Helper.getValue(fieldValue, fieldType);
} else {
statement = objname + "." + fieldName + " = " + Helper.getValue(fieldValue, fieldType);
}
precedence = L_EVAL;
break;
}
case 182: // invokevirtual
case 185: // invokeinterface
{
processInvokeInstruction(thisIns, myStack, false);
break;
}
case 183: { // invokespecial
processInvokeInstruction(thisIns, myStack, true);
break;
}
case 184: { //invokestatic
int offset = thisIns.getArgUnsignedShort();
int classIndex = cpInfo.getPtr1(offset);
String classType = JImport.getClassName(cpInfo.getClassName(classIndex));
// GetMethodName
int nameIndex = cpInfo.getPtr2(offset);
String methodName = cpInfo.getFirstDirectName(nameIndex);
// Get No: of arguments
int argsIndex = cpInfo.getPtr2(nameIndex);
String argsList = cpInfo.getCpValue(argsIndex);
List args = Helper.getArguments(argsList);
int popMax = args.size();
String methodType = Helper.getReturnType(argsList);
// Get Return type
List argValues = new ArrayList<>(popMax);
for (int i = popMax - 1; i >= 0; i--) {
argValues.add(0, myStack.pop().getValue());
}
statement = classType + "." + methodName + getArgValues(args, argValues);
precedence = L_REF;
if (!methodType.equals(JVM_VOID)) {
myStack.push(statement, methodType, VALUE);
}
break;
}
case 186: {
// UnUsed
throw new RevEngineException("Opcode 186 unused");
}
}
}
/**
* Executes the JVM Opcodes from 187 - 201
*
* @param thisIns Current Instruction that is to be
* operated on the JVM stack.
* @param myStack The JVM OperandStack of the current method
* that is under reference.
*/
void opr187to201(final JInstruction thisIns, JOperandStack myStack) {
switch (thisIns.opcode) {
case 187: { //new
int offset = thisIns.getArgUnsignedShort();
String classType = cpInfo.getClassName(offset);
String className = JImport.getClassName(Helper.getJavaDataType(classType, false));
myStack.push("new " + className, classType, L_REF);
break;
}
case 188: { // newarray
int atype = thisIns.getArgByte();
Operand op1 = myStack.pop();
String count = op1.getValue();
switch (atype) {
case 4: {
myStack.push("new boolean[" + count + "]", "[Z", L_REF);
break;
}
case 5: {
myStack.push("new char[" + count + "]", "[C", L_REF);
break;
}
case 6: {
myStack.push("new float[" + count + "]", "[F", L_REF);
break;
}
case 7: {
myStack.push("new double[" + count + "]", "[D", L_REF);
break;
}
case 8: {
myStack.push("new byte[" + count + "]", "[B", L_REF);
break;
}
case 9: {
myStack.push("new short[" + count + "]", "[S", L_REF);
break;
}
case 10: {
myStack.push("new int[" + count + "]", "[I", L_REF);
break;
}
case 11: {
myStack.push("new long[" + count + "]", "[J", L_REF);
break;
}
}
break;
}
case 189: { // anewarray
int offset = thisIns.getArgUnsignedShort();
String classType = cpInfo.getClassName(offset);
String className = JImport.getClassName(Helper.getJavaDataType(classType, true));
//Get Class Name
Operand op1 = myStack.pop();
String count = op1.getValue();
myStack.push("new " + className + "[" + count + "]", classType, L_REF);
break;
}
case 190: { //arraylength
Operand op1 = myStack.pop();
myStack.push(op1.getValueEx(L_REF) + "." + LENGTH, INT, VALUE);
break;
}
case 191: { //athrow
Operand op1 = myStack.pop();
statement = THROW + " " + op1.getValueEx(L_REF);
precedence = L_REF;
// No Change
break;
}
case 192: { //checkcast
int offset = thisIns.getArgUnsignedShort();
//Get Class Name
Operand op1 = myStack.pop();
String castType = cpInfo.getClassName(offset);
String javaCastType = JImport.getClassName(Helper.getJavaDataType(castType, false));
String value = "(" + javaCastType + ")";
value = value + op1.getValueEx(L_CAST);
myStack.push(value, castType, L_CAST);
//No Change to JVM Stack
break;
}
case 193: { // instanceof
Operand op1 = myStack.pop();
int offset = thisIns.getArgUnsignedShort();
// Class Type found here
String classType = Helper.getJavaDataType(cpInfo.getClassName(offset), false);
classType = JImport.getClassName(classType);
myStack.push(op1.getValue() + SPACE + INSTANCEOF + SPACE + classType, BOOLEAN, L_LOGIOF);
break;
}
case 194: // monitorenter
case 195: // monitorexit
{
Operand op1 = myStack.pop();
statement = op1.getValue();
precedence = VALUE;
break;
}
case 196:
case 201:
case 200: { //wide -doesn't affect stack
// wide ignore it
break;
}
case 197: { //multianewarray
int offset = thisIns.getArgUnsignedShort();
// Dimensions. Max 255.
int dimensions = thisIns.getArgUnsignedByte(2);
String[] strIndex = new String[dimensions];
// ClassType
String classType = Helper.getJavaDataType(cpInfo.getClassName(offset), false);
classType = JImport.getClassName(classType);
// For Output
for (int i = dimensions - 1; i >= 0; i--) {
strIndex[i] = myStack.pop().getValue();
}
StringBuilder arrayIndex = new StringBuilder();
arrayIndex.append(NEW + SPACE).append(classType);
StringBuilder arrayType = new StringBuilder();
for (int i = 0; i < dimensions; i++) {
arrayIndex.append("[ ").append(strIndex[i]).append(" ]");
arrayType.append("[");
}
statement = arrayIndex.toString();
precedence = L_REF;
myStack.push(arrayIndex.toString(), arrayType.append("L").append(classType).toString(), L_REF);
break;
}
case 198: { //ifnull
Operand op1 = myStack.pop();
strOp1 = op1.getValue();
strOp2 = NULL;
statement = OPR_EQ;
precedence = L_LOGEQ;
break;
}
case 199: { //ifnonnull
Operand op1 = myStack.pop();
strOp1 = op1.getValue();
strOp2 = NULL;
statement = OPR_NE;
precedence = L_LOGNEQ;
break;
}//goto_w
//No Change to stack
//jsr_w
// Represents finally
}// End of switch
}
/**
* Executes the JVM Opcodes from 200- 255.
* Currently not supported by JVM spec since this contains
* quick variables and hence not to be supported.
*
* @param thisIns Current Instruction that is to be
* operated on the JVM stack.
* @param myStack The JVM OperandStack of the current method
* that is under reference.
* @throws RevEngineException Thrown in case we get any error
* while operating the current instruction on the current
* JVM stack.
*/
void opr202to255(final JInstruction thisIns, JOperandStack myStack)
throws RevEngineException {
throw new RevEngineException("OpCode not allowed in a valid class file");
}
private void pushVariable(JOperandStack myStack, String localVar, String datatype, Operand op1) {
if (op1 != null && (op1.getValue().equals("++") || op1.getValue().equals("--"))) {
op1 = myStack.pop();
localVar = op1.getValue() + localVar;
myStack.push(localVar, datatype, L_UNARY);
} else {
myStack.push(localVar, datatype, VALUE);
}
}
/**
* @param popValue Value popped from stack
* @param intIndex Index of the integer variable onto the
* symbol table.
* @param insIndex Instruction Index
*/
private void dealIntegerStore(String popValue, int intIndex, int insIndex) {
String localVar = symLocal.getName(intIndex, insIndex);
String localType = symLocal.getDataType(intIndex, insIndex);
statement = localVar + " = " + Helper.getValue(popValue, localType);
precedence = L_EVAL;
}
private void pushOperands(JOperandStack myStack, Operand op1, Operand op2) {
if (op1.isCategory1()) {
// Cat.1
myStack.push(op2);
myStack.push(op1);
if (op2 == null) {
myStack.push(myStack.pop());
} else {
myStack.push(op2);
}
} else {
// Cat.2
myStack.push(op1);
}
}
/**
* Processes an invoke instruction -
* invokespecial, invokestatic, invokeinterface, invokevirtual.
*
* @param aCurIns Current Instruction that is to be
* operated on the JVM stack.
* @param aJos The JVM OperandStack of the current method
* that is under reference.
* @param aInvokeSpecialFlag if this instruction is invokespecial.
*/
private void processInvokeInstruction(JInstruction aCurIns, JOperandStack aJos, boolean aInvokeSpecialFlag) {
int offset = aCurIns.getArgUnsignedShort();
int classIndex = cpInfo.getPtr1(offset);
int nameIndex = cpInfo.getPtr2(offset);
String methodName = cpInfo.getFirstDirectName(nameIndex);
String className = cpInfo.getClassName(classIndex);
String argsList = cpInfo.getCpValue(cpInfo.getPtr2(nameIndex));
List args = Helper.getArguments(argsList);
int popMax = args.size();
//Equals Number of Arguments
String methodType = Helper.getReturnType(argsList);
//log.info(className);
List argValues = new ArrayList<>(popMax);
for (int i = popMax - 1; i >= 0; i--) {
// add arguments in reverse order
argValues.add(0, aJos.pop().getValue());
}
String objRef = aJos.pop().getValue();
/* Takes care of modifying the input */
if (objRef.compareTo(THIS) != 0) {
if (aInvokeSpecialFlag && methodName.equals(INIT)) {
statement = objRef; //Constructor
} else {
statement = objRef + "." + methodName;
}
} else {
if (aInvokeSpecialFlag && methodName.equals(INIT)) {
if ((className.equals(LANG_OBJECT))) {
statement = ""; // filter out the default Object() constructor.
return;
} else {
statement = SUPER;
//Code for super constructor here.
}
} else {
statement = methodName;
}
}
precedence = L_REF;
statement += getArgValues(args, argValues);
if (methodType.compareTo(JVM_VOID) == 0) {
if (aInvokeSpecialFlag && !aJos.empty()) {
Operand op1 = aJos.pop();
aJos.push(new Operand(statement, op1.getDatatype(), precedence));
}
} else {
aJos.push(statement, methodType, precedence);
}
invokedObject = new Operand(objRef, className, L_REF);
}
/**
* @param args Argument - members are String.
* @param argValues Argument - members are String.
* @return Returns a String.
*/
private String getArgValues(List args, List argValues) {
StringBuilder result = new StringBuilder("(");
for (int i = 0; i < args.size(); i++) {
String value = Helper.getValue(argValues.get(i), (String) args.get(i));
if (i != 0) {
result.append(" , ");
}
result.append(value);
}
result.append(")");
return result.toString();
}
}/* End of class */