1.1 --- a/emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/zip/FastJar.java Sun Feb 10 09:51:22 2013 +0100
1.2 +++ b/emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/zip/FastJar.java Sun Feb 10 12:14:40 2013 +0100
1.3 @@ -28,17 +28,12 @@
1.4 *
1.5 * Portions Copyrighted 2007 Sun Microsystems, Inc.
1.6 */
1.7 -package org.netbeans.modules.java.source.parsing;
1.8 +package org.apidesign.bck2brwsr.emul.zip;
1.9
1.10 -import java.io.File;
1.11 +import java.io.ByteArrayInputStream;
1.12 import java.io.IOException;
1.13 import java.io.InputStream;
1.14 -import java.io.RandomAccessFile;
1.15 -import java.util.Date;
1.16 -import java.util.LinkedList;
1.17 -import java.util.List;
1.18 import java.util.zip.ZipEntry;
1.19 -import java.util.zip.ZipFile;
1.20 import java.util.zip.ZipInputStream;
1.21
1.22 /**
1.23 @@ -46,78 +41,28 @@
1.24 * @author Tomas Zezula
1.25 */
1.26 public final class FastJar {
1.27 + private final byte[] arr;
1.28
1.29 - private FastJar() {
1.30 + public FastJar(byte[] arr) {
1.31 + this.arr = arr;
1.32 }
1.33
1.34
1.35 private static final int GIVE_UP = 1<<16;
1.36 -
1.37 -
1.38 - private static class RandomAccessFileInputStream extends InputStream {
1.39 -
1.40 - private final RandomAccessFile b;
1.41 - private final long len;
1.42 -
1.43 - public RandomAccessFileInputStream (RandomAccessFile b) throws IOException {
1.44 - assert b != null;
1.45 - this.b = b;
1.46 - this.len = b.length();
1.47 - }
1.48 -
1.49 - public RandomAccessFileInputStream (RandomAccessFile b, long len) throws IOException {
1.50 - assert b != null;
1.51 - assert len >=0;
1.52 - this.b = b;
1.53 - this.len = b.getFilePointer()+len;
1.54 - }
1.55 -
1.56 - public int read (byte[] data, int offset, int size) throws IOException {
1.57 - int rem = available();
1.58 - if (rem == 0) {
1.59 - return -1;
1.60 - }
1.61 - int rlen;
1.62 - if (size<rem) {
1.63 - rlen = size;
1.64 - }
1.65 - else {
1.66 - rlen = rem;
1.67 - }
1.68 - return this.b.read(data, offset, rlen);
1.69 - }
1.70
1.71 - public int read() throws java.io.IOException {
1.72 - if (available()==0) {
1.73 - return -1;
1.74 - }
1.75 - else {
1.76 - return b.readByte();
1.77 - }
1.78 - }
1.79 -
1.80 - public int available () throws IOException {
1.81 - return (int) (len - this.b.getFilePointer());
1.82 - }
1.83 -
1.84 - public void close () throws IOException {
1.85 - b.close ();
1.86 - }
1.87 - }
1.88 -
1.89 public static final class Entry {
1.90
1.91 public final String name;
1.92 final long offset;
1.93 private final long dosTime;
1.94
1.95 - public Entry (String name, long offset, long time) {
1.96 + Entry (String name, long offset, long time) {
1.97 assert name != null;
1.98 this.name = name;
1.99 this.offset = offset;
1.100 this.dosTime = time;
1.101 }
1.102 -
1.103 +/*
1.104 public long getTime () {
1.105 Date d = new Date((int)(((dosTime >> 25) & 0x7f) + 80),
1.106 (int)(((dosTime >> 21) & 0x0f) - 1),
1.107 @@ -127,120 +72,94 @@
1.108 (int)((dosTime << 1) & 0x3e));
1.109 return d.getTime();
1.110 }
1.111 + */
1.112 }
1.113
1.114 - public static InputStream getInputStream (final File file, final Entry e) throws IOException {
1.115 - return getInputStream(file, e.offset);
1.116 + public InputStream getInputStream (final Entry e) throws IOException {
1.117 + return getInputStream(arr, e.offset);
1.118 }
1.119
1.120 - static InputStream getInputStream (final File file, final long offset) throws IOException {
1.121 - RandomAccessFile f = new RandomAccessFile (file, "r"); //NOI18N
1.122 - f.seek (offset);
1.123 - ZipInputStream in = new ZipInputStream (new RandomAccessFileInputStream (f));
1.124 + private static InputStream getInputStream (byte[] arr, final long offset) throws IOException {
1.125 + ByteArrayInputStream is = new ByteArrayInputStream(arr);
1.126 + is.skip(offset);
1.127 + ZipInputStream in = new ZipInputStream (is);
1.128 ZipEntry e = in.getNextEntry();
1.129 if (e != null && e.getCrc() == 0L && e.getMethod() == ZipEntry.STORED) {
1.130 - long cp = f.getFilePointer();
1.131 - in.close();
1.132 - f = new RandomAccessFile (file, "r"); //NOI18N
1.133 - f.seek (cp);
1.134 - return new RandomAccessFileInputStream (f, e.getSize());
1.135 + int cp = arr.length - is.available();
1.136 + return new ByteArrayInputStream(arr, cp, (int)e.getSize());
1.137 }
1.138 return in;
1.139 }
1.140
1.141 - static ZipEntry getZipEntry (final File file, final long offset) throws IOException {
1.142 - RandomAccessFile f = new RandomAccessFile (file, "r"); //NOI18N
1.143 - try {
1.144 - f.seek (offset);
1.145 - ZipInputStream in = new ZipInputStream (new RandomAccessFileInputStream (f));
1.146 - try {
1.147 - return in.getNextEntry();
1.148 - } finally {
1.149 - in.close();
1.150 + public Entry[] list() throws IOException {
1.151 + final int size = arr.length;
1.152 +
1.153 + int at = size - ZipInputStream.ENDHDR;
1.154 +
1.155 + byte[] data = new byte[ZipInputStream.ENDHDR];
1.156 + int giveup = 0;
1.157 +
1.158 + do {
1.159 + org.apidesign.bck2brwsr.emul.lang.System.arraycopy(arr, at, data, 0, data.length);
1.160 + at--;
1.161 + giveup++;
1.162 + if (giveup > GIVE_UP) {
1.163 + throw new IOException ();
1.164 }
1.165 - } finally {
1.166 - f.close ();
1.167 + } while (getsig(data) != ZipInputStream.ENDSIG);
1.168 +
1.169 +
1.170 + final long censize = endsiz(data);
1.171 + final long cenoff = endoff(data);
1.172 + at = (int) cenoff;
1.173 +
1.174 + Entry[] result = new Entry[0];
1.175 + int cenread = 0;
1.176 + data = new byte[ZipInputStream.CENHDR];
1.177 + while (cenread < censize) {
1.178 + org.apidesign.bck2brwsr.emul.lang.System.arraycopy(arr, at, data, 0, data.length);
1.179 + at += data.length;
1.180 + if (getsig(data) != ZipInputStream.CENSIG) {
1.181 + throw new IOException("No central table"); //NOI18N
1.182 + }
1.183 + int cennam = cennam(data);
1.184 + int cenext = cenext(data);
1.185 + int cencom = cencom(data);
1.186 + long lhoff = cenoff(data);
1.187 + long centim = centim(data);
1.188 + String name = new String(arr, at, cennam, "UTF-8");
1.189 + at += cennam;
1.190 + int seekby = cenext+cencom;
1.191 + int cendatalen = ZipInputStream.CENHDR + cennam + seekby;
1.192 + cenread+=cendatalen;
1.193 + result = addEntry(result, new Entry(name,lhoff, centim));
1.194 + at += seekby;
1.195 }
1.196 + return result;
1.197 }
1.198
1.199 - public static Iterable<? extends Entry> list(File f) throws IOException {
1.200 - RandomAccessFile b = new RandomAccessFile (f,"r"); //NOI18N
1.201 - try {
1.202 - final long size = (int) b.length();
1.203 - b.seek (size-ZipFile.ENDHDR);
1.204 -
1.205 - byte[] data = new byte[ZipFile.ENDHDR];
1.206 - int giveup = 0;
1.207 -
1.208 - do {
1.209 - if (b.read(data, 0, ZipFile.ENDHDR)!=ZipFile.ENDHDR) {
1.210 - throw new IOException ();
1.211 - }
1.212 - b.seek(b.getFilePointer()-(ZipFile.ENDHDR+1));
1.213 - giveup++;
1.214 - if (giveup > GIVE_UP) {
1.215 - throw new IOException ();
1.216 - }
1.217 - } while (getsig(data) != ZipFile.ENDSIG);
1.218 -
1.219 -
1.220 - final long censize = endsiz(data);
1.221 - final long cenoff = endoff(data);
1.222 - b.seek (cenoff);
1.223 -
1.224 - List<Entry> result = new LinkedList<Entry>();
1.225 - int cenread = 0;
1.226 - data = new byte[ZipFile.CENHDR];
1.227 - while (cenread < censize) {
1.228 - if (b.read(data, 0, ZipFile.CENHDR)!=ZipFile.CENHDR) {
1.229 - throw new IOException ("No central table"); //NOI18N
1.230 - }
1.231 - if (getsig(data) != ZipFile.CENSIG) {
1.232 - throw new IOException("No central table"); //NOI18N
1.233 - }
1.234 - int cennam = cennam(data);
1.235 - int cenext = cenext(data);
1.236 - int cencom = cencom(data);
1.237 - long lhoff = cenoff(data);
1.238 - long centim = centim(data);
1.239 - String name = name(b, cennam);
1.240 - int seekby = cenext+cencom;
1.241 - int cendatalen = ZipFile.CENHDR + cennam + seekby;
1.242 - cenread+=cendatalen;
1.243 - result.add(new Entry(name,lhoff, centim));
1.244 - seekBy(b,seekby);
1.245 - }
1.246 - return result;
1.247 - } finally {
1.248 - b.close();
1.249 - }
1.250 - }
1.251 -
1.252 - private static final String name(final RandomAccessFile b, final int cennam) throws IOException {
1.253 - byte[] name = new byte[cennam];
1.254 - b.read(name, 0, cennam);
1.255 - return new String(name, "UTF-8"); //NOI18N
1.256 + private Entry[] addEntry(Entry[] result, Entry entry) {
1.257 + Entry[] e = new Entry[result.length + 1];
1.258 + e[result.length] = entry;
1.259 + org.apidesign.bck2brwsr.emul.lang.System.arraycopy(result, 0, e, 0, result.length);
1.260 + return e;
1.261 }
1.262
1.263 private static final long getsig(final byte[] b) throws IOException {return get32(b,0);}
1.264 - private static final long endsiz(final byte[] b) throws IOException {return get32(b,ZipFile.ENDSIZ);}
1.265 - private static final long endoff(final byte[] b) throws IOException {return get32(b,ZipFile.ENDOFF);}
1.266 - private static final long cenlen(final byte[] b) throws IOException {return get32(b,ZipFile.CENLEN);}
1.267 - private static final long censiz(final byte[] b) throws IOException {return get32(b,ZipFile.CENSIZ);}
1.268 - private static final long centim(final byte[] b) throws IOException {return get32(b,ZipFile.CENTIM);}
1.269 - private static final int cennam(final byte[] b) throws IOException {return get16(b,ZipFile.CENNAM);}
1.270 - private static final int cenext(final byte[] b) throws IOException {return get16(b,ZipFile.CENEXT);}
1.271 - private static final int cencom(final byte[] b) throws IOException {return get16(b,ZipFile.CENCOM);}
1.272 - private static final long cenoff (final byte[] b) throws IOException {return get32(b,ZipFile.CENOFF);}
1.273 - private static final int lochow(final byte[] b) throws IOException {return get16(b,ZipFile.LOCHOW);}
1.274 - private static final int locname(final byte[] b) throws IOException {return get16(b,ZipFile.LOCNAM);}
1.275 - private static final int locext(final byte[] b) throws IOException {return get16(b,ZipFile.LOCEXT);}
1.276 - private static final long locsiz(final byte[] b) throws IOException {return get32(b,ZipFile.LOCSIZ);}
1.277 + private static final long endsiz(final byte[] b) throws IOException {return get32(b,ZipInputStream.ENDSIZ);}
1.278 + private static final long endoff(final byte[] b) throws IOException {return get32(b,ZipInputStream.ENDOFF);}
1.279 + private static final long cenlen(final byte[] b) throws IOException {return get32(b,ZipInputStream.CENLEN);}
1.280 + private static final long censiz(final byte[] b) throws IOException {return get32(b,ZipInputStream.CENSIZ);}
1.281 + private static final long centim(final byte[] b) throws IOException {return get32(b,ZipInputStream.CENTIM);}
1.282 + private static final int cennam(final byte[] b) throws IOException {return get16(b,ZipInputStream.CENNAM);}
1.283 + private static final int cenext(final byte[] b) throws IOException {return get16(b,ZipInputStream.CENEXT);}
1.284 + private static final int cencom(final byte[] b) throws IOException {return get16(b,ZipInputStream.CENCOM);}
1.285 + private static final long cenoff (final byte[] b) throws IOException {return get32(b,ZipInputStream.CENOFF);}
1.286 + private static final int lochow(final byte[] b) throws IOException {return get16(b,ZipInputStream.LOCHOW);}
1.287 + private static final int locname(final byte[] b) throws IOException {return get16(b,ZipInputStream.LOCNAM);}
1.288 + private static final int locext(final byte[] b) throws IOException {return get16(b,ZipInputStream.LOCEXT);}
1.289 + private static final long locsiz(final byte[] b) throws IOException {return get32(b,ZipInputStream.LOCSIZ);}
1.290
1.291 - private static final void seekBy(final RandomAccessFile b, int offset) throws IOException {
1.292 - b.seek(b.getFilePointer() + offset);
1.293 - }
1.294 -
1.295 private static final int get16(final byte[] b, int off) throws IOException {
1.296 final int b1 = b[off];
1.297 final int b2 = b[off+1];
2.1 --- a/vm/src/main/java/org/apidesign/vm4brwsr/Zips.java Sun Feb 10 09:51:22 2013 +0100
2.2 +++ b/vm/src/main/java/org/apidesign/vm4brwsr/Zips.java Sun Feb 10 12:14:40 2013 +0100
2.3 @@ -19,17 +19,25 @@
2.4
2.5 import java.io.ByteArrayInputStream;
2.6 import java.io.IOException;
2.7 +import java.io.InputStream;
2.8 import java.net.URL;
2.9 -import java.util.zip.ZipEntry;
2.10 -import java.util.zip.ZipInputStream;
2.11 import org.apidesign.bck2brwsr.core.JavaScriptBody;
2.12 +import org.apidesign.bck2brwsr.emul.zip.FastJar;
2.13
2.14 /** Conversion from classpath to load function.
2.15 *
2.16 * @author Jaroslav Tulach <jtulach@netbeans.org>
2.17 */
2.18 final class Zips {
2.19 - private Zips() {
2.20 + private final FastJar fj;
2.21 +
2.22 + private Zips(String path, byte[] zipData) throws IOException {
2.23 + long bef = currentTimeMillis();
2.24 + fj = new FastJar(zipData);
2.25 + for (FastJar.Entry e : fj.list()) {
2.26 + putRes(e.name, e);
2.27 + }
2.28 + log("Iterating thru " + path + " took " + (currentTimeMillis() - bef) + "ms");
2.29 }
2.30
2.31 public static void init() {
2.32 @@ -64,38 +72,32 @@
2.33 }
2.34 return null;
2.35 }
2.36 +
2.37 + @JavaScriptBody(args = { "msg" }, body = "console.log(msg.toString());")
2.38 + private static native void log(String msg);
2.39 +
2.40 + private byte[] findRes(String res) throws IOException {
2.41 + Object arr = findResImpl(res);
2.42 + if (arr instanceof FastJar.Entry) {
2.43 + long bef = currentTimeMillis();
2.44 + InputStream zip = fj.getInputStream((FastJar.Entry)arr);
2.45 + arr = readFully(new byte[512], zip);
2.46 + putRes(res, arr);
2.47 + log("Reading " + res + " took " + (currentTimeMillis() - bef) + "ms");
2.48 + }
2.49 + return (byte[]) arr;
2.50 + }
2.51
2.52 @JavaScriptBody(args = { "res" }, body = "var r = this[res]; return r ? r : null;")
2.53 - private native byte[] findRes(String res);
2.54 + private native Object findResImpl(String res);
2.55
2.56 @JavaScriptBody(args = { "res", "arr" }, body = "this[res] = arr;")
2.57 - private native void putRes(String res, byte[] arr);
2.58 + private native void putRes(String res, Object arr);
2.59
2.60 private static Zips toZip(String path) throws IOException {
2.61 URL u = new URL(path);
2.62 - ZipInputStream zip = new ZipInputStream(u.openStream());
2.63 - Zips z = new Zips();
2.64 - for (;;) {
2.65 - ZipEntry entry = zip.getNextEntry();
2.66 - if (entry == null) {
2.67 - break;
2.68 - }
2.69 - byte[] arr = new byte[4096];
2.70 - int offset = 0;
2.71 - for (;;) {
2.72 - int len = zip.read(arr, offset, arr.length - offset);
2.73 - if (len == -1) {
2.74 - break;
2.75 - }
2.76 - offset += len;
2.77 - if (offset == arr.length) {
2.78 - enlargeArray(arr, arr.length + 4096);
2.79 - }
2.80 - }
2.81 - sliceArray(arr, offset);
2.82 - z.putRes(entry.getName(), arr);
2.83 - }
2.84 - return z;
2.85 + byte[] zipData = (byte[]) u.getContent(new Class[] { byte[].class });
2.86 + return new Zips(path, zipData);
2.87 }
2.88
2.89 private static String processClassPathAttr(final byte[] man, String url, Object[] classpath) throws IOException {
2.90 @@ -132,6 +134,28 @@
2.91
2.92 @JavaScriptBody(args = { "arr", "len" }, body = "arr.splice(len, arr.length - len);")
2.93 private static native void sliceArray(byte[] arr, int len);
2.94 +
2.95 + private static Object readFully(byte[] arr, InputStream zip) throws IOException {
2.96 + int offset = 0;
2.97 + for (;;) {
2.98 + int len = zip.read(arr, offset, arr.length - offset);
2.99 + if (len == -1) {
2.100 + break;
2.101 + }
2.102 + offset += len;
2.103 + if (offset == arr.length) {
2.104 + enlargeArray(arr, arr.length + 4096);
2.105 + }
2.106 + }
2.107 + sliceArray(arr, offset);
2.108 + return arr;
2.109 + }
2.110 +
2.111 + private static long currentTimeMillis() {
2.112 + return (long)m();
2.113 + }
2.114 + @JavaScriptBody(args = { }, body = "return window.performance.now();")
2.115 + private static native double m();
2.116
2.117
2.118 }
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3.2 +++ b/vmtest/src/test/java/org/apidesign/bck2brwsr/vmtest/impl/ZipEntryTest.java Sun Feb 10 12:14:40 2013 +0100
3.3 @@ -0,0 +1,67 @@
3.4 +/**
3.5 + * Back 2 Browser Bytecode Translator
3.6 + * Copyright (C) 2012 Jaroslav Tulach <jaroslav.tulach@apidesign.org>
3.7 + *
3.8 + * This program is free software: you can redistribute it and/or modify
3.9 + * it under the terms of the GNU General Public License as published by
3.10 + * the Free Software Foundation, version 2 of the License.
3.11 + *
3.12 + * This program is distributed in the hope that it will be useful,
3.13 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
3.14 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3.15 + * GNU General Public License for more details.
3.16 + *
3.17 + * You should have received a copy of the GNU General Public License
3.18 + * along with this program. Look for COPYING file in the top folder.
3.19 + * If not, see http://opensource.org/licenses/GPL-2.0.
3.20 + */
3.21 +package org.apidesign.bck2brwsr.vmtest.impl;
3.22 +
3.23 +import java.io.ByteArrayInputStream;
3.24 +import java.io.IOException;
3.25 +import java.io.InputStream;
3.26 +import org.apidesign.bck2brwsr.emul.zip.FastJar;
3.27 +import org.testng.annotations.Test;
3.28 +import static org.testng.Assert.*;
3.29 +
3.30 +/**
3.31 + *
3.32 + * @author Jaroslav Tulach <jtulach@netbeans.org>
3.33 + */
3.34 +@GenerateZip(name = "five.zip", contents = {
3.35 + "1.txt", "one",
3.36 + "2.txt", "duo",
3.37 + "3.txt", "three",
3.38 + "4.txt", "four",
3.39 + "5.txt", "five"
3.40 +})
3.41 +public class ZipEntryTest {
3.42 + @Test
3.43 + public void readEntriesEffectively() throws IOException {
3.44 + InputStream is = ZipEntryTest.class.getResourceAsStream("five.zip");
3.45 + byte[] arr = new byte[is.available()];
3.46 + int len = is.read(arr);
3.47 + assertEquals(len, arr.length, "Read fully");
3.48 +
3.49 + FastJar fj = new FastJar(arr);
3.50 + FastJar.Entry[] entrs = fj.list();
3.51 +
3.52 + assertEquals(5, entrs.length, "Five entries");
3.53 +
3.54 + for (int i = 1; i <= 5; i++) {
3.55 + FastJar.Entry en = entrs[i - 1];
3.56 + assertEquals(en.name, i + ".txt");
3.57 +// assertEquals(cis.cnt, 0, "Content of the file should be skipped, not read");
3.58 + }
3.59 +
3.60 + assertContent("three", fj.getInputStream(entrs[3 - 1]), "read OK");
3.61 + assertContent("five", fj.getInputStream(entrs[5 - 1]), "read OK");
3.62 + }
3.63 +
3.64 + private static void assertContent(String exp, InputStream is, String msg) throws IOException {
3.65 + byte[] arr = new byte[512];
3.66 + int len = is.read(arr);
3.67 + String s = new String(arr, 0, len);
3.68 + assertEquals(exp, s, msg);
3.69 + }
3.70 +}