rt/vm/src/main/java/org/apidesign/vm4brwsr/Zips.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Tue, 26 Feb 2013 16:54:16 +0100
changeset 772 d382dacfd73f
parent 746 vm/src/main/java/org/apidesign/vm4brwsr/Zips.java@daca661c9bc4
child 1357 f5c3f68c0664
permissions -rw-r--r--
Moving modules around so the runtime is under one master pom and can be built without building other modules that are in the repository
jaroslav@644
     1
/**
jaroslav@644
     2
 * Back 2 Browser Bytecode Translator
jaroslav@644
     3
 * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
jaroslav@644
     4
 *
jaroslav@644
     5
 * This program is free software: you can redistribute it and/or modify
jaroslav@644
     6
 * it under the terms of the GNU General Public License as published by
jaroslav@644
     7
 * the Free Software Foundation, version 2 of the License.
jaroslav@644
     8
 *
jaroslav@644
     9
 * This program is distributed in the hope that it will be useful,
jaroslav@644
    10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
jaroslav@644
    11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
jaroslav@644
    12
 * GNU General Public License for more details.
jaroslav@644
    13
 *
jaroslav@644
    14
 * You should have received a copy of the GNU General Public License
jaroslav@644
    15
 * along with this program. Look for COPYING file in the top folder.
jaroslav@644
    16
 * If not, see http://opensource.org/licenses/GPL-2.0.
jaroslav@644
    17
 */
jaroslav@644
    18
package org.apidesign.vm4brwsr;
jaroslav@644
    19
jaroslav@672
    20
import java.io.ByteArrayInputStream;
jaroslav@644
    21
import java.io.IOException;
jaroslav@706
    22
import java.io.InputStream;
jaroslav@644
    23
import java.net.URL;
jaroslav@644
    24
import org.apidesign.bck2brwsr.core.JavaScriptBody;
jaroslav@706
    25
import org.apidesign.bck2brwsr.emul.zip.FastJar;
jaroslav@644
    26
jaroslav@644
    27
/** Conversion from classpath to load function.
jaroslav@644
    28
 *
jaroslav@644
    29
 * @author Jaroslav Tulach <jtulach@netbeans.org>
jaroslav@644
    30
 */
jaroslav@644
    31
