Not logged in.  Login/Logout/Register | List snippets | | Create snippet | Upload image | Upload data

1581
LINES

< > BotCompany Repo | #1000438 // Default boot-up code for JavaX/Android 19 (backup)

JavaX source code (Android) - run with: the app

1  
import java.security.NoSuchAlgorithmException;
2  
import java.security.MessageDigest;
3  
import java.lang.reflect.*;
4  
import java.net.*;
5  
import javax.swing.*;
6  
import java.util.regex.*;
7  
import java.util.*;
8  
9  
import android.widget.*;
10  
import android.view.*;
11  
import android.content.Context;
12  
import android.app.Activity;
13  
import android.view.inputmethod.*;
14  
import java.util.Timer;
15  
import java.util.TimerTask;
16  
import java.io.*;
17  
18  
public class main {
19  
  static class Lg {
20  
    Activity context;
21  
    ScrollView sv;
22  
    TextView tv;
23  
    StringBuilder buf = new StringBuilder();
24  
    
25  
    Lg(Activity context) {
26  
      this.context = context;
27  
      sv = new ScrollView(context);
28  
      tv = new TextView(context);
29  
      tv.setText(buf.toString());
30  
      sv.addView(tv);
31  
    }
32  
    
33  
    View getView() {
34  
      return sv;
35  
    }
36  
    
37  
    void print(final String s) {
38  
      context.runOnUiThread(new Runnable() {
39  
        public void run() {
40  
          buf.append(s);
41  
          tv.setText(buf.toString());
42  
          
43  
          sv.post(new Runnable() {
44  
            public void run() {
45  
              // This method works but animates the scrolling 
46  
              // which looks weird on first load
47  
              sv.fullScroll(View.FOCUS_DOWN);
48  
49  
              // This method works even better because there are no animations.
50  
              //sv.scrollTo(0, sv.getBottom());
51  
            }
52  
          });
53  
        }
54  
      });
55  
    }
56  
    
57  
    void println(String s) {
58  
      print(s + "\n");
59  
    }
60  
  }
61  
  
62  
  public static View main(final Activity context) throws Exception {
63  
    x18.androidContext = context;
64  
    final File defSnip = new File(x18.userHome(), ".javax/defsnip");
65  
    String id = x18.loadTextFile(defSnip.getPath(), "675");
66  
67  
    ScrollView sv = new ScrollView(context);
68  
    LinearLayout ll = new LinearLayout(context);
69  
    ll.setOrientation(LinearLayout.VERTICAL);
70  
    
71  
    LinearLayout line1 = new LinearLayout(context);
72  
    
73  
    TextView label = new TextView(context);
74  
    label.setText("Run which snippet ID?");
75  
    line1.addView(label);
76  
    
77  
    final EditText tv = new EditText(context);
78  
    tv.setText(id);
79  
    line1.addView(tv);
80  
    
81  
    Button btnGo = new Button(context);
82  
    btnGo.setText("Go");
83  
    line1.addView(btnGo);
84  
    
85  
    ll.addView(line1);
86  
    
87  
    btnGo.setOnClickListener(new View.OnClickListener() {
88  
      public void onClick(View v) {
89  
        hideKeyboard(context);
90  
        String snippetID = tv.getText().toString();
91  
        String text = "Running: " + snippetID;
92  
        Toast.makeText(context, text, 2000).show();
93  
        
94  
        try {
95  
          x18.saveTextFile(defSnip.getPath(), snippetID);
96  
        } catch (IOException e) {
97  
        }
98  
        run(context, snippetID);
99  
      }
100  
    });
101  
102  
    sv.addView(ll);
103  
    return sv;
104  
  }
105  
  
106  
  static Lg lg;
107  
  
108  
  public static void run(final Activity context, final String mainSnippet) {
109  
    lg = new Lg(context);
110  
    
111  
    OutputStream outputStream = new OutputStream() {
112  
      public void write(int b) {
113  
        try {
114  
          lg.print(new String(new byte[] {(byte) b}, "UTF-8")); // This is crap
115  
        } catch (UnsupportedEncodingException e) {}
116  
      }
117  
      
118  
      @Override
119  
      public void write(byte[] b, int off, int len) {
120  
        try {
121  
          lg.print(new String(b, off, len, "UTF-8")); // This is crap
122  
        } catch (UnsupportedEncodingException e) {}
123  
      }
124  
    };
125  
    
126  
    PrintStream ps = new PrintStream(outputStream, true);
127  
    System.setOut(ps);
128  
    System.setErr(ps);
129  
    
130  
    new Thread() {
131  
      public void run() {
132  
        try {
133  
         
134  
          x18.main(new String[] {mainSnippet});
135  
        } catch (Throwable e) {
136  
          System.out.println("Whoa!");
137  
          e.printStackTrace();
138  
        }
139  
      }
140  
    }.start();
141  
    
142  
    context.setContentView(lg.getView());
143  
  }
144  
  
145  
  static void setContentViewInUIThread(final View view) {
146  
    ((Activity) x18.androidContext).runOnUiThread(new Runnable() {
147  
      public void run() {
148  
        ((Activity) x18.androidContext).setContentView(view);
149  
      }
150  
    });
151  
  }
152  
  
153  
  public static void hideKeyboard(Activity context) {   
154  
    View view = context.getCurrentFocus();
155  
    if (view != null) {
156  
        InputMethodManager inputManager = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
157  
        inputManager.hideSoftInputFromWindow(view.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
158  
    }
159  
  }
160  
}
161  
162  
/**
163  
 JavaX runner version 18
164  
165  
 Changes to v17:
166  
 -can run server-transpiled main programs for super-quick compilation
167  
  (no local transpiling except for nested solvers or something)
168  
 -making Android-aware (FileInputStream/FileOutputStream/other file stuff?)
169  
170  
 */
171  
172  
class x18 {
173  
  static final String version = "JavaX 18";
174  
175  
  static boolean verbose = false, translate = false, list = false, virtualizeTranslators = true;
176  
  static String translateTo = null;
177  
  static boolean preferCached = false, safeOnly = false, noID = false, noPrefetch = false;
178  
  static List<String[]> mainTranslators = new ArrayList<String[]>();
179  
  private static Map<Long, String> memSnippetCache = new HashMap<Long, String>();
180  
  private static int processesStarted, compilations;
181  
182  
  // snippet ID -> md5
183  
  private static HashMap<Long, String> prefetched = new HashMap<Long, String>();
184  
  private static File virtCache;
185  
186  
  // doesn't work yet
187  
  private static Map<String, Class<?>> programCache = new HashMap<String, Class<?>>();
188  
  static boolean cacheTranslators = false;
189  
190  
  // this should work (caches transpiled translators)
191  
  private static HashMap<Long, Object[]> translationCache = new HashMap<Long, Object[]>();
192  
  static boolean cacheTranspiledTranslators = true;
193  
194  
  // which snippets are available pre-transpiled server-side?
195  
  private static Set<Long> hasTranspiledSet = new HashSet<Long>();
196  
  static boolean useServerTranspiled = true;
197  
198  
  static Object androidContext;
199  
  static boolean android = isAndroid();
200  
201  
  public static void main(String[] args) throws Exception {
202  
    File ioBaseDir = new File("."), inputDir = null, outputDir = null;
203  
    String src = null;
204  
    List<String> programArgs = new ArrayList<String>();
205  
206  
    for (int i = 0; i < args.length; i++) {
207  
      String arg = args[i];
208  
209  
      if (arg.equals("-version")) {
210  
        showVersion();
211  
        return;
212  
      }
213  
214  
      if (arg.equals("-sysprop")) {
215  
        showSystemProperties();
216  
        return;
217  
      }
218  
219  
      if (arg.equals("-v") || arg.equals("-verbose"))
220  
        verbose = true;
221  
      else if (arg.equals("-finderror"))
222  
        verbose = true;
223  
      else if (arg.equals("-offline") || arg.equalsIgnoreCase("-prefercached"))
224  
        preferCached = true;
225  
      else if (arg.equals("-novirt"))
226  
        virtualizeTranslators = false;
227  
      else if (arg.equals("-safeonly"))
228  
        safeOnly = true;
229  
      else if (arg.equals("-noid"))
230  
        noID = true;
231  
      else if (arg.equals("-nocachetranspiled"))
232  
        cacheTranspiledTranslators = false;
233  
      else if (arg.equals("-localtranspile"))
234  
        useServerTranspiled = false;
235  
      else if (arg.equals("translate"))
236  
        translate = true;
237  
      else if (arg.equals("list")) {
238  
        list = true;
239  
        virtualizeTranslators = false; // so they are silenced
240  
      } else if (arg.equals("run")) {
241  
        // it's the default command anyway
242  
      } else if (arg.startsWith("input="))
243  
        inputDir = new File(arg.substring(6));
244  
      else if (arg.startsWith("output="))
245  
        outputDir = new File(arg.substring(7));
246  
      else if (arg.equals("with"))
247  
        mainTranslators.add(new String[] {args[++i], null});
248  
      else if (translate && arg.equals("to"))
249  
        translateTo = args[++i];
250  
      else if (src == null) {
251  
        //System.out.println("src=" + arg);
252  
        src = arg;
253  
      } else
254  
        programArgs.add(arg);
255  
    }
256  
257  
    cleanCache();
258  
259  
    if (useServerTranspiled)
260  
      noPrefetch = true;
261  
262  
    if (src == null) src = ".";
263  
264  
    // Might actually want to write to 2 disk caches (global/per program).
265  
    if (virtualizeTranslators && !preferCached)
266  
      virtCache = TempDirMaker_make();
267  
268  
    if (inputDir != null) {
269  
      ioBaseDir = TempDirMaker_make();
270  
      System.out.println("Taking input from: " + inputDir.getAbsolutePath());
271  
      System.out.println("Output is in: " + new File(ioBaseDir, "output").getAbsolutePath());
272  
      copyInput(inputDir, new File(ioBaseDir, "input"));
273  
    }
274  
275  
    javaxmain(src, ioBaseDir, translate, list, programArgs.toArray(new String[programArgs.size()]));
276  
277  
    if (outputDir != null) {
278  
      copyInput(new File(ioBaseDir, "output"), outputDir);
279  
      System.out.println("Output copied to: " + outputDir.getAbsolutePath());
280  
    }
281  
282  
    if (verbose) {
283  
      // print stats
284  
      System.out.println("Processes started: " + processesStarted + ", compilations: " + compilations);
285  
    }
286  
  }
287  
288  
  public static void javaxmain(String src, File ioDir, boolean translate, boolean list,
289  
                               String[] args) throws Exception {
290  
    List<File> libraries = new ArrayList<File>();
291  
    File X = transpileMain(src, libraries);
292  
    if (X == null)
293  
      return;
294  
295  
    // list or run
296  
297  
    if (translate) {
298  
      File to = X;
299  
      if (translateTo != null)
300  
        if (new File(translateTo).isDirectory())
301  
          to = new File(translateTo, "main.java");
302  
        else
303  
          to = new File(translateTo);
304  
      if (to != X)
305  
        copy(new File(X, "main.java"), to);
306  
      System.out.println("Program translated to: " + to.getAbsolutePath());
307  
    } else if (list)
308  
      System.out.println(loadTextFile(new File(X, "main.java").getPath(), null));
309  
    else
310  
      javax2(X, ioDir, false, false, libraries, args, null);
311  
  }
312  
313  
  static File transpileMain(String src, List<File> libraries) throws Exception {
314  
    File srcDir;
315  
    boolean isTranspiled = false;
316  
    if (isSnippetID(src)) {
317  
      prefetch(src);
318  
      long id = parseSnippetID(src);
319  
      srcDir = loadSnippetAsMainJava(src);
320  
      if (hasTranspiledSet.contains(id)) {
321  
        System.err.println("Trying pretranspiled main program: #" + id);
322  
        String transpiledSrc = getServerTranspiled("#" + id);
323  
        if (!transpiledSrc.isEmpty()) {
324  
          srcDir = TempDirMaker_make();
325  
          saveTextFile(new File(srcDir, "main.java").getPath(), transpiledSrc);
326  
          isTranspiled = true;
327  
          //translationCache.put(id, new Object[] {srcDir, libraries});
328  
        }
329  
      }
330  
    } else {
331  
      srcDir = new File(src);
332  
333  
      // if the argument is a file, it is assumed to be main.java
334  
      if (srcDir.isFile()) {
335  
        srcDir = TempDirMaker_make();
336  
        copy(new File(src), new File(srcDir, "main.java"));
337  
      }
338  
339  
      if (!new File(srcDir, "main.java").exists()) {
340  
        showVersion();
341  
        System.out.println("No main.java found, exiting");
342  
        return null;
343  
      }
344  
    }
345  
346  
    // translate
347  
348  
    File X = srcDir;
349  
350  
    if (!isTranspiled) {
351  
      X = topLevelTranslate(X, libraries);
352  
      System.err.println("Translated " + src);
353  
354  
      // save prefetch data
355  
      if (isSnippetID(src))
356  
        savePrefetchData(src);
357  
    }
358  
    return X;
359  
  }
360  
361  
  private static void prefetch(String mainSnippetID) throws IOException {
362  
    if (noPrefetch) return;
363  
364  
    long mainID = parseSnippetID(mainSnippetID);
365  
    String s = mainID + " " + loadTextFile(new File(userHome(), ".tinybrain/prefetch/" + mainID + ".txt").getPath(), "");
366  
    String[] ids = s.trim().split(" ");
367  
    if (ids.length > 1) {
368  
      String url = "http://tinybrain.de:8080/tb-int/prefetch.php?ids=" + URLEncoder.encode(s, "UTF-8");
369  
      String data = loadPage(new URL(url));
370  
      String[] split = data.split(" ");
371  
      if (split.length == ids.length)
372  
        for (int i = 0; i < ids.length; i++)
373  
          prefetched.put(parseSnippetID(ids[i]), split[i]);
374  
    }
375  
  }
376  
377  
  static String userHome() {
378  
    if (android)
379  
      return ((File) call(androidContext, "getFilesDir")).getAbsolutePath();
380  
    else
381  
      return System.getProperty("user.home");
382  
  }
383  
384  
  private static void savePrefetchData(String mainSnippetID) throws IOException {
385  
    List<String> ids = new ArrayList<String>();
386  
    long mainID = parseSnippetID(mainSnippetID);
387  
388  
    for (long id : memSnippetCache.keySet())
389  
      if (id != mainID)
390  
        ids.add(String.valueOf(id));
391  
392  
    saveTextFile(new File(userHome(),".tinybrain/prefetch/" + mainID + ".txt").getPath(), join(" ", ids));
393  
  }
394  
395  
  static File topLevelTranslate(File srcDir, List<File> libraries_out) throws Exception {
396  
    File X = srcDir;
397  
    X = applyTranslators(X, mainTranslators, libraries_out); // translators supplied on command line (unusual)
398  
399  
    // actual inner translation of the JavaX source
400  
    X = defaultTranslate(X, libraries_out);
401  
    return X;
402  
  }
403  
404  
  private static File defaultTranslate(File x, List<File> libraries_out) throws Exception {
405  
    x = luaPrintToJavaPrint(x);
406  
    x = repeatAutoTranslate(x, libraries_out);
407  
    return x;
408  
  }
409  
410  
  private static File repeatAutoTranslate(File x, List<File> libraries_out) throws Exception {
411  
    while (true) {
412  
      File y = autoTranslate(x, libraries_out);
413  
      if (y == x)
414  
        return x;
415  
      x = y;
416  
    }
417  
  }
418  
419  
  private static File autoTranslate(File x, List<File> libraries_out) throws Exception {
420  
    String main = loadTextFile(new File(x, "main.java").getPath(), null);
421  
    List<String> lines = toLines(main);
422  
    List<String[]> translators = findTranslators(lines);
423  
    if (translators.isEmpty())
424  
      return x;
425  
426  
    main = fromLines(lines);
427  
    File newDir = TempDirMaker_make();
428  
    saveTextFile(new File(newDir, "main.java").getPath(), main);
429  
    return applyTranslators(newDir, translators, libraries_out);
430  
  }
431  
432  
  private static List<String[]> findTranslators(List<String> lines) {
433  
    List<String[]> translators = new ArrayList<String[]>();
434  
    Pattern pattern = Pattern.compile("^!([0-9# \t]+)");
435  
    Pattern pArgs = Pattern.compile("^\\s*\\((.*)\\)");
436  
    for (ListIterator<String> iterator = lines.listIterator(); iterator.hasNext(); ) {
437  
      String line = iterator.next();
438  
      line = line.trim();
439  
      Matcher matcher = pattern.matcher(line);
440  
      if (matcher.find()) {
441  
        String[] t = matcher.group(1).split("[ \t]+");
442  
        String rest = line.substring(matcher.end());
443  
        String arg = null;
444  
        if (t.length == 1) {
445  
          Matcher mArgs = pArgs.matcher(rest);
446  
          if (mArgs.find())
447  
            arg = mArgs.group(1);
448  
        }
449  
        for (String transi : t)
450  
          translators.add(new String[]{transi, arg});
451  
        iterator.remove();
452  
      }
453  
    }
454  
    return translators;
455  
  }
456  
457  
  public static List<String> toLines(String s) {
458  
    List<String> lines = new ArrayList<String>();
459  
    int start = 0;
460  
    while (true) {
461  
      int i = toLines_nextLineBreak(s, start);
462  
      if (i < 0) {
463  
        if (s.length() > start) lines.add(s.substring(start));
464  
        break;
465  
      }
466  
467  
      lines.add(s.substring(start, i));
468  
      if (s.charAt(i) == '\r' && i+1 < s.length() && s.charAt(i+1) == '\n')
469  
        i += 2;
470  
      else
471  
        ++i;
472  
473  
      start = i;
474  
    }
475  
    return lines;
476  
  }
477  
478  
  private static int toLines_nextLineBreak(String s, int start) {
479  
    for (int i = start; i < s.length(); i++) {
480  
      char c = s.charAt(i);
481  
      if (c == '\r' || c == '\n')
482  
        return i;
483  
    }
484  
    return -1;
485  
  }
486  
487  
  public static String fromLines(List<String> lines) {
488  
    StringBuilder buf = new StringBuilder();
489  
    for (String line : lines) {
490  
      buf.append(line).append('\n');
491  
    }
492  
    return buf.toString();
493  
  }
494  
495  
  private static File applyTranslators(File x, List<String[]> translators, List<File> libraries_out) throws Exception {
496  
    for (String[] translator : translators)
497  
      x = applyTranslator(x, translator[0], translator[1], libraries_out);
498  
    return x;
499  
  }
500  
501  
  // also takes a library
502  
  private static File applyTranslator(File x, String translator, String arg, List<File> libraries_out) throws Exception {
503  
    if (verbose)
504  
      System.out.println("Using translator " + translator + " on sources in " + x.getPath());
505  
506  
    File newDir = runTranslatorOnInput(translator, null, arg, x, !verbose, libraries_out);
507  
508  
    if (!new File(newDir, "main.java").exists()) {
509  
      throw new Exception("Translator " + translator + " did not generate main.java");
510  
      // TODO: show translator output
511  
    }
512  
    if (verbose)
513  
      System.out.println("Translated with " + translator + " from " + x.getPath() + " to " + newDir.getPath());
514  
    x = newDir;
515  
    return x;
516  
  }
517  
518  
  private static File luaPrintToJavaPrint(File x) throws IOException {
519  
    File newDir = TempDirMaker_make();
520  
    String code = loadTextFile(new File(x, "main.java").getPath(), null);
521  
    code = luaPrintToJavaPrint(code);
522  
    if (verbose)
523  
      System.out.println(code);
524  
    saveTextFile(new File(newDir, "main.java").getPath(), code);
525  
    return newDir;
526  
  }
527  
528  
  public static String luaPrintToJavaPrint(String code) {
529  
    return ("\n" + code).replaceAll(
530  
      "(\n\\s*)print (\".*\")",
531  
      "$1System.out.println($2);").substring(1);
532  
  }
533  
534  
  public static File loadSnippetAsMainJava(String snippetID) throws IOException {
535  
    checkProgramSafety(snippetID);
536  
    File srcDir = TempDirMaker_make();
537  
    saveTextFile(new File(srcDir, "main.java").getPath(), loadSnippet(snippetID));
538  
    return srcDir;
539  
  }
540  
541  
  public static File loadSnippetAsMainJavaVerified(String snippetID, String hash) throws IOException {
542  
    checkProgramSafety(snippetID);
543  
    File srcDir = TempDirMaker_make();
544  
    saveTextFile(new File(srcDir, "main.java").getPath(), loadSnippetVerified(snippetID, hash));
545  
    return srcDir;
546  
  }
547  
548  
  /** returns output dir */
549  
  private static File runTranslatorOnInput(String snippetID, String hash, String arg, File input,
550  
                                           boolean silent,
551  
                                           List<File> libraries_out) throws Exception {
552  
    long id = parseSnippetID(snippetID);
553  
    File libraryFile = DiskSnippetCache_getLibrary(id);
554  
    if (libraryFile != null) {
555  
      loadLibrary(snippetID, libraries_out, libraryFile);
556  
      return input;
557  
    }
558  
559  
    String[] args = arg != null ? new String[]{arg} : new String[0];
560  
561  
    File srcDir = hash == null ? loadSnippetAsMainJava(snippetID)
562  
      : loadSnippetAsMainJavaVerified(snippetID, hash);
563  
    long mainJavaSize = new File(srcDir, "main.java").length();
564  
565  
    if (mainJavaSize == 0) { // no text in snippet? assume it's a library
566  
      loadLibrary(snippetID, libraries_out, libraryFile);
567  
      return input;
568  
    }
569  
570  
    List<File> libraries = new ArrayList<File>();
571  
    Object[] cached = translationCache.get(id);
572  
    if (cached != null) {
573  
      //System.err.println("Taking translator " + snippetID + " from cache!");
574  
      srcDir = (File) cached[0];
575  
      libraries = (List<File>) cached[1];
576  
    } else if (hasTranspiledSet.contains(id)) {
577  
      System.err.println("Trying pretranspiled translator: #" + snippetID);
578  
      String transpiledSrc = getServerTranspiled(snippetID);
579  
      if (!transpiledSrc.isEmpty()) {
580  
        srcDir = TempDirMaker_make();
581  
        saveTextFile(new File(srcDir, "main.java").getPath(), transpiledSrc);
582  
        translationCache.put(id, cached = new Object[] {srcDir, libraries});
583  
      }
584  
    }
585  
586  
    File ioBaseDir = TempDirMaker_make();
587  
588  
    /*Class<?> mainClass = programCache.get("" + parseSnippetID(snippetID));
589  
    if (mainClass != null)
590  
      return runCached(ioBaseDir, input, args);*/
591  
    // Doesn't work yet because virtualized directories are hardcoded in translator...
592  
593  
    if (cached == null) {
594  
      System.err.println("Translating translator #" + id);
595  
      srcDir = defaultTranslate(srcDir, libraries);
596  
      System.err.println("Translated translator #" + id);
597  
      if (cacheTranspiledTranslators)
598  
        translationCache.put(id, new Object[]{srcDir, libraries});
599  
    }
600  
601  
    boolean runInProcess = false;
602  
603  
    if (virtualizeTranslators) {
604  
      if (verbose) System.out.println("Virtualizing translator");
605  
606  
      //srcDir = applyTranslator(srcDir, "#2000351"); // I/O-virtualize the translator
607  
      // that doesn't work because it recurses infinitely...
608  
609  
      // So we do it right here:
610  
      String s = loadTextFile(new File(srcDir, "main.java").getPath(), null);
611  
      s = s.replaceAll("new\\s+File\\(", "virtual.newFile(");
612  
      s = s.replaceAll("new\\s+FileInputStream\\(", "virtual.newFileInputStream(");
613  
      s = s.replaceAll("new\\s+FileOutputStream\\(", "virtual.newFileOutputStream(");
614  
      s += "\n\n" + loadSnippet("#2000355"); // load class virtual
615  
616  
      // change baseDir
617  
      s = s.replace("virtual_baseDir = \"\";",
618  
        "virtual_baseDir = " + javaQuote(ioBaseDir.getAbsolutePath()) + ";");
619  
620  
      // forward snippet cache (virtualized one)
621  
      File dir = virtCache != null ? virtCache : DiskSnippetCache_dir;
622  
      s = s.replace("static File DiskSnippetCache_dir;",
623  
        "static File DiskSnippetCache_dir = new File(" + javaQuote(dir.getAbsolutePath()) + ");");
624  
      s = s.replace("static boolean preferCached = false;", "static boolean preferCached = true;");
625  
626  
      if (verbose) {
627  
        System.out.println("==BEGIN VIRTUALIZED TRANSLATOR==");
628  
        System.out.println(s);
629  
        System.out.println("==END VIRTUALIZED TRANSLATOR==");
630  
      }
631  
      srcDir = TempDirMaker_make();
632  
      saveTextFile(new File(srcDir, "main.java").getPath(), s);
633  
634  
      // TODO: silence translator also
635  
      runInProcess = true;
636  
    }
637  
638  
    return runJavaX(ioBaseDir, srcDir, input, silent, runInProcess, libraries,
639  
      args, cacheTranslators ? "" + id : null);
640  
  }
641  
642  
  private static String getServerTranspiled(String snippetID) throws IOException {
643  
    long id = parseSnippetID(snippetID);
644  
    URL url = new URL("http://tinybrain.de:8080/tb-int/get-transpiled.php?raw=1&id=" + id);
645  
    return loadPage(url);
646  
  }
647  
648  
  static void checkProgramSafety(String snippetID) throws IOException {
649  
    if (!safeOnly) return;
650  
    URL url = new URL("http://tinybrain.de:8080/tb-int/is-javax-safe.php?id=" + parseSnippetID(snippetID));
651  
    String text = loadPage(url);
652  
    if (!text.startsWith("{\"safe\":\"1\"}"))
653  
      throw new RuntimeException("Translator not safe: #" + parseSnippetID(snippetID));
654  
  }
655  
656  
  private static void loadLibrary(String snippetID, List<File> libraries_out, File libraryFile) throws IOException {
657  
    if (verbose)
658  
      System.out.println("Assuming " + snippetID + " is a library.");
659  
660  
    if (libraryFile == null) {
661  
      byte[] data = loadDataSnippetImpl(snippetID);
662  
      DiskSnippetCache_putLibrary(parseSnippetID(snippetID), data);
663  
      libraryFile = DiskSnippetCache_getLibrary(parseSnippetID(snippetID));
664  
    }
665  
666  
    if (!libraries_out.contains(libraryFile))
667  
      libraries_out.add(libraryFile);
668  
  }
669  
670  
  private static byte[] loadDataSnippetImpl(String snippetID) throws IOException {
671  
    byte[] data;
672  
    try {
673  
      URL url = new URL("http://eyeocr.sourceforge.net/filestore/filestore.php?cmd=serve&file=blob_"
674  
        + parseSnippetID(snippetID) + "&contentType=application/binary");
675  
      System.err.println("Loading library: " + url);
676  
      data = loadBinaryPage(url.openConnection());
677  
      if (verbose)
678  
        System.err.println("Bytes loaded: " + data.length);
679  
    } catch (FileNotFoundException e) {
680  
      throw new IOException("Binary snippet #" + snippetID + " not found or not public");
681  
    }
682  
    return data;
683  
  }
684  
685  
  /** returns output dir */
686  
  private static File runJavaX(File ioBaseDir, File originalSrcDir, File originalInput,
687  
                               boolean silent, boolean runInProcess,
688  
                               List<File> libraries, String[] args, String cacheAs) throws Exception {
689  
    File srcDir = new File(ioBaseDir, "src");
690  
    File inputDir = new File(ioBaseDir, "input");
691  
    File outputDir = new File(ioBaseDir, "output");
692  
    copyInput(originalSrcDir, srcDir);
693  
    copyInput(originalInput, inputDir);
694  
    javax2(srcDir, ioBaseDir, silent, runInProcess, libraries, args, cacheAs);
695  
    return outputDir;
696  
  }
697  
698  
  private static void copyInput(File src, File dst) throws IOException {
699  
    copyDirectory(src, dst);
700  
  }
701  
702  
  public static boolean hasFile(File inputDir, String name) {
703  
    return new File(inputDir, name).exists();
704  
  }
705  
706  
  public static void copyDirectory(File src, File dst) throws IOException {
707  
    if (verbose) System.out.println("Copying " + src.getAbsolutePath() + " to " + dst.getAbsolutePath());
708  
    dst.mkdirs();
709  
    File[] files = src.listFiles();
710  
    if (files == null) return;
711  
    for (File file : files) {
712  
      File dst1 = new File(dst, file.getName());
713  
      if (file.isDirectory())
714  
        copyDirectory(file, dst1);
715  
      else {
716  
        if (verbose) System.out.println("Copying " + file.getAbsolutePath() + " to " + dst1.getAbsolutePath());
717  
        copy(file, dst1);
718  
      }
719  
    }
720  
  }
721  
722  
  /** Quickly copy a file without a progress bar or any other fancy GUI... :) */
723  
  public static void copy(File src, File dest) throws IOException {
724  
    FileInputStream inputStream = newFileInputStream(src);
725  
    FileOutputStream outputStream = newFileOutputStream(dest);
726  
    try {
727  
      copy(inputStream, outputStream);
728  
      inputStream.close();
729  
    } finally {
730  
      outputStream.close();
731  
    }
732  
  }
733  
734  
  static Object call(Object o, String method, Object... args) {
735  
    try {
736  
      Method m = call_findMethod(o, method, args, false);
737  
      m.setAccessible(true);
738  
      return m.invoke(o, args);
739  
    } catch (Exception e) {
740  
      throw new RuntimeException(e);
741  
    }
742  
  }
743  
744  
  static Object call(Class c, String method, Object... args) {
745  
    try {
746  
      Method m = call_findStaticMethod(c, method, args, false);
747  
      m.setAccessible(true);
748  
      return m.invoke(null, args);
749  
    } catch (Exception e) {
750  
      throw new RuntimeException(e);
751  
    }
752  
  }
753  
754  
  static Method call_findStaticMethod(Class c, String method, Object[] args, boolean debug) {
755  
    while (c != null) {
756  
      for (Method m : c.getDeclaredMethods()) {
757  
        if (debug)
758  
          System.out.println("Checking method " + m.getName() + " with " + m.getParameterTypes().length + " parameters");;
759  
        if (!m.getName().equals(method)) {
760  
          if (debug) System.out.println("Method name mismatch: " + method);
761  
          continue;
762  
        }
763  
764  
        if ((m.getModifiers() & Modifier.STATIC) == 0 || !call_checkArgs(m, args, debug))
765  
          continue;
766  
767  
        return m;
768  
      }
769  
      c = c.getSuperclass();
770  
    }
771  
    throw new RuntimeException("Method '" + method + "' (static) with " + args.length + " parameter(s) not found in " + c.getName());
772  
  }
773  
774  
  static Method call_findMethod(Object o, String method, Object[] args, boolean debug) {
775  
    Class c = o.getClass();
776  
    while (c != null) {
777  
      for (Method m : c.getDeclaredMethods()) {
778  
        if (debug)
779  
          System.out.println("Checking method " + m.getName() + " with " + m.getParameterTypes().length + " parameters");;
780  
        if (m.getName().equals(method) && call_checkArgs(m, args, debug))
781  
          return m;
782  
      }
783  
      c = c.getSuperclass();
784  
    }
785  
    throw new RuntimeException("Method '" + method + "' (non-static) with " + args.length + " parameter(s) not found in " + o.getClass().getName());
786  
  }
787  
788  
  private static boolean call_checkArgs(Method m, Object[] args, boolean debug) {
789  
    Class<?>[] types = m.getParameterTypes();
790  
    if (types.length != args.length) {
791  
      if (debug)
792  
        System.out.println("Bad parameter length: " + args.length + " vs " + types.length);
793  
      return false;
794  
    }
795  
    for (int i = 0; i < types.length; i++)
796  
      if (!(args[i] == null || types[i].isInstance(args[i]))) {
797  
        if (debug)
798  
          System.out.println("Bad parameter " + i + ": " + args[i] + " vs " + types[i]);
799  
        return false;
800  
      }
801  
    return true;
802  
  }
803  
804  
  private static FileInputStream newFileInputStream(File f) throws FileNotFoundException {
805  
    /*if (androidContext != null)
806  
      return (FileInputStream) call(androidContext,
807  
        "openFileInput", f.getPath());
808  
    else*/
809  
    return new FileInputStream(f);
810  
  }
811  
812  
  private static FileOutputStream newFileOutputStream(File f) throws FileNotFoundException {
813  
    /*if (androidContext != null)
814  
      return (FileOutputStream) call(androidContext,
815  
        "openFileOutput", f.getPath(), 0);
816  
    else*/
817  
    return new FileOutputStream(f);
818  
  }
819  
820  
  public static void copy(InputStream in, OutputStream out) throws IOException {
821  
    byte[] buf = new byte[65536];
822  
    while (true) {
823  
      int n = in.read(buf);
824  
      if (n <= 0) return;
825  
      out.write(buf, 0, n);
826  
    }
827  
  }
828  
829  
  /** writes safely (to temp file, then rename) */
830  
  public static void saveTextFile(String fileName, String contents) throws IOException {
831  
    File file = new File(fileName);
832  
    File parentFile = file.getParentFile();
833  
    if (parentFile != null)
834  
      parentFile.mkdirs();
835  
    String tempFileName = fileName + "_temp";
836  
    FileOutputStream fileOutputStream = newFileOutputStream(new File(tempFileName));
837  
    OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream, charsetForTextFiles);
838  
    PrintWriter printWriter = new PrintWriter(outputStreamWriter);
839  
    printWriter.print(contents);
840  
    printWriter.close();
841  
    if (file.exists() && !file.delete())
842  
      throw new IOException("Can't delete " + fileName);
843  
844  
    if (!new File(tempFileName).renameTo(file))
845  
      throw new IOException("Can't rename " + tempFileName + " to " + fileName);
846  
  }
847  
848  
  /** writes safely (to temp file, then rename) */
849  
  public static void saveBinaryFile(String fileName, byte[] contents) throws IOException {
850  
    File file = new File(fileName);
851  
    File parentFile = file.getParentFile();
852  
    if (parentFile != null)
853  
      parentFile.mkdirs();
854  
    String tempFileName = fileName + "_temp";
855  
    FileOutputStream fileOutputStream = newFileOutputStream(new File(tempFileName));
856  
    fileOutputStream.write(contents);
857  
    fileOutputStream.close();
858  
    if (file.exists() && !file.delete())
859  
      throw new IOException("Can't delete " + fileName);
860  
861  
    if (!new File(tempFileName).renameTo(file))
862  
      throw new IOException("Can't rename " + tempFileName + " to " + fileName);
863  
  }
864  
865  
  public static String loadTextFile(String fileName, String defaultContents) throws IOException {
866  
    if (!new File(fileName).exists())
867  
      return defaultContents;
868  
869  
    FileInputStream fileInputStream = newFileInputStream(new File(fileName));
870  
    InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream, charsetForTextFiles);
871  
    return loadTextFile(inputStreamReader, (int) new File(fileName).length());
872  
  }
