rt/emul/zip/src/main/java/org/apidesign/bck2brwsr/emul/zip/FastJar.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Tue, 13 May 2014 21:14:44 +0200
branchclosure
changeset 1569 9eb0eb434c67
parent 1555 71e68f7ed23f
permissions -rw-r--r--
Used from tests, must be exported
jaroslav@705
     1
/*
jaroslav@705
     2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
jaroslav@705
     3
 *
jaroslav@705
     4
 * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
jaroslav@705
     5
 *
jaroslav@705
     6
 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
jaroslav@705
     7
 * Other names may be trademarks of their respective owners.
jaroslav@705
     8
 *
jaroslav@705
     9
 * The contents of this file are subject to the terms of either the GNU
jaroslav@705
    10
 * General Public License Version 2 only ("GPL") or the Common
jaroslav@705
    11
 * Development and Distribution License("CDDL") (collectively, the
jaroslav@705
    12
 * "License"). You may not use this file except in compliance with the
jaroslav@705
    13
 * License. You can obtain a copy of the License at
jaroslav@705
    14
 * http://www.netbeans.org/cddl-gplv2.html
jaroslav@705
    15
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
jaroslav@705
    16
 * specific language governing permissions and limitations under the
jaroslav@705
    17
 * License.  When distributing the software, include this License Header
jaroslav@705
    18
 * Notice in each file and include the License file at
jaroslav@705
    19
 * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
jaroslav@705
    20
 * particular file as subject to the "Classpath" exception as provided
jaroslav@705
    21
 * by Oracle in the GPL Version 2 section of the License file that
jaroslav@705
    22
 * accompanied this code. If applicable, add the following below the
jaroslav@705
    23
 * License Header, with the fields enclosed by brackets [] replaced by
jaroslav@705
    24
 * your own identifying information:
jaroslav@705
    25
 * "Portions Copyrighted [year] [name of copyright owner]"
jaroslav@705
    26
 *
jaroslav@705
    27
 * Contributor(s):
jaroslav@705
    28
 *
jaroslav@705
    29
 * Portions Copyrighted 2007 Sun Microsystems, Inc.
jaroslav@705
    30
 */
jaroslav@706
    31
package org.apidesign.bck2brwsr.emul.zip;
jaroslav@705
    32
jaroslav@706
    33
import java.io.ByteArrayInputStream;
jaroslav@705
    34
import java.io.IOException;
jaroslav@705
    35
import java.io.InputStream;
jaroslav@1555
    36
import java.lang.reflect.Method;
jaroslav@705
    37
import java.util.zip.ZipEntry;
jaroslav@705
    38
import java.util.zip.ZipInputStream;
jaroslav@1569
    39
import org.apidesign.bck2brwsr.core.Exported;
jaroslav@1555
    40
import org.apidesign.bck2brwsr.core.JavaScriptBody;
jaroslav@705
    41
jaroslav@705
    42
/**
jaroslav@705
    43
 *
jaroslav@705
    44
 * @author Tomas Zezula
jaroslav@705
    45
 */
jaroslav@705
    46