final class Zips {
jaroslav@706
    32
    private final FastJar fj;
jaroslav@706
    33
jaroslav@706
    34
    private Zips(String path, byte[] zipData) throws IOException {
jaroslav@715
    35
        long bef = timeNow();
jaroslav@706
    36
        fj = new FastJar(zipData);
jaroslav@706
    37
        for (FastJar.Entry e : fj.list()) {
jaroslav@706
    38
            putRes(e.name, e);
jaroslav@706
    39
        }
jaroslav@715
    40
        log("Iterating thru " + path + " took " + (timeNow() - bef) + "ms");
jaroslav@644
    41
    }
jaroslav@644
    42
    
jaroslav@644
    43
    public static void init() {
jaroslav@644
    44
    }
jaroslav@729
    45
    @JavaScriptBody(args = { "arr" }, body = "return arr.length;")
jaroslav@729
    46
    private static native int length(Object arr);
jaroslav@729
    47
    @JavaScriptBody(args = { "arr", "index" }, body = "return arr[index];")
jaroslav@729
    48
    private static native Object at(Object arr, int index);
jaroslav@729
    49
    @JavaScriptBody(args = { "arr", "index", "value" }, body = "arr[index] = value; return value;")
jaroslav@729
    50
    private static native Object set(Object arr, int index, Object value);
jaroslav@644
    51
    
jaroslav@729
    52
    public static byte[] loadFromCp(Object classpath, String res) 
jaroslav@729
    53
    throws IOException, ClassNotFoundException {
jaroslav@729
    54
        for (int i = 0; i < length(classpath); i++) {
jaroslav@729
    55
            Object c = at(classpath, i);
jaroslav@644
    56
            if (c instanceof String) {
jaroslav@644
    57
                try {
jaroslav@672
    58
                    String url = (String)c;
jaroslav@672
    59
                    final Zips z = toZip(url);
jaroslav@729
    60
                    c = set(classpath, i, z);
jaroslav@672
    61
                    final byte[] man = z.findRes("META-INF/MANIFEST.MF");
jaroslav@672
    62
                    if (man != null) {
jaroslav@702
    63
                        String mainClass = processClassPathAttr(man, url, classpath);
jaroslav@743
    64
//                        if (mainClass != null) {
jaroslav@743
    65
//                            Class.forName(mainClass);
jaroslav@743
    66
//                        }
jaroslav@672
    67
                    }
jaroslav@743
    68
                } catch (IOException ex) {
jaroslav@729
    69
                    set(classpath, i, ex);
jaroslav@746
    70
                    log("Cannot load " + c + " - " + ex.getClass().getName() + ":" + ex.getMessage());
jaroslav@644
    71
                }
jaroslav@644
    72
            }
jaroslav@729
    73
            if (res != null) {
jaroslav@729
    74
                byte[] checkRes;
jaroslav@729
    75
                if (c instanceof Zips) {
jaroslav@729
    76
                    checkRes = ((Zips)c).findRes(res);
jaroslav@729
    77
                } else {
jaroslav@729
    78
                    checkRes = callFunction(c, res);
jaroslav@729
    79
                }
jaroslav@729
    80
                if (checkRes != null) {
jaroslav@729
    81
                    return checkRes;
jaroslav@644
    82
                }
jaroslav@644
    83
            }
jaroslav@644
    84
        }
jaroslav@644
    85
        return null;
jaroslav@644
    86
    }
jaroslav@706
    87
    
jaroslav@729
    88
    @JavaScriptBody(args = { "fn", "res" }, body = 
jaroslav@729
    89
        "if (typeof fn === 'function') return fn(res);\n"
jaroslav@729
    90
      + "return null;"
jaroslav@729
    91
    )
jaroslav@729
    92
    private static native byte[] callFunction(Object fn, String res);
jaroslav@729
    93
    
jaroslav@706
    94
    @JavaScriptBody(args = { "msg" }, body = "console.log(msg.toString());")
jaroslav@706
    95
    private static native void log(String msg);
jaroslav@706
    96
jaroslav@706
    97
    private byte[] findRes(String res) throws IOException {
jaroslav@706
    98
        Object arr = findResImpl(res);
jaroslav@706
    99
        if (arr instanceof FastJar.Entry) {
jaroslav@715
   100
            long bef = timeNow();
jaroslav@706
   101
            InputStream zip = fj.getInputStream((FastJar.Entry)arr);
jaroslav@706
   102
            arr = readFully(new byte[512], zip);
jaroslav@706
   103
            putRes(res, arr);
jaroslav@715
   104
            log("Reading " + res + " took " + (timeNow() - bef) + "ms");
jaroslav@706
   105
        }
jaroslav@706
   106
        return (byte[]) arr;
jaroslav@706
   107
    }
jaroslav@644
   108
jaroslav@644
   109
    @JavaScriptBody(args = { "res" }, body = "var r = this[res]; return r ? r : null;")
jaroslav@706
   110
    private native Object findResImpl(String res);
jaroslav@644
   111
jaroslav@644
   112
    @JavaScriptBody(args = { "res", "arr" }, body = "this[res] = arr;")
jaroslav@706
   113
    private native void putRes(String res, Object arr);
jaroslav@644
   114
    
jaroslav@644
   115
    private static Zips toZip(String path) throws IOException {
jaroslav@644
   116
        URL u = new URL(path);
jaroslav@706
   117
        byte[] zipData = (byte[]) u.getContent(new Class[] { byte[].class });
jaroslav@706
   118
        return new Zips(path, zipData);
jaroslav@644
   119
    }
jaroslav@644
   120
jaroslav@729
   121
    private static String processClassPathAttr(final byte[] man, String url, Object classpath) throws IOException {
jaroslav@702
   122
        try (ParseMan is = new ParseMan(new ByteArrayInputStream(man))) {
jaroslav@672
   123
            String cp = is.toString();
jaroslav@702
   124
            if (cp != null) {
jaroslav@702
   125
                cp = cp.trim();
jaroslav@702
   126
                for (int p = 0; p < cp.length();) {
jaroslav@702
   127
                    int n = cp.indexOf(' ', p);
jaroslav@702
   128
                    if (n == -1) {
jaroslav@702
   129
                        n = cp.length();
jaroslav@702
   130
                    }
jaroslav@702
   131
                    String el = cp.substring(p, n);
jaroslav@702
   132
                    URL u = new URL(new URL(url), el);
jaroslav@702
   133
                    classpath = addToArray(classpath, u.toString());
jaroslav@702
   134
                    p = n + 1;
jaroslav@702
   135
                }
jaroslav@672
   136
            }
jaroslav@702
   137
            return is.getMainClass();
jaroslav@672
   138
        }
jaroslav@672
   139
    }
jaroslav@672
   140
jaroslav@729
   141
    private static Object addToArray(Object arr, String value) {
jaroslav@729
   142
        final int last = length(arr);
jaroslav@729
   143
        Object ret = enlargeArray(arr, last + 1);
jaroslav@729
   144
        set(ret, last, value);
jaroslav@672
   145
        return ret;
jaroslav@672
   146
    }
jaroslav@672
   147
jaroslav@729
   148
    @JavaScriptBody(args = { "arr", "len" }, body = "while (arr.length < len) arr.push(null); return arr;")
jaroslav@729
   149
    private static native Object enlargeArray(Object arr, int len);
jaroslav@644
   150
    @JavaScriptBody(args = { "arr", "len" }, body = "while (arr.length < len) arr.push(0);")
jaroslav@729
   151
    private static native void enlargeBytes(byte[] arr, int len);
jaroslav@644
   152
jaroslav@644
   153
    @JavaScriptBody(args = { "arr", "len" }, body = "arr.splice(len, arr.length - len);")
jaroslav@644
   154
    private static native void sliceArray(byte[] arr, int len);
jaroslav@706
   155
jaroslav@706
   156
    private static Object readFully(byte[] arr, InputStream zip) throws IOException {
jaroslav@706
   157
        int offset = 0;
jaroslav@706
   158
        for (;;) {
jaroslav@706
   159
            int len = zip.read(arr, offset, arr.length - offset);
jaroslav@706
   160
            if (len == -1) {
jaroslav@706
   161
                break;
jaroslav@706
   162
            }
jaroslav@706
   163
            offset += len;
jaroslav@706
   164
            if (offset == arr.length) {
jaroslav@729
   165
                enlargeBytes(arr, arr.length + 4096);
jaroslav@706
   166
            }
jaroslav@706
   167
        }
jaroslav@706
   168
        sliceArray(arr, offset);
jaroslav@706
   169
        return arr;
jaroslav@706
   170
    }
jaroslav@706
   171
jaroslav@715
   172
    private static long timeNow() {
jaroslav@715
   173
        double time = m();
jaroslav@715
   174
        if (time >= 0) {
jaroslav@715
   175
            return (long)time;
jaroslav@715
   176
        }
jaroslav@715
   177
        return org.apidesign.bck2brwsr.emul.lang.System.currentTimeMillis();
jaroslav@706
   178
    }
jaroslav@715
   179
    @JavaScriptBody(args = {}, body = 
jaroslav@715
   180
        "if (typeof window.performance === 'undefined') return -1;\n"
jaroslav@715
   181
      + "if (typeof window.performance.now === 'undefined') return -1;\n"
jaroslav@715
   182
      + "return window.performance.now();"
jaroslav@715
   183
    )
jaroslav@706
   184
    private static native double m();
jaroslav@644
   185
    
jaroslav@644
   186
    
jaroslav@644
   187
}