873  
874  
  public static String loadTextFile(Reader reader, int length) throws IOException {
875  
    try {
876  
      char[] chars = new char[length];
877  
      int n = reader.read(chars);
878  
      return new String(chars, 0, n);
879  
    } finally {
880  
      reader.close();
881  
    }
882  
  }
883  
884  
  static File DiskSnippetCache_dir;
885  
886  
  public static void initDiskSnippetCache(File dir) {
887  
    DiskSnippetCache_dir = dir;
888  
    dir.mkdirs();
889  
  }
890  
891  
  // Data files are immutable, use centralized cache
892  
  public static synchronized File DiskSnippetCache_getLibrary(long snippetID) throws IOException {
893  
    File file = new File(getGlobalCache(), "data_" + snippetID + ".jar");
894  
    if (verbose)
895  
      System.out.println("Checking data cache: " + file.getPath());
896  
    return file.exists() ? file : null;
897  
  }
898  
899  
  public static synchronized String DiskSnippetCache_get(long snippetID) throws IOException {
900  
    return loadTextFile(DiskSnippetCache_getFile(snippetID).getPath(), null);
901  
  }
902  
903  
  private static File DiskSnippetCache_getFile(long snippetID) {
904  
    return new File(DiskSnippetCache_dir, "" + snippetID);
905  
  }
