
// JEE - Java Execution Engine
// Author - Tak Yin Wong
// (c) Copyright 1998
// All Rights Reserved
//
// Email: mydy@world.std.com
//

import java.applet.*;
import java.awt.*;
import java.io.*;
import java.awt.event.*;

        public class JEE extends Applet {                        

                
                static String className;
		FileInputStream is;
		DataInputStream ds;
		static byte classFile[];
		static JMap jMap;
		static ClassFile classEntry;
		static Frame mainFrame;
		static JText constantPoolText;
		static JText generalText;
		static JText decompileText;

		// Constructor
		public JEE() {

			classEntry = new ClassFile();
			mainFrame = new Frame("Java Execution Engine");
			constantPoolText = new JText();
			generalText = new JText();
			decompileText = new JText();
			MenuBar JEEMenuBar = new MenuBar();
			Menu fileMenu = new Menu("File");
			MenuItem openMenuItem = new MenuItem("Open");
			MenuItem saveMenuItem = new MenuItem("Save");
			MenuItem exitMenuItem = new MenuItem("Exit");
			fileMenu.add(openMenuItem);
			fileMenu.add(saveMenuItem);
			fileMenu.add(exitMenuItem);
			JEEMenuListener openListener = new JEEMenuListener("Open", this, mainFrame);
			JEEMenuListener saveListener = new JEEMenuListener("Save", this, mainFrame);
			JEEMenuListener exitListener = new JEEMenuListener("Exit");
			Menu writeMenu = new Menu("Save");
			MenuItem writeCPMenuItem = new MenuItem("Constant Pool");
			MenuItem writeGeneralMenuItem = new MenuItem("Raw Dump");
			MenuItem writeDecompileMenuItem = new MenuItem("Decompilation");
			writeMenu.add(writeCPMenuItem);
			writeMenu.add(writeGeneralMenuItem);
			writeMenu.add(writeDecompileMenuItem);
			JEEMenuListener writeCPListener = new JEEMenuListener("Write Constant Pool", this, mainFrame);
			JEEMenuListener writeGeneralListener = new JEEMenuListener("Write Raw Dump", this, mainFrame);
			JEEMenuListener writeDecompileListener = new JEEMenuListener("Write Decompilation", this, mainFrame);
			writeCPMenuItem.addActionListener(writeCPListener);
			writeGeneralMenuItem.addActionListener(writeGeneralListener);
			writeDecompileMenuItem.addActionListener(writeDecompileListener);
			Menu clearMenu = new Menu("Clear");
			MenuItem clearCPMenuItem = new MenuItem("Constant Pool");
			MenuItem clearGeneralMenuItem = new MenuItem("Raw Dump");
			MenuItem clearDecompileMenuItem = new MenuItem("Decompilation");
			clearMenu.add(clearCPMenuItem);
			clearMenu.add(clearGeneralMenuItem);
			clearMenu.add(clearDecompileMenuItem);
			JEEMenuListener clearCPListener = new JEEMenuListener("Clear Constant Pool", this, mainFrame);
			JEEMenuListener clearGeneralListener = new JEEMenuListener("Clear Raw Dump", this, mainFrame);
			JEEMenuListener clearDecompileListener = new JEEMenuListener("Clear Decompilation", this, mainFrame);
			clearCPMenuItem.addActionListener(clearCPListener);
			clearGeneralMenuItem.addActionListener(clearGeneralListener);
			clearDecompileMenuItem.addActionListener(clearDecompileListener);
			mainFrame.setMenuBar(JEEMenuBar);
			Menu listMenu = new Menu("List Class File");
			MenuItem listMenuItem = new MenuItem("List");
			listMenu.add(listMenuItem);
			JEEMenuListener listListener = new JEEMenuListener("List Class File", this, className, classEntry, constantPoolText);
			Menu dumpMenu = new Menu("Raw Dump");
			MenuItem dumpMenuItem = new MenuItem("Dump");
			dumpMenu.add(dumpMenuItem);
			JEEMenuListener dumpListener = new JEEMenuListener("Dump", this, className, generalText);
			Menu decompileMenu = new Menu("Decompile Class File");
			MenuItem decompileMenuItem = new MenuItem("Decompile");
			decompileMenu.add(decompileMenuItem);
			JEEMenuListener decompileListener = new JEEMenuListener("Decompile Class File", this, className, classEntry, decompileText);

			openMenuItem.addActionListener(openListener);
			saveMenuItem.addActionListener(saveListener);
			exitMenuItem.addActionListener(exitListener);
			dumpMenuItem.addActionListener(dumpListener);
			listMenuItem.addActionListener(listListener);
			decompileMenuItem.addActionListener(decompileListener);
			JEEMenuBar.add(fileMenu);
			JEEMenuBar.add(listMenu);
			JEEMenuBar.add(dumpMenu);
			JEEMenuBar.add(decompileMenu);
			JEEMenuBar.add(writeMenu);
			JEEMenuBar.add(clearMenu);

		}

		public static void main(String args[]) {

			JEE jee = new JEE();
			classEntry.magic = new short[4];
			if (args.length > 0) {
                        	className = args[0];
				JeeClassLoader PrimordialClassLoader = 
							new JeeClassLoader();
				try {
					classFile = 
						PrimordialClassLoader.getClassFile(className);
				} catch(java.io.IOException iox) { };
				jMap = new JMap(classFile, classEntry);
			}
			else {
				className = "NOTITLE";
			}


			

			mainFrame.add("East", decompileText);
			mainFrame.add(constantPoolText);
			mainFrame.add("South", generalText);
			mainFrame.resize(800, 500);
			mainFrame.show();

		}

		void rawDump(String fileName, JText tArea) {

			int i;
			String hexDump;
			String hexStr;
			
			
			try {
			for (i = 0; ; i++) {
				hexDump = Integer.toString((int) (0xFF & classFile[i]), 16);
				if (hexDump.length() == 1)
					hexStr = "0" + hexDump + " ";
				else
					hexStr = hexDump + " ";
	
				if ((i + 1)%32 == 0)
					tArea.appendTextln(hexStr);
				else
					tArea.appendText(hexStr);
			}
			} catch (ArrayIndexOutOfBoundsException e) {
					tArea.appendTextln("\n" + "-------- End of Hex Dump for " + fileName + "--------");
			}

		}

		void listAll(String fileName, ClassFile classEntry, JText tArea) {

			listHeader(classEntry, tArea);
			listConstantPool(classEntry.CPTable, classEntry.constantPoolCount, tArea);
			listAccessFlags(classEntry, tArea);
			listThisClass(classEntry, tArea);
			listSuperClass(classEntry, tArea);
			tArea.appendTextln("Interfaces Count = " + classEntry.interfacesCount);
			if (classEntry.interfacesCount > 0)
				listInterfaces(classEntry, tArea);
			tArea.appendTextln("Fields Count = " + classEntry.fieldsCount);
			if (classEntry.fieldsCount > 0)
				listFields(classEntry, tArea);
			tArea.appendTextln("Methods Count = " + classEntry.fieldsCount);
			if (classEntry.methodsCount > 0)
				listMethods(classEntry, tArea);
			if (classEntry.attributesCount > 0)
				listAttributes(classEntry, tArea);
			
			}

		static void listHeader(ClassFile classEntry, JText tArea) {

			tArea.appendText("Magic: ");
			tArea.appendText(Integer.toString((int) (0xFF & classEntry.magic[0]), 16));
			tArea.appendText(Integer.toString((int) (0xFF & classEntry.magic[1]), 16));
			tArea.appendText(Integer.toString((int) (0xFF & classEntry.magic[2]), 16));
			tArea.appendTextln(Integer.toString((int) (0xFF & classEntry.magic[3]), 16));

			tArea.appendText("Version: ");
			tArea.appendText(Integer.toString(0xFF & classEntry.majorVersion, 16) + ".");
			tArea.appendTextln(Integer.toString(0xFF & classEntry.minorVersion, 16));
		}

		static void listAccessFlags(ClassFile classEntry, JText tArea) {

			tArea.appendText("Access Flags: ");
			tArea.appendTextln(Integer.toString(classEntry.accessFlags, 16));
		}
		static void listThisClass(ClassFile classEntry, JText tArea) {
			tArea.appendText("This Class: ");
			CPEntry entry = classEntry.CPTable[classEntry.thisClass];
			entry = classEntry.CPTable[entry.classNameIndex];
			
			tArea.appendTextln(entry.string);
		}
		static void listSuperClass(ClassFile classEntry, JText tArea) {
			tArea.appendText("Super Class: ");
			CPEntry entry = classEntry.CPTable[classEntry.superClass];
			entry = classEntry.CPTable[entry.classNameIndex];
			
			tArea.appendTextln(entry.string);
		}

		static void listInterfaces(ClassFile classEntry, JText tArea) {

			int i;
			CPEntry entry;
			short classNameIndex;

			for (i = 0; i < classEntry.interfacesCount; i++) {
				entry = classEntry.CPTable[classEntry.interfaces[i]];
				classNameIndex = entry.classNameIndex;
				entry = classEntry.CPTable[classNameIndex];
				tArea.appendTextln("\t" + entry.string);
			}
				
		}
		static void listFields(ClassFile classEntry, JText tArea) {

			int i, j;
			CPEntry CPTable[];
			CPTable = classEntry.CPTable;
			String typeString;

			for (i = 0; i < classEntry.fieldsCount; i++) {
				tArea.appendText("" + (i + 1) + ":");
				tArea.appendTextln("\tAccess Flags = 0x" + Integer.toString(classEntry.fields[i].accessFlags, 16));
			
				typeString = CPTable[classEntry.fields[i].typeIndex].string;
				if (CPTable[classEntry.fields[i].typeIndex].string.equals("B"))
					typeString = "byte";
				if (CPTable[classEntry.fields[i].typeIndex].string.equals("C"))
					typeString = "char";	
				if (CPTable[classEntry.fields[i].typeIndex].string.equals("D"))
					typeString = "double";
				if (CPTable[classEntry.fields[i].typeIndex].string.equals("F"))
					typeString = "float";
				if (CPTable[classEntry.fields[i].typeIndex].string.equals("I"))
					typeString = "int";
				if (CPTable[classEntry.fields[i].typeIndex].string.equals("J"))
					typeString = "long";
				if (CPTable[classEntry.fields[i].typeIndex].string.equals("S"))
					typeString = "short";
				if (CPTable[classEntry.fields[i].typeIndex].string.equals("Z"))
					typeString = "boolean";
				tArea.appendTextln("\t" + typeString + " " + CPTable[classEntry.fields[i].nameIndex].string);
				tArea.appendTextln("\t" + "Attributes Count = " + classEntry.fields[i].attributesCount);
				for (j = 0; j < classEntry.fields[i].attributesCount; j++) {
					tArea.appendTextln("\t" + (j + 1) + ":");
					FieldAttribute fAttribute = (FieldAttribute) classEntry.fields[i].attributes[j];
					short attributeNameIndex = fAttribute.attributeNameIndex;
					short constantValueIndex = fAttribute.constantValueIndex;
					tArea.appendText("\t\t" + CPTable[attributeNameIndex].string + " : ");
					switch(CPTable[constantValueIndex].constantType) { 

						case 1: 
							tArea.appendTextln(CPTable[constantValueIndex].string);
							break;
						case 3:
							if (typeString.equals("char")) {
								char theChar = (char) CPTable[constantValueIndex].intValue;
								tArea.appendTextln("" + theChar);
								break;
							}
							if (typeString.equals("boolean")) {
								String theString = "false";
								if (CPTable[constantValueIndex].intValue == 1) {
									theString = "true";
								}
								tArea.appendTextln("" + theString);
								break;
							}	
						case 4:
						case 5:
						case 6:
							tArea.appendTextln("" + CPTable[constantValueIndex].intValue);
							break;
						case 7:
						case 8:
							tArea.appendTextln("" + CPTable[CPTable[constantValueIndex].stringIndex].string);
							break;
						case 9:
						case 10:
						case 11:
						case 12:

							System.out.println("To be implemented");
					}
				}
						
			}

		}
		static void listMethods(ClassFile classEntry, JText tArea) {
			int i, j, k;
			CPEntry CPTable[];
			CPTable = classEntry.CPTable;

			for (i = 0; i < classEntry.methodsCount; i++) {
				tArea.appendText("" + (i + 1) + ":");
				tArea.appendTextln("\tAccess Flags = 0x" + Integer.toString(classEntry.methods[i].accessFlags, 16));
			
				String typeString = CPTable[classEntry.methods[i].typeIndex].string;
				tArea.appendTextln("\t" + typeString + " " + CPTable[classEntry.methods[i].nameIndex].string);
				tArea.appendTextln("\t" + "Attributes Count = " + classEntry.methods[i].attributesCount);
				for (j = 0; j < classEntry.methods[i].attributesCount; j++) {
					Attribute mAttribute = (Attribute) classEntry.methods[i].attributes[j];
					short attributeNameIndex = mAttribute.attributeNameIndex;
					tArea.appendTextln("\t\t" + CPTable[attributeNameIndex].string);
					if (CPTable[attributeNameIndex].string.equals("Exceptions")) {
						ExceptionAttribute eAttribute = (ExceptionAttribute) mAttribute;
						eAttribute.throwsIndex = new short[eAttribute.throwsCount];
						tArea.appendTextln("\t\tThrows:");
						for (k = 0; k < eAttribute.throwsCount; k++) {
							short index = eAttribute.throwsIndex[k];
							tArea.appendTextln("\t\t\t" + CPTable[index].string);
						}
					}

					if (CPTable[attributeNameIndex].string.equals("Code")) {
						CodeAttribute cAttribute = (CodeAttribute) mAttribute;
						tArea.appendTextln("\t\tmaxStack = " + cAttribute.maxStack);
						tArea.appendTextln("\t\tmaxLocals = " + cAttribute.maxLocals);
					}
				}
						
			}


		}
		static void listAttributes(ClassFile classEntry, JText tArea) {
			int i, j, k;
			CPEntry CPTable[];
			CPTable = classEntry.CPTable;
			Attribute tAttribute;

			tArea.appendTextln("Class Attributes:");
			for (i = 0; i < classEntry.attributesCount; i++) {
				tAttribute = classEntry.attributes[i];
				tArea.appendTextln("" + (i + 1) + "\t" + CPTable[tAttribute.attributeNameIndex].string);
				if (CPTable[tAttribute.attributeNameIndex].string.equals("SourceFile")) {
				SrcFileAttribute sAttribute = (SrcFileAttribute) tAttribute;
				tArea.appendTextln("\t\t" + CPTable[sAttribute.attributeNameIndex].string);
				tArea.appendTextln("\t\t" + CPTable[sAttribute.srcFileIndex].string);
				
				}
			

			}
				
		}
		static void listConstantPool(CPEntry CPTable[], int CPCount, JText tArea) {
			
			byte theByte;
			short index;
			CPEntry entry;
		
			tArea.appendTextln("Constant Pool:");

			for (int i = 1; i < CPCount; i++)  {
			
			int type = CPTable[i].constantType;

			tArea.appendText("Entry " + i + ": ");
			switch(type) {

			case 1:
				tArea.appendText("Utf8; ");
				tArea.appendTextln(CPTable[i].string);
				break;

			case 3:
				tArea.appendText("Integer; ");
				tArea.appendTextln("" + CPTable[i].intValue);
				break;

			case 4:
				tArea.appendText("Float; ");
				tArea.appendTextln("" + CPTable[i].floatValue);
				break;

			case 5:
				tArea.appendText("Long; ");
				tArea.appendTextln("" + CPTable[i].longValue);
				break;

			case 6:
				tArea.appendText("Double; ");
				tArea.appendTextln("" + CPTable[i].doubleValue);
				break;

			case 7:
				tArea.appendText("Class; ");
				index = CPTable[i].classNameIndex;
				tArea.appendTextln(CPTable[index].string);
				break;

			case 8:
				tArea.appendText("String; ");
				index = CPTable[i].stringIndex;
				tArea.appendTextln("\"" + CPTable[index].string + "\"");
				break;

			case 9:
			case 10:
			case 11:
				switch(type) {
				case 9:
					tArea.appendText("FieldRef; ");
					break;
				case 10:
					tArea.appendText("MethodRef; ");
					break;
				case 11:
					tArea.appendText("InterfaceMethodRef; ");
					break;
				}

				entry = CPTable[CPTable[i].classIndex];
				entry = CPTable[entry.classNameIndex];
				tArea.appendText(entry.string + ";");
				entry = CPTable[CPTable[i].nameTypeIndex];
				int nameIndex = entry.nameIndex;
				int typeIndex = entry.typeIndex;
				entry = CPTable[nameIndex];
				tArea.appendText(entry.string + ";");
				entry = CPTable[typeIndex];
				tArea.appendTextln(entry.string);
				break;

			case 12:
				tArea.appendText("NameAndType; ");
				entry = CPTable[CPTable[i].nameIndex];
				tArea.appendText(entry.string);
				entry = CPTable[CPTable[i].typeIndex];
				tArea.appendTextln(entry.string);
				break;
			default:
				System.out.println("Unknown type " + type);
			}
			}

		}

		boolean hasSeparator(String str) {


			for (int i = 0; i < str.length(); i++) {
				if (str.charAt(i) == '/') {
					return true;
				}
			}

			return false;
		}

		void decompileImports(CPEntry CPTable[], short constantPoolCount, JText tArea) {

			int i, j = 0;
			int k;
			CPEntry entry;
			int strCount;
			String importsArray[] = new String[0];
			boolean contFlag;
			for (i = 0, strCount = 0; i < constantPoolCount; i++) {
				if (CPTable[i].constantType == 7) {
					strCount++;
				}	
			}
			if (strCount > 0) {
				importsArray = new String[strCount];
				for (i = 0, j = 0; i < constantPoolCount; i++) {
					contFlag = false;
					if (CPTable[i].constantType == 7) {
						entry = CPTable[CPTable[i].classNameIndex];
						if (hasSeparator(entry.string)) {
							for (k = 0; k < entry.string.length(); k++) {
								if (entry.string.startsWith("java/lang/", k)) {
									contFlag = true;
									break;
								}
							}
							if (contFlag == true) {
								continue;
							}
							StringBuffer strBuf = new StringBuffer();
							int l = 0;
							for (k = 0; k < entry.string.length(); k++) {
								if (entry.string.charAt(k) != '[' && entry.string.charAt(k) != 'L')
									strBuf.append(entry.string.charAt(k));
							}
							String newString = new String(strBuf);
							importsArray[j++] = newString.replace('/', '.');
						}
					}
				}	
			}				
			
			for (i = 0; i < j; i++) {
				tArea.appendTextln("import " + importsArray[i] + ";");
			}
		}

		static void decompileFields(ClassFile classEntry, JText tArea) {

			int i, j;
			CPEntry CPTable[];
			CPTable = classEntry.CPTable;
			String typeString;

			for (i = 0; i < classEntry.fieldsCount; i++) {
				tArea.appendText("\t");
				if ((classEntry.fields[i].accessFlags & JConstants.ACC_STATIC) != 0)  
					tArea.appendText("static ");
				if ((classEntry.fields[i].accessFlags & JConstants.ACC_PUBLIC) != 0)  
					tArea.appendText("public ");
					
				if ((classEntry.fields[i].accessFlags & JConstants.ACC_PRIVATE) != 0)  
					tArea.appendText("private ");
				if ((classEntry.fields[i].accessFlags & JConstants.ACC_PROTECTED) != 0)  
					tArea.appendText("protected ");
				if ((classEntry.fields[i].accessFlags & JConstants.ACC_FINAL) != 0)  
					tArea.appendText("final ");
				if ((classEntry.fields[i].accessFlags & JConstants.ACC_VOLATILE) != 0)  
					tArea.appendText("volatile ");
				if ((classEntry.fields[i].accessFlags & JConstants.ACC_TRANSIENT) != 0)  
					tArea.appendText("transient ");
			
				typeString = CPTable[classEntry.fields[i].typeIndex].string;
				tArea.appendText("" + parseType(typeString, CPTable[classEntry.fields[i].nameIndex].string));

				for (j = 0; j < classEntry.fields[i].attributesCount; j++) {
					FieldAttribute fAttribute = (FieldAttribute) classEntry.fields[i].attributes[j];
					short attributeNameIndex = fAttribute.attributeNameIndex;
					short constantValueIndex = fAttribute.constantValueIndex;
					switch(CPTable[constantValueIndex].constantType) { 

						case 1: 
							tArea.appendText(CPTable[constantValueIndex].string);
							break;
						case 3:
							if (typeString.equals("char")) {
								char theChar = (char) CPTable[constantValueIndex].intValue;
								tArea.appendText(" = '" + theChar + "'");
								break;
							}
							if (typeString.equals("boolean")) {
								String theString = "false";
								if (CPTable[constantValueIndex].intValue == 1) {
									theString = "true";
								} 
								tArea.appendText(" = " + theString);
								break;
							}
						case 4:
						case 5:
						case 6:
							tArea.appendText(" = " + CPTable[constantValueIndex].intValue);
							break;
						case 7:
						case 8:
							tArea.appendText(" = \"" + CPTable[CPTable[constantValueIndex].stringIndex].string + "\"");
							break;
						case 9:
						case 10:
						case 11:
						case 12:

							System.out.println("To be implemented");
					}
				}

				tArea.appendTextln(";");
						





						
			}

		}

		static String parseType(String typeString, String symbol) {
			int arrayLevel = 0;
			int i, j;
			String str;
			String retStr;
			StringBuffer strBuf = new StringBuffer(symbol);
			Character thisChar;

			if (typeString.equals("B"))
				return("byte");
			if (typeString.equals("C"))
				return("char");	
			if (typeString.equals("D"))
				return("double");
			if (typeString.equals("F"))
				return("float");
			if (typeString.equals("I"))
				return("int");
			if (typeString.equals("J"))
				return("long");
			if (typeString.equals("S"))
				return("short");
			if (typeString.equals("Z"))
				return("boolean");
			
			for (i = 0; i < typeString.length(); i++) {
				if (typeString.charAt(i) == '[') {
					arrayLevel++;
				} else {
					break;
				}
			}
			if (typeString.charAt(i) != 'L') {
				thisChar = new Character(typeString.charAt(i));
				str = thisChar.toString();
				retStr = parseType(str, symbol);
		
			} else {
				
				i = typeString.lastIndexOf("/");
				j = typeString.lastIndexOf(";");
				retStr = typeString.substring(i + 1, j);
			}
			while (arrayLevel > 0) {
				strBuf.append("[ ]");
				arrayLevel--;
			}
			return(retStr + " " + strBuf.toString());	
		}

		static void decompileAccessFlags(short accessFlags, TextArea tArea) {


			if ((accessFlags & JConstants.ACC_PUBLIC) != 0)
				tArea.appendText("public ");

			if ((accessFlags & JConstants.ACC_PRIVATE) != 0)
				tArea.appendText("privat");

			if ((accessFlags & JConstants.ACC_PROTECTED) != 0)
				tArea.appendText("protected ");

			if ((accessFlags & JConstants.ACC_STATIC) != 0)
				tArea.appendText("static ");

			if ((accessFlags & JConstants.ACC_FINAL) != 0)
				tArea.appendText("final ");

			if ((accessFlags & JConstants.ACC_VOLATILE) != 0)
				tArea.appendText("volatile ");

			if ((accessFlags & JConstants.ACC_TRANSIENT) != 0)
				tArea.appendText("transient ");

		}


		static void decompileRetVal(char c, TextArea tArea) {

			switch (c) {

				case 'V':
					tArea.appendText("void ");
					break;

				case 'C':
					tArea.appendText("char ");
					break;

				case 'D':
					tArea.appendText("double ");
					break;

				case 'F':
					tArea.appendText("float ");
					break;

				case 'I':
					tArea.appendText("int ");
					break;

				case 'J':
					tArea.appendText("long ");
					break;

				case 'S':
					tArea.appendText("short ");
					break;

				case 'Z':
					tArea.appendText("boolean ");
					break;

			}
		}
				


		static void decompileMethods(ClassFile classEntry, JText tArea) {
			int i, j, k;
			CPEntry CPTable[];
			CPTable = classEntry.CPTable;

			for (i = 0; i < classEntry.methodsCount; i++) {
			
				
					//continue; 
				if (CPTable[classEntry.methods[i].nameIndex].string.equals("<clinit>"))
					continue; 
				tArea.appendText("\t");
				decompileAccessFlags(classEntry.methods[i].accessFlags, tArea);
				String typeString = CPTable[classEntry.methods[i].typeIndex].string;
				decompileRetVal(typeString.charAt(typeString.length() - 1), tArea);
				if (CPTable[classEntry.methods[i].nameIndex].string.equals("<init>"))

					tArea.appendTextln(CPTable[CPTable[classEntry.thisClass].classNameIndex].string + typeString + " {\n");
				else
					tArea.appendTextln(CPTable[classEntry.methods[i].nameIndex].string + typeString + " {\n");
				for (j = 0; j < classEntry.methods[i].attributesCount; j++) {
					Attribute mAttribute = (Attribute) classEntry.methods[i].attributes[j];
					short attributeNameIndex = mAttribute.attributeNameIndex;
					if (CPTable[attributeNameIndex].string.equals("Exceptions")) {
						ExceptionAttribute eAttribute = (ExceptionAttribute) mAttribute;
						eAttribute.throwsIndex = new short[eAttribute.throwsCount];
						for (k = 0; k < eAttribute.throwsCount; k++) {
							short index = eAttribute.throwsIndex[k];
						}
					}

					if (CPTable[attributeNameIndex].string.equals("Code")) {
						CodeAttribute cAttribute = (CodeAttribute) mAttribute;
						String hexDump, hexStr;
						byte code[] = cAttribute.code;
						for (int ii = 0; ii < cAttribute.codeCount; ii++) {
							hexDump = Integer.toString((int) (0xFF & code[ii]), 16);
							if (hexDump.length() == 1)
							hexStr = "0" + hexDump + " ";
							else
								hexStr = hexDump + " ";
							//tArea.appendTextln("\t\t" + hexStr);
							ii += OpCode.printOpCodeString(tArea, (short) code[ii], code, ii, CPTable);
						}
					}
				}
						
				tArea.appendTextln("\t}\n");


			}


		}


		void decompile(String fileName, ClassFile classEntry, JText tArea) {
			CPEntry CPTable[];
			CPEntry entry, iEntry;
			short classNameIndex;
			String shortString;

			CPTable = classEntry.CPTable;

			tArea.appendTextln("\n");

			decompileImports(CPTable, classEntry.constantPoolCount, tArea);
			tArea.appendTextln("\n");


			entry = CPTable[classEntry.thisClass];
			entry = CPTable[entry.classNameIndex];
			if ((classEntry.accessFlags & JConstants.ACC_PUBLIC) != 0) {
				tArea.appendText("public ");
			} 
			tArea.appendText("class " + entry.string);
			boolean objectFlag = false;
			entry = CPTable[classEntry.superClass];
			entry = CPTable[entry.classNameIndex];
			if (entry.string.equals("java/lang/Object"))
				objectFlag = true;
			int lastIndex = entry.string.lastIndexOf("/");
			shortString = entry.string.substring(lastIndex + 1);
			if (objectFlag == false) {
				tArea.appendText(" extends ");
				tArea.appendText(shortString);
			}
			if (classEntry.interfacesCount > 0) {
				tArea.appendText(" implements ");
				for (int i = 0; i < classEntry.interfacesCount; i++) {
					iEntry = CPTable[classEntry.interfaces[i]];
					classNameIndex = iEntry.classNameIndex;
					iEntry = CPTable[classNameIndex];
					lastIndex = iEntry.string.lastIndexOf("/");
					shortString = iEntry.string.substring(lastIndex + 1);
					tArea.appendText(" " + shortString);
					if (i + 1 < classEntry.interfacesCount)
						tArea.appendText(",");
				}
			} 
			tArea.appendTextln(" {\n");
			decompileFields(classEntry, tArea);
			tArea.appendTextln("\n");
			decompileMethods(classEntry, tArea);
			tArea.appendTextln("\n");
			tArea.appendTextln(" }\n");
		}

	}

	class JEEMenuListener implements ActionListener, Runnable {

		String itemId;
		String fileName;
		byte classFile[];
		ClassFile classEntry;
		JText tArea;
		JEE jee;
		JDialog openDialog;
		JDialog saveDialog;
		Frame mainFrame;
		FileOutputStream os;
		String str;
		int ii;
		
		JEEMenuListener(String id) {
			itemId = id;
		}

		JEEMenuListener(String id, JEE j, Frame f) {
			itemId = id;
			mainFrame = f;
			jee = j;
		}

		JEEMenuListener(String id, JEE j, String fName, ClassFile entry, JText ta) {
			itemId = id;
			jee = j;
			fileName = fName;
			classEntry = entry;
			tArea = ta;
		}

		JEEMenuListener(String id, JEE j, String fName, JText ta) {
			itemId = id;
			jee = j;
			fileName = fName;
			tArea = ta;
		}

		public void actionPerformed(ActionEvent e) {


			if (itemId.equals("Open")) {
				if (openDialog == null) {
					openDialog = new JDialog(mainFrame, jee, "Open File");
				}
				openDialog.show();
			} else {
				if (itemId.equals("Save")) {
					if (saveDialog == null) {
						saveDialog = new JDialog(mainFrame, jee, "Save File");
					}
					saveDialog.show();
				} else {
					if (itemId.equals("Exit")) {
						System.out.println("Exiting...");
						System.exit(0);
					} else {
						Thread listThread = new Thread(this);
						listThread.start();
						return;
					}
				}
			}
		}

		public void run() {
			if (itemId.equals("List Class File")) {
				jee.listAll(fileName, classEntry, tArea);
			}
			if (itemId.equals("Dump")) {
				jee.rawDump(fileName, tArea);

			}
			if (itemId.equals("Decompile Class File")) {
				jee.decompile(fileName, classEntry, tArea);
			}
			if (itemId.equals("Write Constant Pool")) {
				str = jee.constantPoolText.getText();
				try {
				os = new FileOutputStream("constantpool.out");
				for (ii = 0; ii < str.length(); ii++) {
					if (str.charAt(ii) == '\n')
						os.write('\r');
					os.write(str.charAt(ii));
				}
				os.write('\r');
				os.write('\n');
				os.close();
				} catch (java.io.IOException iox) {
					System.out.println("IO Exception");
				}
				System.out.println("Written to constantpool.out");
			}
			if (itemId.equals("Write Raw Dump")) {
				str = jee.generalText.getText();
				try {
				os = new FileOutputStream("rawdump.out");
				for (ii = 0; ii < str.length(); ii++) {
					if (str.charAt(ii) == '\n')
						os.write('\r');
					os.write(str.charAt(ii));
				}
				os.write('\r');
				os.write('\n');
				os.close();
				} catch (java.io.IOException iox) {
					System.out.println("IO Exception");
				}
				System.out.println("Written to rawdump.out");
			}
			if (itemId.equals("Write Decompilation")) {
				str = jee.decompileText.getText();
				try {
				os = new FileOutputStream("decompilation.out");
				for (ii = 0; ii < str.length(); ii++) {
					if (str.charAt(ii) == '\n')
						os.write('\r');
					os.write(str.charAt(ii));
				}
				os.write('\r');
				os.write('\n');
				os.close();
				} catch (java.io.IOException iox) {
					System.out.println("IO Exception");
				}
				System.out.println("Written to decompilation.out");
			}
			if (itemId.equals("Clear Constant Pool")) {
				System.out.println("Clearing constant pool text");
				jee.constantPoolText.setText("");
			}
			if (itemId.equals("Clear Raw Dump")) {
				System.out.println("Clearing raw dump");
				jee.generalText.setText("");
			}
			if (itemId.equals("Clear Decompilation")) {
				System.out.println("Clearing decompilation");
				jee.decompileText.setText("");
			}
			
		}
	}


	class JDialog extends Dialog {

		private TextField tField;
		private Button ok;
		private Button dismiss;
		private Button constPool;
		private Button general;
		private Button decompile;
		private String dialogName;
		private Label label;
		private String inputStr;
		private ButtonListener okAction;
		private ButtonListener dismissAction;
		private ButtonListener CPAction;
		private ButtonListener generalAction;
		private ButtonListener decompileAction;
		private Frame myFrame; 
		// private InputListener textAction;

		public JDialog(Frame mf, JEE j, String name) {
			super(mf, name, true);

			myFrame = mf;
			dialogName = name;
			Panel panel = new Panel();
			label = new Label(name);
			panel.add(label);
			tField = new TextField(10);
			//textAction = new InputListener(tField, name);
			//tField.addFocusListener(textAction);
			if (name.equals("Open File"))
			{
				ok = new Button("OK");
				okAction = new ButtonListener(j, this, tField, "OK");
				ok.addActionListener(okAction);
				panel.add(tField);
				panel.add(ok);
			}
			if (name.equals("Save File"))
			{
				constPool = new Button("Constant Pool Text");
				CPAction = new ButtonListener(j, this, tField, "Constant Pool");
				general = new Button("Raw Dump Text");
				generalAction = new ButtonListener(j, this, tField, "Raw Dump");
				decompile = new Button("Decompile Text");
				decompileAction = new ButtonListener(j, this, tField, "Decompile");
				constPool.addActionListener(CPAction);
				general.addActionListener(generalAction);
				decompile.addActionListener(decompileAction);
				panel.add(constPool);
				panel.add(general);
				panel.add(decompile);
			}
			dismiss = new Button("Dismiss");
			dismissAction = new ButtonListener(j, this, tField, "Dismiss");
			dismiss.addActionListener(dismissAction);
			panel.add(dismiss);
			add("Center", panel);
			pack();
			
		}
		//public void hide() {
			//super.hide();
			//myFrame.show();
		//}

		public void showFrame() {
			myFrame.show();
		}
	}


	class ButtonListener implements ActionListener {

		private JDialog parentDialog;
		private String buttonId;
		private JEE jee;
		private TextField tField;


		public ButtonListener(JEE j, JDialog pd, TextField t, String id) {

			parentDialog = pd;
			jee = j;
			tField = t;
			buttonId = id;
		}

		public void actionPerformed(ActionEvent e) {

			if (buttonId == "OK") {
				JeeClassLoader PrimordialClassLoader = 
							new JeeClassLoader();
				try {
					jee.classFile = 
						PrimordialClassLoader.getClassFile(tField.getText());
				} catch(java.io.IOException iox) { };

				parentDialog.hide();
				parentDialog.showFrame();
				jee.jMap = 
					new JMap(jee.classFile, jee.classEntry);
			
			}

			if (buttonId == "Constant Pool") {
				System.out.println("Saving constant pool");
				System.out.println(jee.constantPoolText.getText());
			}
			if (buttonId == "Raw Dump") {
				System.out.println("Saving general");
				System.out.println(jee.generalText.getText());
			}
			if (buttonId == "Decompile") {
				System.out.println("Saving decompile");
				System.out.println(jee.decompileText.getText());
			}
			if (buttonId == "Dismiss") {
				parentDialog.hide();
			}
		}
	}


	//class InputListener extends FocusAdapter {

		//TextField textField;
	

		//public InputListener(TextField t);

			// textField = t;
		//}


		//public void focusLost(FocusEvent e) {

			//if textId.equals("Open File") {

		//}
	//}
