2 * Back 2 Browser Bytecode Translator
3 * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, version 2 of the License.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. Look for COPYING file in the top folder.
16 * If not, see http://opensource.org/licenses/GPL-2.0.
18 package org.apidesign.vm4brwsr;
20 import com.google.javascript.jscomp.CommandLineRunner;
21 import com.google.javascript.jscomp.SourceFile;
22 import java.io.IOException;
23 import java.io.OutputStream;
24 import java.io.PrintStream;
25 import java.util.ArrayList;
26 import java.util.Arrays;
27 import java.util.Collection;
28 import java.util.Collections;
29 import java.util.List;
30 import org.apidesign.bck2brwsr.core.ExtraJavaScript;
31 import org.apidesign.vm4brwsr.ByteCodeParser.ClassData;
32 import org.apidesign.vm4brwsr.ByteCodeParser.FieldData;
33 import org.apidesign.vm4brwsr.ByteCodeParser.MethodData;
37 * @author Jaroslav Tulach <jtulach@netbeans.org>
39 @ExtraJavaScript(processByteCode = false, resource="")
40 final class ClosureWrapper extends CommandLineRunner {
41 private static final String[] ARGS = { "--compilation_level", "SIMPLE_OPTIMIZATIONS", "--js", "bck2brwsr-raw.js" /*, "--debug", "--formatting", "PRETTY_PRINT" */ };
43 private final ClosuresObfuscationDelegate obfuscationDelegate;
44 private final Bck2Brwsr.Resources res;
45 private final StringArray classes;
47 private String compiledCode;
48 private String externsCode;
50 private ClosureWrapper(Appendable out,
51 String compilationLevel,
52 ClosuresObfuscationDelegate obfuscationDelegate,
53 Bck2Brwsr.Resources res, StringArray classes) {
55 generateArguments(compilationLevel),
56 new PrintStream(new APS(out)), System.err
58 this.obfuscationDelegate = obfuscationDelegate;
60 this.classes = classes;
64 protected List<SourceFile> createInputs(List<String> files, boolean allowStdIn) throws FlagUsageException, IOException {
65 if (files.size() != 1 || !"bck2brwsr-raw.js".equals(files.get(0))) {
66 throw new IOException("Unexpected files: " + files);
68 return Collections.nCopies(
70 SourceFile.fromGenerator(
72 new SourceFile.Generator() {
74 public String getCode() {
75 return getCompiledCode();
82 protected List<SourceFile> createExterns()
83 throws FlagUsageException, IOException {
84 final List<SourceFile> externsFiles =
85 new ArrayList<SourceFile>(super.createExterns());
88 SourceFile.fromGenerator(
89 "bck2brwsr_externs.js",
90 new SourceFile.Generator() {
92 public String getCode() {
93 return getExternsCode();
99 private String getCompiledCode() {
100 if (compiledCode == null) {
101 StringBuilder sb = new StringBuilder();
103 VM.compile(res, sb, classes, obfuscationDelegate);
104 compiledCode = sb.toString();
105 } catch (IOException ex) {
106 compiledCode = ex.getMessage();
112 private String getExternsCode() {
113 if (externsCode == null) {
114 // need compiled code at this point
117 final StringBuilder sb = new StringBuilder("function RAW() {};\n");
118 for (final String extern: obfuscationDelegate.getExterns()) {
119 sb.append("RAW.prototype.").append(extern).append(";\n");
121 externsCode = sb.toString();
126 private static final class APS extends OutputStream {
127 private final Appendable out;
129 public APS(Appendable out) {
133 public void write(int b) throws IOException {
138 private static String[] generateArguments(String compilationLevel) {
139 String[] finalArgs = ARGS.clone();
140 finalArgs[1] = compilationLevel;
145 static int produceTo(Appendable w, ObfuscationLevel obfuscationLevel, Bck2Brwsr.Resources resources, StringArray arr) throws IOException {
146 ClosureWrapper cw = create(w, obfuscationLevel, resources, arr);
149 } catch (FlagUsageException ex) {
150 throw new IOException(ex);
154 private static ClosureWrapper create(Appendable w,
155 ObfuscationLevel obfuscationLevel,
156 Bck2Brwsr.Resources resources,
158 switch (obfuscationLevel) {
160 return new ClosureWrapper(w, "SIMPLE_OPTIMIZATIONS",
161 new SimpleObfuscationDelegate(),
164 return new ClosureWrapper(w, "ADVANCED_OPTIMIZATIONS",
165 new MediumObfuscationDelegate(),
168 return new ClosureWrapper(w, "ADVANCED_OPTIMIZATIONS",
169 new FullObfuscationDelegate(),
172 throw new IllegalArgumentException(
173 "Unsupported level: " + obfuscationLevel);
177 private static abstract class ClosuresObfuscationDelegate
178 extends ObfuscationDelegate {
179 public abstract Collection<String> getExterns();
182 private static final class SimpleObfuscationDelegate
183 extends ClosuresObfuscationDelegate {
185 public void exportJSProperty(Appendable out,
187 String propertyName) throws IOException {
191 public void exportClass(Appendable out,
194 ClassData classData) throws IOException {
198 public void exportMethod(Appendable out,
201 MethodData methodData) throws IOException {
205 public void exportField(Appendable out,
208 FieldData fieldData) throws IOException {
212 public Collection<String> getExterns() {
213 return Collections.EMPTY_LIST;
217 private static abstract class AdvancedObfuscationDelegate
218 extends ClosuresObfuscationDelegate {
219 private static final String[] INITIAL_EXTERNS = {
261 "getClass__Ljava_lang_Class_2",
262 "clone__Ljava_lang_Object_2"
265 private final Collection<String> externs;
267 protected AdvancedObfuscationDelegate() {
268 externs = new ArrayList<String>(Arrays.asList(INITIAL_EXTERNS));
272 public void exportClass(Appendable out,
275 ClassData classData) throws IOException {
276 exportJSProperty(out, destObject, mangledName);
280 public void exportMethod(Appendable out,
283 MethodData methodData) throws IOException {
284 if ((methodData.access & ByteCodeParser.ACC_PRIVATE) == 0) {
285 exportJSProperty(out, destObject, mangledName);
290 public void exportField(Appendable out,
293 FieldData fieldData) throws IOException {
294 if ((fieldData.access & ByteCodeParser.ACC_PRIVATE) == 0) {
295 exportJSProperty(out, destObject, mangledName);
300 public Collection<String> getExterns() {
304 protected void addExtern(String extern) {
309 private static final class MediumObfuscationDelegate
310 extends AdvancedObfuscationDelegate {
312 public void exportJSProperty(Appendable out,
314 String propertyName) {
315 addExtern(propertyName);
319 private static final class FullObfuscationDelegate
320 extends AdvancedObfuscationDelegate {
322 public void exportJSProperty(Appendable out,
324 String propertyName) throws IOException {
325 out.append("\n").append(destObject).append("['")
326 .append(propertyName)
328 .append(destObject).append(".").append(propertyName)