906  
907  
  public static synchronized void DiskSnippetCache_put(long snippetID, String snippet) throws IOException {
908  
    saveTextFile(DiskSnippetCache_getFile(snippetID).getPath(), snippet);
909  
  }
910  
911  
  public static synchronized void DiskSnippetCache_putLibrary(long snippetID, byte[] data) throws IOException {
912  
    saveBinaryFile(new File(getGlobalCache(), "data_" + snippetID).getPath() + ".jar", data);
913  
  }
914  
915  
  public static File DiskSnippetCache_getDir() {
916  
    return DiskSnippetCache_dir;
917  
  }
918  
919  
  public static void initSnippetCache() {
920  
    if (DiskSnippetCache_dir == null)
921  
      initDiskSnippetCache(getGlobalCache());
922  
  }
923  
924  
  private static File getGlobalCache() {
925  
    File file = new File(userHome(), ".tinybrain/snippet-cache");
926  
    file.mkdirs();
927  
    return file;
928  
  }
929  
930  
  public static String loadSnippetVerified(String snippetID, String hash) throws IOException {
931  
    String text = loadSnippet(snippetID);
932  
    String realHash = getHash(text.getBytes("UTF-8"));
933  
    if (!realHash.equals(hash)) {
934  
      String msg;
935  
      if (hash.isEmpty())
936  
        msg = "Here's your hash for " + snippetID + ", please put in your program: " + realHash;
937  
      else
938  
        msg = "Hash mismatch for " + snippetID + ": " + realHash + " (new) vs " + hash + " - has tinybrain.de been hacked??";
939  
      throw new RuntimeException(msg);
940  
    }
941  
    return text;
942  
  }
