jaroslav@106: /** jaroslav@106: * Back 2 Browser Bytecode Translator jaroslav@106: * Copyright (C) 2012 Jaroslav Tulach jaroslav@106: * jaroslav@106: * This program is free software: you can redistribute it and/or modify jaroslav@106: * it under the terms of the GNU General Public License as published by jaroslav@106: * the Free Software Foundation, version 2 of the License. jaroslav@106: * jaroslav@106: * This program is distributed in the hope that it will be useful, jaroslav@106: * but WITHOUT ANY WARRANTY; without even the implied warranty of jaroslav@106: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the jaroslav@106: * GNU General Public License for more details. jaroslav@106: * jaroslav@106: * You should have received a copy of the GNU General Public License jaroslav@106: * along with this program. Look for COPYING file in the top folder. jaroslav@106: * If not, see http://opensource.org/licenses/GPL-2.0. jaroslav@106: */ jaroslav@29: package org.apidesign.vm4brwsr; jaroslav@29: jaroslav@29: import java.io.BufferedWriter; jaroslav@1058: import java.io.File; jaroslav@1762: import java.io.FileOutputStream; jaroslav@29: import java.io.IOException; jaroslav@1762: import java.io.OutputStreamWriter; jaroslav@29: import java.io.Writer; lubomir@1020: import java.net.URI; lubomir@1020: import java.net.URISyntaxException; lubomir@1020: import java.net.URL; lubomir@1020: import java.util.Enumeration; lubomir@1020: import java.util.jar.JarEntry; lubomir@1020: import java.util.jar.JarFile; jaroslav@29: jaroslav@136: /** Generator of JavaScript from bytecode of classes on classpath of the VM jaroslav@136: * with a Main method. jaroslav@29: * jaroslav@29: * @author Jaroslav Tulach jaroslav@29: */ jaroslav@136: final class Main { jaroslav@136: private Main() {} jaroslav@29: lubomir@1020: public static void main(String... args) throws IOException, URISyntaxException { jaroslav@881: final String obfuscate = "--obfuscatelevel"; lubomir@1029: final String extension = "--createextension"; lubomir@1029: jaroslav@29: if (args.length < 2) { jaroslav@298: System.err.println("Bck2Brwsr Translator from Java(tm) to JavaScript, (c) Jaroslav Tulach 2012"); lubomir@1029: System.err.print("Usage: java -cp ... -jar ... ["); jaroslav@881: System.err.print(obfuscate); jaroslav@881: System.err.print(" ["); jaroslav@881: boolean first = true; jaroslav@881: for (ObfuscationLevel l : ObfuscationLevel.values()) { jaroslav@881: if (!first) { jaroslav@881: System.err.print('|'); jaroslav@881: } jaroslav@881: System.err.print(l.name()); jaroslav@881: first = false; jaroslav@881: } lubomir@1029: System.err.print("]] ["); lubomir@1029: System.err.print(extension); jaroslav@881: System.err.println("] java/lang/Class org/your/App ..."); jaroslav@881: System.exit(9); jaroslav@29: } lubomir@1020: lubomir@1020: final ClassLoader mainClassLoader = Main.class.getClassLoader(); lubomir@1020: jaroslav@881: ObfuscationLevel obfLevel = ObfuscationLevel.NONE; lubomir@1029: boolean createExtension = false; jaroslav@881: StringArray classes = new StringArray(); jaroslav@881: String generateTo = null; jaroslav@881: for (int i = 0; i < args.length; i++) { jaroslav@881: if (obfuscate.equals(args[i])) { // NOI18N jaroslav@881: i++; jaroslav@881: try { jaroslav@881: obfLevel = ObfuscationLevel.valueOf(args[i]); jaroslav@881: } catch (Exception e) { jaroslav@881: System.err.print(obfuscate); jaroslav@881: System.err.print(" parameter needs to be followed by one of "); jaroslav@881: boolean first = true; jaroslav@881: for (ObfuscationLevel l : ObfuscationLevel.values()) { jaroslav@881: if (!first) { jaroslav@881: System.err.print(", "); jaroslav@881: } jaroslav@881: System.err.print(l.name()); jaroslav@881: first = false; jaroslav@881: } jaroslav@881: System.err.println(); jaroslav@881: System.exit(1); jaroslav@881: } jaroslav@881: continue; jaroslav@881: } lubomir@1029: if (extension.equals(args[i])) { // NOI18N lubomir@1029: createExtension = true; lubomir@1029: continue; lubomir@1029: } jaroslav@881: if (generateTo == null) { jaroslav@881: generateTo = args[i]; jaroslav@881: } else { lubomir@1020: collectClasses(classes, mainClassLoader, args[i]); jaroslav@881: } jaroslav@881: } jaroslav@1058: jaroslav@1058: File gt = new File(generateTo); jaroslav@1058: if (Boolean.getBoolean("skip.if.exists") && gt.isFile()) { jaroslav@1058: System.err.println("Skipping as " + gt + " exists."); jaroslav@1058: System.exit(0); jaroslav@1058: } jaroslav@1058: jaroslav@1762: try (Writer w = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(gt), "UTF-8"))) { jaroslav@1604: Bck2Brwsr c = Bck2Brwsr.newCompiler(). jaroslav@881: obfuscation(obfLevel). jaroslav@881: addRootClasses(classes.toArray()). jaroslav@1604: resources(new LdrRsrcs(Main.class.getClassLoader(), true)); jaroslav@1604: jaroslav@1604: if (createExtension) { jaroslav@1604: c = c.library(); jaroslav@1604: } jaroslav@1604: jaroslav@1604: c.generate(w); lubomir@281: } jaroslav@29: } lubomir@1020: lubomir@1020: private static void collectClasses( lubomir@1020: final StringArray dest, lubomir@1020: final ClassLoader cl, final String relativePath) lubomir@1020: throws IOException, URISyntaxException { lubomir@1020: final Enumeration urls = cl.getResources(relativePath); lubomir@1020: if (!urls.hasMoreElements()) { lubomir@1020: dest.add(relativePath); lubomir@1020: return; lubomir@1020: } lubomir@1020: do { lubomir@1020: final URL url = urls.nextElement(); lubomir@1020: switch (url.getProtocol()) { lubomir@1020: case "file": lubomir@1020: collectClasses(dest, relativePath, lubomir@1020: new File(new URI(url.toString()))); lubomir@1020: continue; lubomir@1020: case "jar": lubomir@1020: final String fullPath = url.getPath(); lubomir@1020: final int sepIndex = fullPath.indexOf('!'); lubomir@1020: final String jarFilePath = lubomir@1020: (sepIndex != -1) ? fullPath.substring(0, sepIndex) lubomir@1020: : fullPath; lubomir@1020: lubomir@1020: final URI jarUri = new URI(jarFilePath); lubomir@1020: if (jarUri.getScheme().equals("file")) { lubomir@1020: try (JarFile jarFile = new JarFile(new File(jarUri))) { lubomir@1020: collectClasses(dest, relativePath, jarFile); lubomir@1020: continue; lubomir@1020: } lubomir@1020: } lubomir@1020: break; lubomir@1020: } lubomir@1020: lubomir@1020: dest.add(relativePath); lubomir@1020: } while (urls.hasMoreElements()); lubomir@1020: } lubomir@1020: lubomir@1020: private static void collectClasses(final StringArray dest, lubomir@1020: final String relativePath, lubomir@1020: final File file) { lubomir@1020: if (file.isDirectory()) { lubomir@1020: final File[] subFiles = file.listFiles(); lubomir@1020: for (final File subFile: subFiles) { lubomir@1020: collectClasses(dest, lubomir@1020: extendPath(relativePath, subFile.getName()), lubomir@1020: subFile); lubomir@1020: } lubomir@1020: lubomir@1020: return; lubomir@1020: } lubomir@1020: lubomir@1020: final String filePath = file.getPath(); lubomir@1020: if (filePath.endsWith(".class")) { lubomir@1020: validateAndAddClass(dest, relativePath); lubomir@1020: } lubomir@1020: } lubomir@1020: lubomir@1020: private static void collectClasses(final StringArray dest, lubomir@1020: final String relativePath, lubomir@1020: final JarFile jarFile) { lubomir@1020: if (relativePath.endsWith(".class")) { lubomir@1020: if (jarFile.getJarEntry(relativePath) != null) { lubomir@1020: validateAndAddClass(dest, relativePath); lubomir@1020: } lubomir@1020: lubomir@1020: return; lubomir@1020: } lubomir@1020: lubomir@1020: final String expectedPrefix = lubomir@1020: relativePath.endsWith("/") ? relativePath lubomir@1020: : relativePath + '/'; lubomir@1020: final Enumeration entries = jarFile.entries(); lubomir@1020: while (entries.hasMoreElements()) { lubomir@1020: final JarEntry entry = entries.nextElement(); lubomir@1020: if (!entry.isDirectory()) { lubomir@1020: final String entryName = entry.getName(); lubomir@1020: if (entryName.startsWith(expectedPrefix) lubomir@1020: && entryName.endsWith(".class")) { lubomir@1020: validateAndAddClass(dest, entryName); lubomir@1020: } lubomir@1020: } lubomir@1020: } lubomir@1020: } lubomir@1020: lubomir@1020: private static String extendPath(final String relativePath, lubomir@1020: final String fileName) { lubomir@1020: return relativePath.endsWith("/") ? relativePath + fileName lubomir@1020: : relativePath + '/' + fileName; lubomir@1020: } lubomir@1020: lubomir@1020: private static void validateAndAddClass(final StringArray dest, lubomir@1020: final String relativePath) { lubomir@1020: final String className = lubomir@1020: relativePath.substring(0, relativePath.length() - 6); lubomir@1020: if (!className.endsWith("package-info")) { lubomir@1020: dest.add(className); lubomir@1020: } lubomir@1020: } jaroslav@29: }