emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/zip/FastJar.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Sun, 10 Feb 2013 12:14:40 +0100
branchemul
changeset 706 a48961ff3e6b
parent 705 6de8252246b5
permissions -rw-r--r--
Using FastJar to read the content table of JAR files
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@705
    36
import java.util.zip.ZipEntry;
jaroslav@705
    37
import java.util.zip.ZipInputStream;
jaroslav@705
    38
jaroslav@705
    39
/**
jaroslav@705
    40
 *
jaroslav@705
    41
 * @author Tomas Zezula
jaroslav@705
    42
 */
jaroslav@705
    43
public final class FastJar {
jaroslav@706
    44
    private final byte[] arr;
jaroslav@705
    45
jaroslav@706
    46
    public FastJar(byte[] arr) {
jaroslav@706
    47
        this.arr = arr;
jaroslav@705
    48
    }
jaroslav@705
    49
    
jaroslav@705
    50
    
jaroslav@705
    51
    private static final int GIVE_UP = 1<<16;
jaroslav@705
    52
jaroslav@705
    53
    public static final  class Entry {
jaroslav@705
    54
        
jaroslav@705
    55
        public final String name;
jaroslav@705
    56
        final long offset;
jaroslav@705
    57
        private final long dosTime;
jaroslav@705
    58
        
jaroslav@706
    59
        Entry (String name, long offset, long time) {
jaroslav@705
    60
            assert name != null;
jaroslav@705
    61
            this.name = name;
jaroslav@705
    62
            this.offset = offset;
jaroslav@705
    63
            this.dosTime = time;
jaroslav@705
    64
        }        
jaroslav@706
    65
/*        
jaroslav@705
    66
        public long getTime () {
jaroslav@705
    67
            Date d = new Date((int)(((dosTime >> 25) & 0x7f) + 80),
jaroslav@705
    68
                    (int)(((dosTime >> 21) & 0x0f) - 1),
jaroslav@705
    69
                    (int)((dosTime >> 16) & 0x1f),
jaroslav@705
    70
                    (int)((dosTime >> 11) & 0x1f),
jaroslav@705
    71
                    (int)((dosTime >> 5) & 0x3f),
jaroslav@705
    72
                    (int)((dosTime << 1) & 0x3e));
jaroslav@705
    73
            return d.getTime();
jaroslav@705
    74
        }
jaroslav@706
    75
        */
jaroslav@705
    76
    }
jaroslav@705
    77
    
jaroslav@706
    78
    public InputStream getInputStream (final Entry e) throws IOException {
jaroslav@706
    79
        return getInputStream(arr, e.offset);
jaroslav@705
    80
    }
jaroslav@705
    81
    
jaroslav@706
    82
    private static InputStream getInputStream (byte[] arr, final long offset) throws IOException {
jaroslav@706
    83
        ByteArrayInputStream is = new ByteArrayInputStream(arr);
jaroslav@706
    84
        is.skip(offset);
jaroslav@706
    85
        ZipInputStream in = new ZipInputStream (is);
jaroslav@705
    86
        ZipEntry e = in.getNextEntry();
jaroslav@705
    87
        if (e != null && e.getCrc() == 0L && e.getMethod() == ZipEntry.STORED) {
jaroslav@706
    88
            int cp = arr.length - is.available();
jaroslav@706
    89
            return new ByteArrayInputStream(arr, cp, (int)e.getSize());
jaroslav@705
    90
        }
jaroslav@705
    91
        return in;
jaroslav@705
    92
    }
jaroslav@705
    93
    
jaroslav@706
    94
    public Entry[] list() throws IOException {
jaroslav@706
    95
        final int size = arr.length;
jaroslav@706
    96
jaroslav@706
    97
        int at = size - ZipInputStream.ENDHDR;
jaroslav@706
    98
jaroslav@706
    99
        byte[] data = new byte[ZipInputStream.ENDHDR];        
jaroslav@706
   100
        int giveup = 0;
jaroslav@706
   101
jaroslav@706
   102
        do {
jaroslav@706
   103
            org.apidesign.bck2brwsr.emul.lang.System.arraycopy(arr, at, data, 0, data.length);
jaroslav@706
   104
            at--;
jaroslav@706
   105
            giveup++;
jaroslav@706
   106
            if (giveup > GIVE_UP) {
jaroslav@706
   107
                throw new IOException ();
jaroslav@705
   108
            }
jaroslav@706
   109
        } while (getsig(data) != ZipInputStream.ENDSIG);
jaroslav@706
   110
jaroslav@706
   111
jaroslav@706
   112
        final long censize = endsiz(data);
jaroslav@706
   113
        final long cenoff  = endoff(data);
jaroslav@706
   114
        at = (int) cenoff;                                                     
jaroslav@706
   115
jaroslav@706
   116
        Entry[] result = new Entry[0];
jaroslav@706
   117
        int cenread = 0;
jaroslav@706
   118
        data = new byte[ZipInputStream.CENHDR];
jaroslav@706
   119
        while (cenread < censize) {
jaroslav@706
   120
            org.apidesign.bck2brwsr.emul.lang.System.arraycopy(arr, at, data, 0, data.length);
jaroslav@706
   121
            at += data.length;
jaroslav@706
   122
            if (getsig(data) != ZipInputStream.CENSIG) {
jaroslav@706
   123
                throw new IOException("No central table");          //NOI18N
jaroslav@706
   124
            }
jaroslav@706
   125
            int cennam = cennam(data);
jaroslav@706
   126
            int cenext = cenext(data);
jaroslav@706
   127
            int cencom = cencom(data);
jaroslav@706
   128
            long lhoff = cenoff(data);
jaroslav@706
   129
            long centim = centim(data);
jaroslav@706
   130
            String name = new String(arr, at, cennam, "UTF-8");
jaroslav@706
   131
            at += cennam;
jaroslav@706
   132
            int seekby = cenext+cencom;
jaroslav@706
   133
            int cendatalen = ZipInputStream.CENHDR + cennam + seekby;
jaroslav@706
   134
            cenread+=cendatalen;
jaroslav@706
   135
            result = addEntry(result, new Entry(name,lhoff, centim));
jaroslav@706
   136
            at += seekby;
jaroslav@705
   137
        }
jaroslav@706
   138
        return result;
jaroslav@705
   139
    }
jaroslav@705
   140
jaroslav@706
   141
    private Entry[] addEntry(Entry[] result, Entry entry) {
jaroslav@706
   142
        Entry[] e = new Entry[result.length + 1];
jaroslav@706
   143
        e[result.length] = entry;
jaroslav@706
   144
        org.apidesign.bck2brwsr.emul.lang.System.arraycopy(result, 0, e, 0, result.length);
jaroslav@706
   145
        return e;
jaroslav@705
   146
    }
jaroslav@705
   147
jaroslav@705
   148
    private static final long getsig(final byte[] b) throws IOException {return get32(b,0);}
jaroslav@706
   149
    private static final long endsiz(final byte[] b) throws IOException {return get32(b,ZipInputStream.ENDSIZ);}
jaroslav@706
   150
    private static final long endoff(final byte[] b) throws IOException {return get32(b,ZipInputStream.ENDOFF);}
jaroslav@706
   151
    private static final long  cenlen(final byte[] b) throws IOException {return get32(b,ZipInputStream.CENLEN);}
jaroslav@706
   152
    private static final long  censiz(final byte[] b) throws IOException {return get32(b,ZipInputStream.CENSIZ);}
jaroslav@706
   153
    private static final long centim(final byte[] b) throws IOException {return get32(b,ZipInputStream.CENTIM);}
jaroslav@706
   154
    private static final int  cennam(final byte[] b) throws IOException {return get16(b,ZipInputStream.CENNAM);}
jaroslav@706
   155
    private static final int  cenext(final byte[] b) throws IOException {return get16(b,ZipInputStream.CENEXT);}
jaroslav@706
   156
    private static final int  cencom(final byte[] b) throws IOException {return get16(b,ZipInputStream.CENCOM);}
jaroslav@706
   157
    private static final long cenoff (final byte[] b) throws IOException {return get32(b,ZipInputStream.CENOFF);}
jaroslav@706
   158
    private static final int lochow(final byte[] b) throws IOException {return get16(b,ZipInputStream.LOCHOW);}
jaroslav@706
   159
    private static final int locname(final byte[] b) throws IOException {return get16(b,ZipInputStream.LOCNAM);}
jaroslav@706
   160
    private static final int locext(final byte[] b) throws IOException {return get16(b,ZipInputStream.LOCEXT);}
jaroslav@706
   161
    private static final long locsiz(final byte[] b) throws IOException {return get32(b,ZipInputStream.LOCSIZ);}
jaroslav@705
   162
    
jaroslav@705
   163
    private static final int get16(final byte[] b, int off) throws IOException {        
jaroslav@705
   164
        final int b1 = b[off];
jaroslav@705
   165
	final int b2 = b[off+1];
jaroslav@705
   166
        return (b1 & 0xff) | ((b2 & 0xff) << 8);
jaroslav@705
   167
    }
jaroslav@705
   168
jaroslav@705
   169
    private static final long get32(final byte[] b, int off) throws IOException {
jaroslav@705
   170
	final int s1 = get16(b, off);
jaroslav@705
   171
	final int s2 = get16(b, off+2);
jaroslav@705
   172
        return s1 | ((long)s2 << 16);
jaroslav@705
   173
    }
jaroslav@705
   174
jaroslav@705
   175
}