943  
944  
  public static String getHash(byte[] data) {
945  
    return bytesToHex(getFullFingerprint(data));
946  
  }
947  
948  
  public static byte[] getFullFingerprint(byte[] data) {
949  
    try {
950  
      return MessageDigest.getInstance("MD5").digest(data);
951  
    } catch (NoSuchAlgorithmException e) {
952  
      throw new RuntimeException(e);
953  
    }
954  
  }
955  
956  
  public static String bytesToHex(byte[] bytes) {
957  
    return bytesToHex(bytes, 0, bytes.length);
958  
  }
959  
960  
  public static String bytesToHex(byte[] bytes, int ofs, int len) {
961  
    StringBuilder stringBuilder = new StringBuilder(len*2);
962  
    for (int i = 0; i < len; i++) {
963  
      String s = "0" + Integer.toHexString(bytes[ofs+i]);
964  
      stringBuilder.append(s.substring(s.length()-2, s.length()));
965  
    }
966  
    return stringBuilder.toString();
967  
  }
968  
969  
  public static String loadSnippet(String snippetID) throws IOException {
970  
    return loadSnippet(parseSnippetID(snippetID));
971  
  }
972  
973  
  public static long parseSnippetID(String snippetID) {
974  
    return Long.parseLong(shortenSnippetID(snippetID));
975  
  }
