오늘은 자바 AWT(Abstract Windows Toolkit)/Swing(Part of Java Foundation Classes)를 사용하여 class파일 디컴파일러를 제작해 보았습니다. AWT와 Swing 은 자바에서 GUI용 개체(콤포넌트)를 사용해서 윈도우용(GUI) 프로그램을 만들수 있도록 하는 툴이고, 마이크로소프트의 MFC(Microsoft Foundation Class) 프로그램과 비교 됩니다.
더 진행하기 전에 작성된 프로그램의 라에센스를 짚고 넘어 가겠습니다.
외부프로그램으로 아래 2가지가 사용되었습니다.
1. jad이용 : Free for non-commercial use (Copyright: Pavel Kouznetsov).
jad.exe
(
- https://web.archive.org/web/20080214075546/http://www.kpdus.com/jad.html
- http://www.javadecompilers.com/jad
)
2. exe배포 : launch4j 이용.- http://launch4j.sourceforge.net/
launch4j-3.9-win32.zip ( 압축을 푼 후 launch4j.exe 실행 )
(
This program is free software licensed under the BSD 3-Clause License, the head subproject (the code which is attached to the wrapped jars) is licensed under the MIT License. Launch4j may be used for wrapping closed source, commercial applications.
)
** 최종결과 프로그램인 javad.exe 은 자체제작 했습니다.
작동 화면은 아래와 같습니다.
1. 디컴파일 작업을 위해 메뉴를 선택 합니다.
2. 디컴파일 할 class 파일을 선택 합니다.
3. 디컴파일 완료 메세지 확인 후 파일 내용확인 을 위해 디컴파일한 java 파일 열기 메뉴를 클릭 합니다.
4. 디컴파일 한 파일 내용확인 을 위해 디컴파일한 java 파일을 오픈한 화면(아래에 보시면 \uBC14 와 같은 16진수 바이트코드가 나옵니다. 한글유니코드로 정상으로 나타나도록 jad 디컴파일 -8 옵션을 추가해서 해결 하였습니다.
* 아래 자바소스에 위 외부실행 파일인 jad.exe를 같은 폴더에 위치 시키고, 이클립스에서 자바 프로젝트를 불러오기하시면 됩니다.(아래)
아래에 빌드한 javad.exe 실행파일도 올려 놓습니다. 실행파일도 외부 프로그램인 jad.exe가 같은 폴더에 있어야 합니다.(아래)
참고로 위와 같은 기능의 JD-gui 란 자바프로그램도 있습니다.
Free for non-commercial use 라이센스
(
http://jd.benow.ca/
)
- 소스 javad.java 전문을 아래에 올려 놓았습니다.
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import javax.swing.JLabel;
public class Javad extends Frame implements ActionListener {
/**
* FileDialog 예제입니다. 간단하게 파일을 열고, 저장할때 사용되는 소스입니다.
* 덧붙여 파일다이얼로그 예제를 기반으로 jad[Free for non-commercial use 라이센스]를 이용한 디컴파일러 입니다.
*/
private static final long serialVersionUID = 1L;
MenuBar mb;
MenuItem item1, item2, item3, item4, itemHelp;
TextArea ta;
FileDialog openFD, saveFD;
Dialog dlg, dlgHelp;
Button okbtn, exitbtn;
Label la;
JLabel jla;
public Javad() {
__makeMenuBar();
__makeDialog();
__makeDialogHelp();
this.setTitle("자바디컴파일러 v0.1");
setMenuBar(mb);
ta = new TextArea();
add(ta);
// 프로그램창의 오른쪽상단 [x]닫기 이벤트 발생시
addWindowListener(new WindowAdapter() {
@SuppressWarnings("deprecation")
public void windowClosing(WindowEvent we) {
dlg.show();
}
});
//윈도우 화면 크기 조정
setSize(500, 500);
setVisible(true);
}
//16진수 바이트코드를 유니코드로 변환문제는 jad 디컴파일 -8 옵션으로 해결
/*
private String unicodeConvert(String str) {
StringBuilder sb = new StringBuilder();
char ch;
int len = str.length();
for (int i = 0; i < len; i++) {
ch = str.charAt(i);
if (ch == '\\' && str.charAt(i+1) == 'u') {
sb.append((char) Integer.parseInt(str.substring(i+2, i+6), 16));
i+=5;
continue;
}
sb.append(ch);
}
return sb.toString();
}
*/
//메뉴바 생성
private void __makeMenuBar() {
mb = new MenuBar();
// 메뉴바의 아이템 제작
Menu m1 = new Menu("파일");
item1 = new MenuItem("class선택 후 디컴파일");
item2 = new MenuItem("java열기");
item3 = new MenuItem("java저장");
item4 = new MenuItem("종료");
item1.addActionListener(this);
item2.addActionListener(this);
item3.addActionListener(this);
item4.addActionListener(this);
m1.add(item1);
m1.add(item2);
m1.add(item3);
m1.addSeparator();
m1.add(item4);
mb.add(m1);//메뉴바에 메뉴를 삽입
Menu m2 = new Menu("도움말");
itemHelp = new MenuItem("프로그램에 대해서");
itemHelp.addActionListener(this);
m2.add(itemHelp);
mb.add(m2);//메뉴바에 메뉴를 삽입
}
//종료 확인 다이얼로그 생성
private void __makeDialog() {
dlg = new Dialog(this, "종료");
dlg.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent we) {
dlg.dispose();
}
});
dlg.setSize(50, 100);
dlg.setLocation(400, 300);
la = new Label("진짜로 종료할까요?");
exitbtn = new Button("아니요");
exitbtn.addActionListener(this); //센서
okbtn = new Button("예");
okbtn.addActionListener(this); //센서
dlg.add("North", la);
Panel p = new Panel();
p.add(okbtn);
p.add(exitbtn);
dlg.add(p);
}
//도움말 확인 다이얼로그 생성
private void __makeDialogHelp() {
dlgHelp = new Dialog(this, "프로그램에 대해서");
dlgHelp.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent we) {
dlgHelp.dispose();
}
});
dlgHelp.setSize(400, 100);
dlgHelp.setLocation(40, 200);
jla = new JLabel("<html><body style='text-align:center'>제가 1번째로 만든 awt/swing사용 프로그램입니다.이 프로그램은<br>파일다이얼로그 예제를 기반으로 jad를 이용한 디컴파일러이고,<br>[Free for non-commercial use] 라이센스 입니다.</body></html>");
dlgHelp.add("North", jla);
}
@SuppressWarnings("deprecation")
public void actionPerformed(ActionEvent ae) {
FileInputStream fis = null;
BufferedReader br = null;
FileOutputStream fos = null;
PrintWriter pw = null;
Object obj = ae.getSource();
if (obj.equals(item1)) // 디컴파일
{
openFD = new FileDialog(this, "열기", FileDialog.LOAD);
openFD.show();
String file = openFD.getFile();
String dir = openFD.getDirectory();
//실행할 프로그램과 전달할 인수를 문자열 배열로 만든다.
try {
//Runtime.getRuntime().exec(dir + "\\jad -o -sjava -d"+dir+ " "+ dir + "\\" + file);
Runtime.getRuntime().exec("jad -o -8 -sjava "+ dir + "\\" + file);
ta.setText("");
//ta.append("저장경로 : \n" + dir + " 에\n디컴파일이 완료 되었습니다.");
if (file != null || dir != null) {
ta.append("javad실행경로에\n디컴파일이 완료 되었습니다.");
}else{
ta.append("선택된 파일이 없습니다.");
}
} catch (IOException e) {
System.err.println("에러! 외부 명령 실행에 실패했습니다.\n" + e.getMessage());
}
} else if (obj.equals(item2))// java열기
{
ta.setText("");
try {
//FileDialog을 화면에 생성함
openFD = new FileDialog(this, "열기", FileDialog.LOAD);
openFD.show();
String file = openFD.getFile();
String dir = openFD.getDirectory();
//ok를 누른경우만 처리된다.(file이 null이면 취소버튼를 누른걸로 간주된다.)
if (file != null || dir != null) {
ta.append("file : " + file);
ta.append("f_open_dir : " + dir + "\n");
fis = new FileInputStream(dir + "\\" + file);
br = new BufferedReader(new InputStreamReader(fis));
String str = null;
while ((str = br.readLine()) != null) {
ta.append(str + "\r\n"); // 캐리지 리턴, 뉴라인
}
}
} catch (IOException ie) {
try {
br.close();
fis.close();
} catch (IOException ex) {
}
}
} else if (obj.equals(item3))// 수정한 내용 닫기
{
String content = ta.getText();
try {
//ta.append("저장 선택 \n");
saveFD = new FileDialog(this, "저장", FileDialog.SAVE);
saveFD.show();
String f_save = saveFD.getFile();
String f_save_dir = saveFD.getDirectory();
//ok를 누른경우만 처리된다.(f_save이 null이면 취소버튼를 누른걸로 간주된다.)
if (f_save != null || f_save_dir != null) {
fos = new FileOutputStream(f_save_dir + "\\" + f_save);
pw = new PrintWriter(fos, true);
pw.print(content);
pw.close();
fos.close();
}
} catch (IOException ie) {
}
} else if (obj.equals(itemHelp))// 프로그램도움말보기
{
dlgHelp.show();
// 버튼의 "예"를 누르면 종료(dlg.dispose()+dispose();)되게.. "아니오" 를 누르면 Dialog만 종료 dlg.dispose();
} else if (obj.equals(item4))// 프로그램종료
{
dlg.show();
} else if (obj.equals(okbtn)) {
dlg.dispose();
dispose();
} else
{
dlg.dispose();
}
}
public static void main(String args[]) {
new Javad();
}
}
/*
참고로, FileDialog는 ok, cancel 버튼이 나타나는데, cancel과 ok버튼이 눌렸는지 구분방법은 ok의 경우,
getFile()의 리턴값이 파일명을 가지지만, cancel의 경우는 null값을 가집니다. getDirectory() 함수도 마찬가지 입니다.
String file = openFD.getFile();
String dir = openFD.getDirectory();
*/
codenvy 온라인실습실에서 petclinic 사이트 작업02 (0) | 2017.07.26 |
---|---|
codenvy 온라인실습실에서 petclinic 사이트 작업01 (0) | 2017.07.19 |
이번에 스프링프레임웍 작업하면서, gitlab.com 에서 소스공유(비공개)로 공동작업을 하게 되었습니다 (0) | 2016.08.30 |
스프링 MVC로 입력 작업중 Mysql NOT NULL 조건이 먹히지 않을때 입니다. (0) | 2016.06.06 |
전자정부표준프레임웍 제대로 공부하기 (0) | 2016.03.25 |
댓글 영역