package com.smtscript.lib.zip; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; import org.mozilla.javascript.Context; import org.mozilla.javascript.NativeArray; import org.mozilla.javascript.NativeFunction; import org.mozilla.javascript.NativeObject; import com.smtscript.lib.JSComment; import com.smtscript.lib.JSStaticZip; import com.smtscript.run.ScriptRunScope.FileInfo; import com.smtscript.run.ScriptRunScope.FileInfoFile; import com.smtscript.utils.SMTStatic; public class JSZipWriter { protected static class RunnableDataFile { public FileInfo _fileInfo; public String _entryName; public RunnableDataFile(FileInfo fileInfo, String entryName) { _fileInfo = fileInfo; _entryName = entryName; } } protected JSStaticZip _parent; protected ZipOutputStream _zip; public JSZipWriter(JSStaticZip parent, String zipFile) throws Exception { _parent = parent; _zip = new ZipOutputStream(new FileOutputStream(zipFile)); } public void close() throws IOException { if(_zip == null) return; _zip.close(); _zip = null; } public void createFolder(String folder) throws Exception { ZipEntry entry = new ZipEntry(folder + "/"); _zip.putNextEntry(entry); _zip.closeEntry(); } public void copyFile(String entryFile, String srcFile) throws Exception { FileInfo srcFileInfo = _parent.__parentScope__().__findExistFile__(srcFile, true); copyFile(entryFile, srcFileInfo); } public void copyText(String entryFile, String text) throws Exception { _zip.putNextEntry(new ZipEntry(entryFile)); ByteArrayInputStream bis = new ByteArrayInputStream(text.getBytes("UTF-8")); copyStream(bis, _zip); } protected void copyFile(String entryFile, FileInfo srcFileInfo) throws Exception { _zip.putNextEntry(new ZipEntry(entryFile)); try { copyStream(srcFileInfo.open(), _zip); } finally { srcFileInfo.close(); } _zip.closeEntry(); } @JSComment( "config : object\n" + " *class : String : main class name(default:com.smtscript.run.RunnableJar)\n" + " jar_files : Object : jar file list\n" + " *inc_lib: Boolean : include all lib jar files(false)\n" + " *files : String[] : jar file list\n" + " *filter: Function(name, path): filter jar file\n" + " *data_files: Object :\n" + " *files : Object[] :\n" + " file : file name\n" + " zip : zip entry name\n" + "" ) public void createRunnableJars(NativeObject config) throws Exception { Map listJars = new HashMap(); // 加入系统库jar包 NativeObject jarFileCfg = (NativeObject) SMTStatic.getJSValue(config, "jar_files"); // 扫描lib下的jar包 if((Boolean) SMTStatic.getJSValue(jarFileCfg, "inc_lib", true)) { // 扫描目录下的jar包 File libPath = this._parent.__parentScope__().__libPath__(); for(File jarFile : libPath.listFiles()) { String fileName = jarFile.getName().toLowerCase(); if(!fileName.endsWith(".jar") || fileName.equalsIgnoreCase("SMTScriptEditor.jar")) continue; FileInfo fileInfo = new FileInfoFile(jarFile); listJars.put(fileInfo.getShortName(), fileInfo); } } // 加入独立的jar文件 NativeArray jarFiles = (NativeArray) SMTStatic.getJSValue(jarFileCfg, "files", null); if(jarFiles != null) { for(int i = 0; i < jarFiles.size(); i ++) { String fileName = (String) SMTStatic.unwrapObject(jarFiles.get(i)); FileInfo fileInfo = this._parent.__parentScope__().__findExistFile__(fileName, true); listJars.put(fileInfo.getShortName(), fileInfo); } } // 加入数据文件 List dataFileList = new ArrayList(); NativeObject dataFileCfg = (NativeObject) SMTStatic.getJSValue(config, "data_files", null); // 加入独立的数据文件 if(dataFileCfg != null) { NativeArray dataFiles = (NativeArray) SMTStatic.getJSValue(dataFileCfg, "files", null); if(dataFiles != null) { for(int i = 0; i < dataFiles.size(); i ++) { NativeObject dataFile = (NativeObject) SMTStatic.unwrapObject(dataFiles.get(i)); String fileName = (String) SMTStatic.getJSValue(dataFile, "file"); FileInfo fileInfo = this._parent.__parentScope__().__findExistFile__(fileName, true); String zipName = (String) SMTStatic.getJSValue(dataFile, "zip", fileInfo.getShortName()); dataFileList.add(new RunnableDataFile(fileInfo, zipName)); } } } // 获取执行主类 String mainClass = (String) SMTStatic.getJSValue(config, "class", "com.smtscript.run.RunnableJar"); Context cx = this._parent.__parentScope__().__runtime__().entryContext(); try { // 插入自运行的类 copyRunnableJars(); // 插入jar包的文件 StringBuilder sbJarNames = new StringBuilder(); NativeFunction filterJar = (NativeFunction) SMTStatic.getJSValue(jarFileCfg, "filter", null); for(Entry entry : listJars.entrySet()) { if(filterJar != null) { Object value = filterJar.call(cx, filterJar, null, new Object[]{entry.getKey(), entry.getValue().getName()}); if(value instanceof Boolean && !(Boolean)value) continue; } copyFile(entry.getKey(), entry.getValue()); sbJarNames.append(" " + entry.getKey()); } // 插入数据文件 for(RunnableDataFile dataFile : dataFileList) { copyFile(dataFile._entryName, dataFile._fileInfo); } // 生成META-INF文件 StringBuilder sbText = new StringBuilder(); appendToMetaInfo("Manifest-Version: 1.0", sbText); appendToMetaInfo("Rsrc-Class-Path: ./" + sbJarNames.toString(), sbText); appendToMetaInfo("Class-Path: .", sbText); appendToMetaInfo("Rsrc-Main-Class: " + mainClass, sbText); appendToMetaInfo("Main-Class: org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader", sbText); copyText("META-INF/MANIFEST.MF", sbText.toString()); } finally { Context.exit(); } } protected void appendToMetaInfo(String line, StringBuilder sbText) { int pos = 0; for(int i = 0; i < line.length(); i ++) { if(pos > 70) { sbText.append("\n "); pos = 1; } sbText.append(line.charAt(i)); pos ++; } sbText.append("\n"); } protected void copyRunnableJars() throws Exception { String[] files = new String[]{ "JarRsrcLoader", "JarRsrcLoader$ManifestInfo", "JIJConstants", "RsrcURLConnection", "RsrcURLStreamHandler", "RsrcURLStreamHandlerFactory", }; for(String file : files) { copyResource( "org/eclipse/jdt/internal/jarinjarloader/" + file + ".class", "runablejar/" + file + ".class.dat"); } } public void copyResource(String entryFile, String srcFile) throws Exception { InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream(srcFile); if(is == null) throw new Exception("can't find resource : " + srcFile); _zip.putNextEntry(new ZipEntry(entryFile)); try { copyStream(is, _zip); } finally { is.close(); } _zip.closeEntry(); } public void copyEntry(JSZipReaderEntry entry) throws Exception { _zip.putNextEntry(new ZipEntry(entry._entry)); copyStream(entry._zip.getInputStream(entry._entry), _zip); _zip.closeEntry(); } private void copyStream(InputStream input, OutputStream output) throws IOException { int bytesRead; byte[] BUFFER = new byte[4096 * 1024]; while ((bytesRead = input.read(BUFFER))!= -1) { output.write(BUFFER, 0, bytesRead); } } }