976  
977  
  private static String shortenSnippetID(String snippetID) {
978  
    if (snippetID.startsWith("#"))
979  
      snippetID = snippetID.substring(1);
980  
    String httpBlaBla = "http://tinybrain.de/";
981  
    if (snippetID.startsWith(httpBlaBla))
982  
      snippetID = snippetID.substring(httpBlaBla.length());
983  
    return snippetID;
984  
  }
985  
986  
  public static boolean isSnippetID(String snippetID) {
987  
    snippetID = shortenSnippetID(snippetID);
988  
    return isInteger(snippetID) && Long.parseLong(snippetID) != 0;
989  
  }
990  
991  
  public static boolean isInteger(String s) {
992  
    return Pattern.matches("\\-?\\d+", s);
993  
  }
994  
995  
  public static String loadSnippet(long snippetID) throws IOException {
996  
    String text = memSnippetCache.get(snippetID);
997  
    if (text != null)
998  
      return text;
999  
1000  
    initSnippetCache();
1001  
    text = DiskSnippetCache_get(snippetID);
1002  
    if (preferCached && text != null)
1003  
      return text;
1004  
1005  
    String md5 = text != null ? md5(text) : "-";
1006  
    if (text != null) {
1007  
      String hash = prefetched.get(snippetID);
1008  
      if (hash != null) {
1009  
        if (md5.equals(hash)) {
1010  
          memSnippetCache.put(snippetID, text);
1011  
          return text;
1012  
        } else
1013  
          prefetched.remove(snippetID); // (maybe this is not necessary)
1014  
      }
1015  
    }
1016  
1017  
    try {
1018  
      /*URL url = new URL("http://tinybrain.de:8080/getraw.php?id=" + snippetID);
1019  
      text = loadPage(url);*/
1020  
      String theURL = "http://tinybrain.de:8080/getraw.php?id=" + snippetID + "&getmd5=1&utf8=1&usetranspiled=1";
1021  
      if (text != null) {
1022  
        //System.err.println("MD5: " + md5);
1023  
        theURL += "&md5=" + md5;
1024  
      }
1025  
      URL url = new URL(theURL);
1026  
      String page = loadPage(url);
1027  
1028  
      // parse & drop transpilation flag available line
1029  
      int i = page.indexOf('\n');
1030  
      boolean hasTranspiled = page.substring(0, i).trim().equals("1");
1031  
      if (hasTranspiled)
1032  
        hasTranspiledSet.add(snippetID);
1033  
      else
1034  
        hasTranspiledSet.remove(snippetID);
1035  
      page = page.substring(i+1);
1036  
1037  
      if (page.startsWith("==*#*==")) {
1038  
        // same, keep text
1039  
        //System.err.println("Snippet unchanged, keeping.");
1040  
      } else {
1041  
        // drop md5 line
1042  
        i = page.indexOf('\n');
1043  
        String hash = page.substring(0, i).trim();
1044  
        text = page.substring(i+1);
1045  
1046  
        String myHash = md5(text);
1047  
        if (myHash.equals(hash)) {
1048  
          //System.err.println("Hash match: " + hash);
1049  
        } else
1050  
          System.err.println("Hash mismatch");
1051  
      }
1052  
    } catch (FileNotFoundException e) {
1053  
      e.printStackTrace();
1054  
      throw new IOException("Snippet #" + snippetID + " not found or not public");
1055  
    }
1056  
1057  
    memSnippetCache.put(snippetID, text);
1058  
1059  
    try {
1060  
      initSnippetCache();
1061  
      DiskSnippetCache_put(snippetID, text);
1062  
    } catch (IOException e) {
1063  
      System.err.println("Minor warning: Couldn't save snippet to cache ("  + DiskSnippetCache_getDir() + ")");
1064  
    }
1065  
1066  
    return text;
1067  
  }