public final class FastJar {
jaroslav@706
    47
    private final byte[] arr;
jaroslav@705
    48
jaroslav@706
    49
    public FastJar(byte[] arr) {
jaroslav@706
    50
        this.arr = arr;
jaroslav@705
    51
    }
jaroslav@705
    52
    
jaroslav@705
    53
    
jaroslav@705
    54
    private static final int GIVE_UP = 1<<16;
jaroslav@705
    55
jaroslav@705
    56
    public static final  class Entry {
jaroslav@705
    57
        
jaroslav@705
    58
        public final String name;
jaroslav@705
    59
        final long offset;
jaroslav@705
    60
        private final long dosTime;
jaroslav@705
    61
        
jaroslav@706
    62
        Entry (String name, long offset, long time) {
jaroslav@705
    63
            assert name != null;
jaroslav@705
    64
            this.name = name;
jaroslav@705
    65
            this.offset = offset;
jaroslav@705
    66
            this.dosTime = time;
jaroslav@705
    67
        }        
jaroslav@706
    68
/*        
jaroslav@705
    69
        public long getTime () {
jaroslav@705
    70
            Date d = new Date((int)(((dosTime >> 25) & 0x7f) + 80),
jaroslav@705
    71
                    (int)(((dosTime >> 21) & 0x0f) - 1),
jaroslav@705
    72
                    (int)((dosTime >> 16) & 0x1f),
jaroslav@705
    73
                    (int)((dosTime >> 11) & 0x1f),
jaroslav@705
    74
                    (int)((dosTime >> 5) & 0x3f),
jaroslav@705
    75
                    (int)((dosTime << 1) & 0x3e));
jaroslav@705
    76
            return d.getTime();
jaroslav@705
    77
        }
jaroslav@706
    78
        */
jaroslav@705
    79
    }
jaroslav@705
    80
    
jaroslav@706
    81
    public InputStream getInputStream (final Entry e) throws IOException {
jaroslav@706
    82
        return getInputStream(arr, e.offset);
jaroslav@705
    83
    }
jaroslav@705
    84
    
jaroslav@706
    85
    private static InputStream getInputStream (byte[] arr, final long offset) throws IOException {
jaroslav@706
    86
        ByteArrayInputStream is = new ByteArrayInputStream(arr);
jaroslav@706
    87
        is.skip(offset);
jaroslav@706
    88
        ZipInputStream in = new ZipInputStream (is);
jaroslav@705
    89
        ZipEntry e = in.getNextEntry();
jaroslav@705
    90
        if (e != null && e.getCrc() == 0L && e.getMethod() == ZipEntry.STORED) {
jaroslav@706
    91
            int cp = arr.length - is.available();
jaroslav@706
    92
            return new ByteArrayInputStream(arr, cp, (int)e.getSize());
jaroslav@705
    93
        }
jaroslav@705
    94
        return in;
jaroslav@705
    95
    }
jaroslav@705
    96
    
jaroslav@706
    97
    public Entry[] list() throws IOException {
jaroslav@706
    98
        final int size = arr.length;
jaroslav@706
    99
jaroslav@706
   100
        int at = size - ZipInputStream.ENDHDR;
jaroslav@706
   101
jaroslav@706
   102
        byte[] data = new byte[ZipInputStream.ENDHDR];        
jaroslav@706
   103
        int giveup = 0;
jaroslav@706
   104
jaroslav@706
   105
        do {
jaroslav@1555
   106
            FastJar.arraycopy(arr, at, data, 0, data.length);
jaroslav@706
   107
            at--;
jaroslav@706
   108
            giveup++;
jaroslav@706
   109
            if (giveup > GIVE_UP) {
jaroslav@706
   110
                throw new IOException ();
jaroslav@705
   111
            }
jaroslav@706
   112
        } while (getsig(data) != ZipInputStream.ENDSIG);
jaroslav@706
   113
jaroslav@706
   114
jaroslav@706
   115
        final long censize = endsiz(data);
jaroslav@706
   116
        final long cenoff  = endoff(data);
jaroslav@706
   117
        at = (int) cenoff;                                                     
jaroslav@706
   118
jaroslav@706
   119
        Entry[] result = new Entry[0];
jaroslav@706
   120
        int cenread = 0;
jaroslav@706
   121
        data = new byte[ZipInputStream.CENHDR];
jaroslav@706
   122
        while (cenread < censize) {
jaroslav@1555
   123
            FastJar.arraycopy(arr, at, data, 0, data.length);
jaroslav@706
   124
            at += data.length;
jaroslav@706
   125
            if (getsig(data) != ZipInputStream.CENSIG) {
jaroslav@706
   126
                throw new IOException("No central table");          //NOI18N
jaroslav@706
   127
            }
jaroslav@706
   128
            int cennam = cennam(data);
jaroslav@706
   129
            int cenext = cenext(data);
jaroslav@706
   130
            int cencom = cencom(data);
jaroslav@706
   131
            long lhoff = cenoff(data);
jaroslav@706
   132
            long centim = centim(data);
jaroslav@706
   133
            String name = new String(arr, at, cennam, "UTF-8");
jaroslav@706
   134
            at += cennam;
jaroslav@706
   135
            int seekby = cenext+cencom;
jaroslav@706
   136
            int cendatalen = ZipInputStream.CENHDR + cennam + seekby;
jaroslav@706
   137
            cenread+=cendatalen;
jaroslav@706
   138
            result = addEntry(result, new Entry(name,lhoff, centim));
jaroslav@706
   139
            at += seekby;
jaroslav@705
   140
        }
jaroslav@706
   141
        return result;
jaroslav@705
   142
    }
jaroslav@705
   143
jaroslav@706
   144
    private Entry[] addEntry(Entry[] result, Entry entry) {
jaroslav@706
   145
        Entry[] e = new Entry[result.length + 1];
jaroslav@706
   146
        e[result.length] = entry;
jaroslav@1555
   147
        FastJar.arraycopy(result, 0, e, 0, result.length);
jaroslav@706
   148
        return e;
jaroslav@705
   149
    }
jaroslav@705
   150
jaroslav@705
   151
    private static final long getsig(final byte[] b) throws IOException {return get32(b,0);}
jaroslav@706
   152
    private static final long endsiz(final byte[] b) throws IOException {return get32(b,ZipInputStream.ENDSIZ);}
jaroslav@706
   153
    private static final long endoff(final byte[] b) throws IOException {return get32(b,ZipInputStream.ENDOFF);}
jaroslav@706
   154
    private static final long  cenlen(final byte[] b) throws IOException {return get32(b,ZipInputStream.CENLEN);}
jaroslav@706
   155
    private static final long  censiz(final byte[] b) throws IOException {return get32(b,ZipInputStream.CENSIZ);}
jaroslav@706
   156
    private static final long centim(final byte[] b) throws IOException {return get32(b,ZipInputStream.CENTIM);}
jaroslav@706
   157
    private static final int  cennam(final byte[] b) throws IOException {return get16(b,ZipInputStream.CENNAM);}
jaroslav@706
   158
    private static final int  cenext(final byte[] b) throws IOException {return get16(b,ZipInputStream.CENEXT);}
jaroslav@706
   159
    private static final int  cencom(final byte[] b) throws IOException {return get16(b,ZipInputStream.CENCOM);}
jaroslav@706
   160
    private static final long cenoff (final byte[] b) throws IOException {return get32(b,ZipInputStream.CENOFF);}
jaroslav@706
   161
    private static final int lochow(final byte[] b) throws IOException {return get16(b,ZipInputStream.LOCHOW);}
jaroslav@706
   162
    private static final int locname(final byte[] b) throws IOException {return get16(b,ZipInputStream.LOCNAM);}
jaroslav@706
   163
    private static final int locext(final byte[] b) throws IOException {return get16(b,ZipInputStream.LOCEXT);}
jaroslav@706
   164
    private static final long locsiz(final byte[] b) throws IOException {return get32(b,ZipInputStream.LOCSIZ);}
jaroslav@705
   165
    
jaroslav@705
   166
    private static final int get16(final byte[] b, int off) throws IOException {        
jaroslav@705
   167
        final int b1 = b[off];
jaroslav@705
   168
	final int b2 = b[off+1];
jaroslav@705
   169
        return (b1 & 0xff) | ((b2 & 0xff) << 8);
jaroslav@705
   170
    }
jaroslav@705
   171
jaroslav@705
   172
    private static final long get32(final byte[] b, int off) throws IOException {
jaroslav@705
   173
	final int s1 = get16(b, off);
jaroslav@705
   174
	final int s2 = get16(b, off+2);
jaroslav@705
   175
        return s1 | ((long)s2 << 16);
jaroslav@705
   176
    }
jaroslav@1555
   177
    
jaroslav@1555
   178
    @JavaScriptBody(args = {"value", "srcBegin", "dst", "dstBegin", "count"}, body
jaroslav@1555
   179
            = "if (srcBegin < dstBegin) {\n"
jaroslav@1555
   180
            + "    while (count-- > 0) {\n"
jaroslav@1555
   181
            + "        dst[dstBegin + count] = value[srcBegin + count];\n"
jaroslav@1555
   182
            + "    }\n"
jaroslav@1555
   183
            + "} else {\n"
jaroslav@1555
   184
            + "    while (count-- > 0) {\n"
jaroslav@1555
   185
            + "        dst[dstBegin++] = value[srcBegin++];\n"
jaroslav@1555
   186
            + "    }\n"
jaroslav@1555
   187
            + "}"
jaroslav@1555
   188
    )
jaroslav@1569
   189
    
jaroslav@1569
   190
    @Exported
jaroslav@1555
   191
    static void arraycopy(Object src, int srcBegin, Object dst, int dstBegin, int count) {
jaroslav@1555
   192
        try {
jaroslav@1555
   193
            Class<?> system = Class.forName("java.lang.System");
jaroslav@1555
   194
            Method m = system.getMethod("arraycopy", Object.class, int.class, Object.class, int.class, int.class);
jaroslav@1555
   195
            m.invoke(null, src, srcBegin, dst, dstBegin, count);
jaroslav@1555
   196
        } catch (Exception ex) {
jaroslav@1555
   197
            throw new IllegalStateException(ex);
jaroslav@1555
   198
        }
jaroslav@1555
   199
    }
jaroslav@705
   200
jaroslav@705
   201
}