package org.fangsoft.jar;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URL;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;public class SelfExtractor {
private int BUFFER_SIZE = 2046;
private File extractDir;
private File jarFile;

public SelfExtractor() {init();}
public SelfExtractor(int newBufferSize) {
this();
BUFFER_SIZE = newBufferSize;
jarFile = getEnclosingJar(this);
}
private void init(){
jarFile = getEnclosingJar(this);
String fileName=jarFile.getName();
int index=fileName.lastIndexOf(".");
       if(index!=-1)fileName=fileName.substring(0,index);
makeExtractDir(fileName);
}
private static String unescape(final String s) {
StringBuffer sb = new StringBuffer(s.length());
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
switch (c) {
case '%': {
try {
sb.append( (char) Integer.parseInt(s.substring(i + 1, i + 3), 16));
i += 2;
break;
}
catch (NumberFormatException nfe) {
throw new IllegalArgumentException();
}
catch (StringIndexOutOfBoundsException siob) {
String end = s.substring(i);
sb.append(end);
if (end.length() == 2) i++;
}
break;
}
default: {
sb.append(c);
break;
}
}
}
return sb.toString();
}
public static File getEnclosingJar(Object self) {
String className = "/" + self.getClass().getName().replace('.','/') + ".class";
URL jarUrl = self.getClass().getResource(className);
String urlStr = jarUrl.toString();
File file = null;
int index = urlStr.indexOf("!/");
if(index != -1){
String unescaped = null;
String fileNamePart = urlStr.substring("jar:file:".length(), index);
file = new File(fileNamePart);
if ( ! file.exists()) {
unescaped = unescape(fileNamePart);
file = new File(unescaped);
}
return file;
}
throw new RuntimeException("cannot open the jar file");
}
protected File makeExtractDir(String dir){
extractDir = new File(dir);
int index = 0;
while (extractDir.exists()) {
            extractDir = new File(dir + (index++));
        }
extractDir.mkdirs();
return extractDir;
}    
public void extract() throws FileNotFoundException, IOException {
JarInputStream zis = new JarInputStream(new FileInputStream(jarFile));
JarEntry entry=null;
while ((entry = zis.getNextJarEntry())!= null) {
if(entry.getName().equals("org/fangsoft/jar/SelfExtractor.class"))continue;
extract(zis, entry);
}
zis.close();
}
private void extract(JarInputStream zis, JarEntry entry) throws FileNotFoundException, IOException {
createPath(entry.getName());
File extractedFile = new File(extractDir, entry.getName());
if (entry.isDirectory())return;
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(extractedFile), BUFFER_SIZE);
byte[] bytes = new byte[BUFFER_SIZE];
int len = 0;
while ( (len = zis.read(bytes)) >= 0) {
bos.write(bytes, 0, len);
}
bos.close();
zis.closeEntry();
}
private void createPath(String entryName) throws IOException {
int slashIdx = entryName.lastIndexOf('/');
if (slashIdx >= 0) {
String firstPath = entryName.substring(0, slashIdx);
File dir = new File(extractDir, firstPath);
if (!dir.exists()) {
dir.mkdirs();
}
}
}
    


public static void main(String[] args) throws FileNotFoundException, IOException {
SelfExtractor extractor = new SelfExtractor();
extractor.extract();
}
}