1068  
1069  
  private static String md5(String text) {
1070  
    try {
1071  
      return bytesToHex(md5impl(text.getBytes("UTF-8"))); // maybe different than the way PHP does it...
1072  
    } catch (UnsupportedEncodingException e) {
1073  
      throw new RuntimeException(e);
1074  
    }
1075  
  }
1076  
1077  
  public static byte[] md5impl(byte[] data) {
1078  
    try {
1079  
      return MessageDigest.getInstance("MD5").digest(data);
1080  
    } catch (NoSuchAlgorithmException e) {
1081  
      throw new RuntimeException(e);
1082  
    }
1083  
  }
1084  
1085  
  private static String loadPage(URL url) throws IOException {
1086  
    System.err.println("Loading: " + url.toExternalForm());
1087  
    URLConnection con = url.openConnection();
1088  
    return loadPage(con, url);
1089  
  }
1090  
1091  
  public static String loadPage(URLConnection con, URL url) throws IOException {
1092  
    setHeaders(con);
1093  
    String contentType = con.getContentType();
1094  
    if (contentType == null)
1095  
      throw new IOException("Page could not be read: " + url);
1096  
    //Log.info("Content-Type: " + contentType);
1097  
    String charset = guessCharset(contentType);
1098  
    //System.err.println("Charset: " + charset);
1099  
    Reader r = new InputStreamReader(con.getInputStream(), charset);
1100  
    StringBuilder buf = new StringBuilder();
1101  
    while (true) {
1102  
      int ch = r.read();
1103  
      if (ch < 0)
1104  
        break;
1105  
      //Log.info("Chars read: " + buf.length());
1106  
      buf.append((char) ch);
1107  
    }
1108  
    return buf.toString();
1109  
  }
1110  
1111  
  public static byte[] loadBinaryPage(URLConnection con) throws IOException {
1112  
    setHeaders(con);
1113  
    return loadBinaryPage_noHeaders(con);
1114  
  }
1115  
1116  
  private static byte[] loadBinaryPage_noHeaders(URLConnection con) throws IOException {
1117  
    ByteArrayOutputStream buf = new ByteArrayOutputStream();
1118  
    InputStream inputStream = con.getInputStream();
1119  
    while (true) {
1120  
      int ch = inputStream.read();
1121  
      if (ch < 0)
1122  
        break;
1123  
      buf.write(ch);
1124  
    }
1125  
    inputStream.close();
1126  
    return buf.toByteArray();
1127  
  }
1128  
1129  
  private static void setHeaders(URLConnection con) throws IOException {
1130  
    String computerID = getComputerID();
1131  
    if (computerID != null)
1132  
      con.setRequestProperty("X-ComputerID", computerID);
1133  
  }
1134  
1135  
  public static String guessCharset(String contentType) {
1136  
    Pattern p = Pattern.compile("text/html;\\s+charset=([^\\s]+)\\s*");
1137  
    Matcher m = p.matcher(contentType);
1138  
    /* If Content-Type doesn't match this pre-conception, choose default and hope for the best. */
1139  
    return m.matches() ? m.group(1) : "ISO-8859-1";
1140  
  }
1141  
1142  
  /** runs a transpiled set of sources */
1143  
  public static void javax2(File srcDir, File ioBaseDir, boolean silent, boolean runInProcess,
1144  
                            List<File> libraries, String[] args, String cacheAs) throws Exception {
1145  
    if (android)
1146  
      javax2android(srcDir, args);
1147  
    else {
1148  
      File classesDir = TempDirMaker_make();
1149  
      String javacOutput = compileJava(srcDir, libraries, classesDir);
1150  
1151  
      // run
1152  
1153  
      if (verbose) System.out.println("Running program (" + srcDir.getAbsolutePath()
1154  
        + ") on io dir " + ioBaseDir.getAbsolutePath() + (runInProcess ? "[in-process]" : "") + "\n");
1155  
      runProgram(javacOutput, classesDir, ioBaseDir, silent, runInProcess, libraries, args, cacheAs);
1156  
    }
1157  
  }
1158  
1159  
  static void javax2android(File srcDir, String[] args) throws Exception {
1160  
    // TODO: optimize if it's a loaded snippet anyway
1161  
    URL url = new URL("http://tinybrain.de:8080/dexcompile.php");
1162  
    URLConnection conn = url.openConnection();
1163  
    String postData = "src=" + URLEncoder.encode(loadTextFile(new File(srcDir, "main.java").getPath(), null), "UTF-8");
1164  
    byte[] dexData = doPostBinary(postData, conn, url);
1165  
    if (!isDex(dexData))
1166  
      throw new RuntimeException("Dex generation error: " + dexData.length + " bytes - " + new String(dexData, "UTF-8"));
1167  
    System.out.println("Dex loaded: " + dexData.length + "b");
1168  
1169  
    File dexDir = TempDirMaker_make();
1170  
    File dexFile = new File(dexDir, System.currentTimeMillis() + ".dex");
1171  
    File dexOutputDir = TempDirMaker_make();
1172  
1173  
    System.out.println("Saving dex to: " + dexDir.getAbsolutePath());
1174  
    try {
1175  
      saveBinaryFile(dexFile.getPath(), dexData);
1176  
    } catch (Throwable e) {
1177  
      System.out.println("Whoa!");
1178  
      throw new RuntimeException(e);
1179  
    }
1180  
1181  
    System.out.println("Getting parent class loader.");
1182  
    ClassLoader parentClassLoader =
1183  
      //ClassLoader.getSystemClassLoader(); // does not find support jar
1184  
      //getClass().getClassLoader(); // Let's try this...
1185  
      x18.class.getClassLoader().getParent(); // XXX !
1186  
1187  
    System.out.println("Making DexClassLoader.");
1188  
    //DexClassLoader classLoader = new DexClassLoader(dexFile.getAbsolutePath(), dexOutputDir.getAbsolutePath(), null,
1189  
    //  parentClassLoader);
1190  
    Class dcl = Class.forName("dalvik.system.DexClassLoader");
1191  
    Object classLoader = dcl.getConstructors()[0].newInstance(dexFile.getAbsolutePath(), dexOutputDir.getAbsolutePath(), null,
1192  
      parentClassLoader);
1193  
1194  
    System.out.println("Loading main class.");
1195  
    //Class<?> theClass = classLoader.loadClass(mainClassName);
1196  
    Class<?> theClass = (Class<?>) call(classLoader, "loadClass", "main");
1197  
1198  
    System.out.println("Main class loaded.");
1199  
    try {
1200  
      set(theClass, "androidContext", androidContext);
1201  
    } catch (Throwable e) {}
1202  
1203  
    Method main = null;
1204  
    try {
1205  
      main = call_findStaticMethod(theClass, "main", new Object[]{androidContext}, false);
1206  
    } catch (RuntimeException e) {
1207  
    }
1208  
1209  
    System.out.println("main method for " + androidContext + " of " + theClass + ": " + main);
1210  
1211  
    if (main != null) {
1212  
      // old style main program that returns a View
1213  
      System.out.println("Calling main (old-style)");
1214  
      Object view = main.invoke(null, androidContext);
1215  
      System.out.println("Calling setContentView with " + view);
1216  
      call(Class.forName("main"), "setContentViewInUIThread", view);
1217  
      //call(androidContext, "setContentView", view);
1218  
      System.out.println("Done.");
1219  
    } else {
1220  
      System.out.println("New-style main method running.\n\n====\n");
1221  
      runMainMethod(args, theClass);
1222  
    }
1223  
  }
1224  
1225  
  static byte[] DEX_FILE_MAGIC = { 0x64, 0x65, 0x78, 0x0a, 0x30, 0x33, 0x35, 0x00 };
1226  
1227  
  static boolean isDex(byte[] dexData) {
1228  
    if (dexData.length < DEX_FILE_MAGIC.length) return false;
1229  
    for (int i = 0; i < DEX_FILE_MAGIC.length; i++)
1230  
      if (dexData[i] != DEX_FILE_MAGIC[i])
1231  
        return false;
1232  
    return true;
1233  
  }
1234  
1235  
  static byte[] doPostBinary(String urlParameters, URLConnection conn, URL url) throws IOException {
1236  
    // connect and do POST
1237  
    setHeaders(conn);
1238  
    conn.setDoOutput(true);
1239  
1240  
    OutputStreamWriter writer = new OutputStreamWriter(conn.getOutputStream());
1241  
    writer.write(urlParameters);
1242  
    writer.flush();
1243  
1244  
    byte[] contents = loadBinaryPage_noHeaders(conn);
1245  
    writer.close();
1246  
    return contents;
1247  
  }
1248  
1249  
  static String compileJava(File srcDir, List<File> libraries, File classesDir) throws IOException {
1250  
    ++compilations;
1251  
1252  
    // collect sources
1253  
1254  
    List<File> sources = new ArrayList<File>();
1255  
    if (verbose) System.out.println("Scanning for sources in " + srcDir.getPath());
1256  
    scanForSources(srcDir, sources, true);
1257  
    if (sources.isEmpty())
1258  
      throw new IOException("No sources found");
1259  
1260  
    // compile
1261  
1262  
    File optionsFile = File.createTempFile("javax", "");
1263  
    if (verbose) System.out.println("Compiling " + sources.size() + " source(s) to " + classesDir.getPath());
1264  
    String options = "-d " + bashQuote(classesDir.getPath());
1265  
    writeOptions(sources, libraries, optionsFile, options);
1266  
    classesDir.mkdirs();
1267  
    return invokeJavac(optionsFile);
1268  
  }
1269  
1270  
  private static void runProgram(String javacOutput, File classesDir, File ioBaseDir,
1271  
                                 boolean silent, boolean runInProcess,
1272  
                                 List<File> libraries, String[] args, String cacheAs) throws Exception {
1273  
    // print javac output if compile failed and it hasn't been printed yet
1274  
    boolean didNotCompile = !didCompile(classesDir);
1275  
    if (verbose || didNotCompile)
1276  
      System.out.println(javacOutput);
1277  
    if (didNotCompile)
1278  
      return;
1279  
1280  
    if (runInProcess
1281  
      || (ioBaseDir.getAbsolutePath().equals(new File(".").getAbsolutePath()) && !silent)) {
1282  
      runProgramQuick(classesDir, libraries, args, cacheAs);
1283  
      return;
1284  
    }
1285  
1286  
    boolean echoOK = false;
1287  
    // TODO: add libraries to class path
1288  
    String bashCmd = "(cd " + bashQuote(ioBaseDir.getAbsolutePath()) + " && (java -cp "
1289  
      + bashQuote(classesDir.getAbsolutePath()) + " main" + (echoOK ? "; echo ok" : "") + "))";
1290  
    if (verbose) System.out.println(bashCmd);
1291  
    String output = backtick(bashCmd);
1292  
    if (verbose || !silent)
1293  
      System.out.println(output);
1294  
  }
1295  
1296  
  static boolean didCompile(File classesDir) {
1297  
    return hasFile(classesDir, "main.class");
1298  
  }
1299  
1300  
  private static void runProgramQuick(File classesDir, List<File> libraries,
1301  
                                      String[] args, String cacheAs) throws Exception {
1302  
    // collect urls
1303  
    URL[] urls = new URL[libraries.size()+1];
1304  
    urls[0] = classesDir.toURI().toURL();
1305  
    for (int i = 0; i < libraries.size(); i++)
1306  
      urls[i+1] = libraries.get(i).toURI().toURL();
1307  
1308  
    // make class loader
1309  
    URLClassLoader classLoader = new URLClassLoader(urls);
1310  
1311  
    // load JavaX main class
1312  
    Class<?> mainClass = classLoader.loadClass("main");
1313  
1314  
    if (cacheAs != null)
1315  
      programCache.put(cacheAs, mainClass);
1316  
1317  
    runMainMethod(args, mainClass);
1318  
  }
1319  
1320  
1321  
  static void runMainMethod(Object args, Class<?> mainClass) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
1322  
    Method main = mainClass.getMethod("main", String[].class);
1323  
    main.invoke(null, args);
1324  
  }
1325  
1326  
  private static String invokeJavac(File optionsFile) throws IOException {
1327  
    String output;
1328  
    try {
1329  
      output = invokeEcj(optionsFile);
1330  
    } catch (Exception e) {
1331  
      if (verbose) {
1332  
        System.err.println("ecj not found or misconfigured - using javac");
1333  
        e.printStackTrace();
1334  
      }
1335  
      output = backtick("javac " + bashQuote("@" + optionsFile.getPath()));
1336  
    }
1337  
    if (verbose) System.out.println(output);
1338  
    return output;
1339  
  }
1340  
1341  
  // throws ClassNotFoundException if ecj is not in classpath
1342  
  static String invokeEcj(File optionsFile) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
1343  
    Class batchCompiler = getEclipseCompiler();
1344  
1345  
    StringWriter writer = new StringWriter();
1346  
    PrintWriter printWriter = new PrintWriter(writer);
1347  
1348  
    // add more eclipse options in the line below
1349  
1350  
    String[] args = { "@" + optionsFile.getPath(),
1351  
      "-source", "1.7",
1352  
      "-nowarn"
1353  
    };
1354  
    Method compile = batchCompiler.getDeclaredMethod("compile", args.getClass(), PrintWriter.class, PrintWriter.class,
1355  
      Class.forName("org.eclipse.jdt.core.compiler.CompilationProgress"));
1356  
    compile.invoke(null, args, printWriter, printWriter, null);
1357  
    return writer.toString();
1358  
  }
1359  
1360  
  private static Class<?> getEclipseCompiler() throws ClassNotFoundException {
1361  
    return Class.forName("org.eclipse.jdt.core.compiler.batch.BatchCompiler");
1362  
  }
1363  
1364  
  private static void writeOptions(List<File> sources, List<File> libraries,
1365  
                                   File optionsFile, String moreOptions) throws IOException {
1366  
    FileWriter writer = new FileWriter(optionsFile);
1367  
    for (File source : sources)
1368  
      writer.write(bashQuote(source.getPath()) + " ");
1369  
    if (!libraries.isEmpty()) {
1370  
      List<String> cp = new ArrayList<String>();
1371  
      for (File lib : libraries)
1372  
        cp.add(lib.getAbsolutePath());
1373  
      writer.write("-cp " + bashQuote(join(File.pathSeparator, cp)) + " ");
1374  
    }
1375  
    writer.write(moreOptions);
1376  
    writer.close();
1377  
  }
1378  
1379  
  static void scanForSources(File source, List<File> sources, boolean topLevel) {
1380  
    if (source.isFile() && source.getName().endsWith(".java"))
1381  
      sources.add(source);
1382  
    else if (source.isDirectory() && !isSkippedDirectoryName(source.getName(), topLevel)) {
1383  
      File[] files = source.listFiles();
1384  
      for (File file : files)
1385  
        scanForSources(file, sources, false);
1386  
    }
1387  
  }
1388  
1389  
  private static boolean isSkippedDirectoryName(String name, boolean topLevel) {
1390  
    if (topLevel) return false; // input or output ok as highest directory (intentionally specified by user, not just found by a directory scan in which case we probably don't want it. it's more like heuristics actually.)
1391  
    return name.equalsIgnoreCase("input") || name.equalsIgnoreCase("output");
1392  
  }
1393  
1394  
  public static String backtick(String cmd) throws IOException {
1395  
    ++processesStarted;
1396  
    File outFile = File.createTempFile("_backtick", "");
1397  
    File scriptFile = File.createTempFile("_backtick", isWindows() ? ".bat" : "");
1398  
1399  
    String command = cmd + ">" + bashQuote(outFile.getPath()) + " 2>&1";
1400  
    //Log.info("[Backtick] " + command);
1401  
    try {
1402  
      saveTextFile(scriptFile.getPath(), command);
1403  
      String[] command2;
1404  
      if (isWindows())
1405  
        command2 = new String[] { scriptFile.getPath() };
1406  
      else
1407  
        command2 = new String[] { "/bin/bash", scriptFile.getPath() };
1408  
      Process process = Runtime.getRuntime().exec(command2);
1409  
      try {
1410  
        process.waitFor();
1411  
      } catch (InterruptedException e) {
1412  
        throw new RuntimeException(e);
1413  
      }
1414  
      process.exitValue();
1415  
      return loadTextFile(outFile.getPath(), "");
1416  
    } finally {
1417  
      scriptFile.delete();
1418  
    }
1419  
  }
1420  
1421  
  /** possibly improvable */
1422  
  public static String javaQuote(String text) {
1423  
    return bashQuote(text);
1424  
  }
1425  
1426  
  /** possibly improvable */
1427  
  public static String bashQuote(String text) {
1428  
    if (text == null) return null;
1429  
    return "\"" + text
1430  
      .replace("\\", "\\\\")
1431  
      .replace("\"", "\\\"")
1432  
      .replace("\n", "\\n")
1433  
      .replace("\r", "\\r") + "\"";
1434  
  }
1435  
1436  
  public final static String charsetForTextFiles = "UTF8";
1437  
1438  
  static long TempDirMaker_lastValue;
1439  
1440  
  public static File TempDirMaker_make() {
1441  
    File dir = new File(userHome(), ".javax/" + TempDirMaker_newValue());
1442  
    dir.mkdirs();
1443  
    return dir;
1444  
  }
1445  
1446  
  private static long TempDirMaker_newValue() {
1447  
    long value;
1448  
    do
1449  
      value = System.currentTimeMillis();
1450  
    while (value == TempDirMaker_lastValue);
1451  
    TempDirMaker_lastValue = value;
1452  
    return value;
1453  
  }
1454  
1455  
  public static String join(String glue, Iterable<String> strings) {
1456  
    StringBuilder buf = new StringBuilder();
1457  
    Iterator<String> i = strings.iterator();
1458  
    if (i.hasNext()) {
1459  
      buf.append(i.next());
1460  
      while (i.hasNext())
1461  
        buf.append(glue).append(i.next());
1462  
    }
1463  
    return buf.toString();
1464  
  }
1465  
1466  
  public static boolean isWindows() {
1467  
    return System.getProperty("os.name").contains("Windows");
1468  
  }
1469  
1470  
  public static String makeRandomID(int length) {
1471  
    Random random = new Random();
1472  
    char[] id = new char[length];
1473  
    for (int i = 0; i< id.length; i++)
1474  
      id[i] = (char) ((int) 'a' + random.nextInt(26));
1475  
    return new String(id);
1476  
  }
1477  
1478  
  static String computerID;
1479  
  public static String getComputerID() throws IOException {
1480  
    if (noID) return null;
1481  
    if (computerID == null) {
1482  
      File file = new File(userHome(), ".tinybrain/computer-id");
1483  
      computerID = loadTextFile(file.getPath(), null);
1484  
      if (computerID == null) {
1485  
        computerID = makeRandomID(12);
1486  
        saveTextFile(file.getPath(), computerID);
1487  
      }
1488  
      if (verbose)
1489  
        System.out.println("Local computer ID: " + computerID);
1490  
    }
1491  
    return computerID;
1492  
  }
1493  
1494  
  static int fileDeletions;
1495  
1496  
  static void cleanCache() {
1497  
    if (verbose)
1498  
      System.out.println("Cleaning cache");
1499  
    fileDeletions = 0;
1500  
    File javax = new File(userHome(), ".javax");
1501  
    long now = System.currentTimeMillis();
1502  
    File[] files = javax.listFiles();
1503  
    if (files != null) for (File dir : files) {
1504  
      if (dir.isDirectory() && Pattern.compile("\\d+").matcher(dir.getName()).matches()) {
1505  
        long time = Long.parseLong(dir.getName());
1506  
        long seconds = (now - time) / 1000;
1507  
        long minutes = seconds / 60;
1508  
        long hours = minutes / 60;
1509  
        if (hours >= 1) {
1510  
          //System.out.println("Can delete " + dir.getAbsolutePath() + ", age: " + hours + " h");
1511  
          removeDir(dir);
1512  
        }
1513  
      }
1514  
    }
1515  
    if (verbose && fileDeletions != 0)
1516  
      System.out.println("Cleaned cache. File deletions: " + fileDeletions);
1517  
  }
1518  
1519  
  static void removeDir(File dir) {
1520  
    if (dir.getAbsolutePath().indexOf(".javax") < 0)  // security check!
1521  
      return;
1522  
    for (File f : dir.listFiles()) {
1523  
      if (f.isDirectory())
1524  
        removeDir(f);
1525  
      else {
1526  
        if (verbose)
1527  
          System.out.println("Deleting " + f.getAbsolutePath());
1528  
        f.delete();
1529  
        ++fileDeletions;
1530  
      }
1531  
    }
1532  
    dir.delete();
1533  
  }
1534  
1535  
  static void showSystemProperties() {
1536  
    System.out.println("System properties:\n");
1537  
    for (Map.Entry<Object, Object> entry : System.getProperties().entrySet()) {
1538  
      System.out.println("  " + entry.getKey() + " = " + entry.getValue());
1539  
    }
1540  
    System.out.println();
1541  
  }
1542  
1543  
  static void showVersion() {
1544  
    //showSystemProperties();
1545  
    boolean eclipseFound = hasEclipseCompiler();
1546  
    //String platform = System.getProperty("java.vendor") + " " + System.getProperty("java.runtime.name") + " " + System.getProperty("java.version");
1547  
    String platform = System.getProperty("java.vm.name") + " " + System.getProperty("java.version");
1548  
    String os = System.getProperty("os.name"), arch = System.getProperty("os.arch");
1549  
    System.out.println("This is " + version + ".");
1550  
    System.out.println("[Details: " +
1551  
      (eclipseFound ? "Eclipse compiler (good)" : "javac (not so good)")
1552  
      + ", " + platform + ", " + arch + ", " + os + "]");
1553  
  }
1554  
1555  
  private static boolean hasEclipseCompiler() {
1556  
    boolean compilerFound = false;
1557  
    try { getEclipseCompiler(); compilerFound = true; } catch (ClassNotFoundException e) {}
1558  
    return compilerFound;
1559  
  }
1560  
1561  
  static boolean isAndroid() {
1562  
    return System.getProperty("java.vendor").toLowerCase().indexOf("android") >= 0;
1563  
  }
1564  
1565  
  static void set(Class c, String field, Object value) {
1566  
    try {
1567  
      Field f = set_findStaticField(c, field);
1568  
      f.setAccessible(true);
1569  
      f.set(null, value);
1570  
    } catch (Exception e) {
1571  
      throw new RuntimeException(e);
1572  
    }
1573  
  }
1574  
1575  
  static Field set_findStaticField(Class<?> c, String field) {
1576  
    for (Field f : c.getDeclaredFields())
1577  
      if (f.getName().equals(field) && (f.getModifiers() & Modifier.STATIC) != 0)
1578  
        return f;
1579  
    throw new RuntimeException("Static field '" + field + "' not found in " + c.getName());
1580  
  }
1581  
}

Author comment

Began life as a copy of #676

download  show line numbers  debug dex  old transpilations   

Travelled to 13 computer(s): aoiabmzegqzx, bhatertpkbcr, cbybwowwnfue, cfunsshuasjs, gwrvuhgaqvyk, ishqpsrjomds, lpdgvwnxivlt, mqqgnosmbjvj, pyentgdyhuwx, pzhvpgtvlbxg, tslmcundralx, tvejysmllsmz, vouqrxazstgt

No comments. add comment

Snippet ID: #1000438
Snippet name: Default boot-up code for JavaX/Android 19 (backup)
Eternal ID of this version: #1000438/1
Text MD5: 60d612679b2529309d4a9effd5ce0aa2
Author: stefan
Category: javax
Type: JavaX source code (Android)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2015-08-06 02:09:09
Source code size: 56443 bytes / 1581 lines
Pitched / IR pitched: No / Yes
Views / Downloads: 679 / 553
Referenced in: [show references]