emul/mini/src/main/java/org/apidesign/bck2brwsr/emul/zip/FastJar.java
author Jaroslav Tulach <jaroslav.tulach@apidesign.org>
Sun, 10 Feb 2013 09:51:22 +0100
branchemul
changeset 705 6de8252246b5
child 706 a48961ff3e6b
permissions -rw-r--r--
Original version of NetBeans FastJar from release73 branch
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@705
    31
package org.netbeans.modules.java.source.parsing;
jaroslav@705
    32
jaroslav@705
    33
import java.io.File;
jaroslav@705
    34
import java.io.IOException;
jaroslav@705
    35
import java.io.InputStream;
jaroslav@705
    36
import java.io.RandomAccessFile;
jaroslav@705
    37
import java.util.Date;
jaroslav@705
    38
import java.util.LinkedList;
jaroslav@705
    39
import java.util.List;
jaroslav@705
    40
import java.util.zip.ZipEntry;
jaroslav@705
    41
import java.util.zip.ZipFile;
jaroslav@705
    42
import java.util.zip.ZipInputStream;
jaroslav@705
    43
jaroslav@705
    44
/**
jaroslav@705
    45
 *
jaroslav@705
    46
 * @author Tomas Zezula
jaroslav@705
    47
 */
jaroslav@705
    48
public final class FastJar {
jaroslav@705
    49
jaroslav@705
    50
    private FastJar() {
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
    
jaroslav@705
    57
    private static class RandomAccessFileInputStream extends InputStream {
jaroslav@705
    58
        
jaroslav@705
    59
        private final RandomAccessFile b;
jaroslav@705
    60
        private final long len;
jaroslav@705
    61
        
jaroslav@705
    62
        public RandomAccessFileInputStream (RandomAccessFile b) throws IOException {
jaroslav@705
    63
            assert b != null;
jaroslav@705
    64
            this.b = b;
jaroslav@705
    65
            this.len = b.length();
jaroslav@705
    66
        }
jaroslav@705
    67
        
jaroslav@705
    68
        public RandomAccessFileInputStream (RandomAccessFile b, long len) throws IOException {
jaroslav@705
    69
            assert b != null;
jaroslav@705
    70
            assert len >=0;
jaroslav@705
    71
            this.b = b;
jaroslav@705
    72
            this.len = b.getFilePointer()+len;
jaroslav@705
    73
        }
jaroslav@705
    74
    
jaroslav@705
    75
        public int read (byte[] data, int offset, int size) throws IOException {
jaroslav@705
    76
            int rem = available();
jaroslav@705
    77
            if (rem == 0) {
jaroslav@705
    78
                return -1;
jaroslav@705
    79
            }
jaroslav@705
    80
            int rlen;
jaroslav@705
    81
            if (size<rem) {
jaroslav@705
    82
                rlen = size;
jaroslav@705
    83
            }
jaroslav@705
    84
            else {
jaroslav@705
    85
                rlen = rem;
jaroslav@705
    86
            }
jaroslav@705
    87
            return this.b.read(data, offset, rlen);
jaroslav@705
    88
        }
jaroslav@705
    89
jaroslav@705
    90
        public int read() throws java.io.IOException {
jaroslav@705
    91
            if (available()==0) {
jaroslav@705
    92
                return -1;
jaroslav@705
    93
            }
jaroslav@705
    94
            else {
jaroslav@705
    95
                return b.readByte();
jaroslav@705
    96
            }
jaroslav@705
    97
        }
jaroslav@705
    98
        
jaroslav@705
    99
        public int available () throws IOException {
jaroslav@705
   100
             return (int) (len - this.b.getFilePointer());
jaroslav@705
   101
        }
jaroslav@705
   102
        
jaroslav@705
   103
        public void close () throws IOException {
jaroslav@705
   104
            b.close ();
jaroslav@705
   105
        }
jaroslav@705
   106
    }
jaroslav@705
   107
    
jaroslav@705
   108
    public static final  class Entry {
jaroslav@705
   109
        
jaroslav@705
   110
        public final String name;
jaroslav@705
   111
        final long offset;
jaroslav@705
   112
        private final long dosTime;
jaroslav@705
   113
        
jaroslav@705
   114
        public Entry (String name, long offset, long time) {
jaroslav@705
   115
            assert name != null;
jaroslav@705
   116
            this.name = name;
jaroslav@705
   117
            this.offset = offset;
jaroslav@705
   118
            this.dosTime = time;
jaroslav@705
   119
        }        
jaroslav@705
   120
        
jaroslav@705
   121
        public long getTime () {
jaroslav@705
   122
            Date d = new Date((int)(((dosTime >> 25) & 0x7f) + 80),
jaroslav@705
   123
                    (int)(((dosTime >> 21) & 0x0f) - 1),
jaroslav@705
   124
                    (int)((dosTime >> 16) & 0x1f),
jaroslav@705
   125
                    (int)((dosTime >> 11) & 0x1f),
jaroslav@705
   126
                    (int)((dosTime >> 5) & 0x3f),
jaroslav@705
   127
                    (int)((dosTime << 1) & 0x3e));
jaroslav@705
   128
            return d.getTime();
jaroslav@705
   129
        }
jaroslav@705
   130
    }
jaroslav@705
   131
    
jaroslav@705
   132
    public static InputStream getInputStream (final File file, final Entry e) throws IOException {
jaroslav@705
   133
        return getInputStream(file, e.offset);
jaroslav@705
   134
    }
jaroslav@705
   135
    
jaroslav@705
   136
    static InputStream getInputStream (final File file, final long offset) throws IOException {
jaroslav@705
   137
        RandomAccessFile  f = new RandomAccessFile (file, "r");     //NOI18N
jaroslav@705
   138
        f.seek (offset);
jaroslav@705
   139
        ZipInputStream in = new ZipInputStream (new RandomAccessFileInputStream (f));
jaroslav@705
   140
        ZipEntry e = in.getNextEntry();
jaroslav@705
   141
        if (e != null && e.getCrc() == 0L && e.getMethod() == ZipEntry.STORED) {
jaroslav@705
   142
            long cp = f.getFilePointer();
jaroslav@705
   143
            in.close();
jaroslav@705
   144
            f = new RandomAccessFile (file, "r");     //NOI18N
jaroslav@705
   145
            f.seek (cp);
jaroslav@705
   146
            return new RandomAccessFileInputStream (f, e.getSize());
jaroslav@705
   147
        }
jaroslav@705
   148
        return in;
jaroslav@705
   149
    }
jaroslav@705
   150
    
jaroslav@705
   151
    static ZipEntry getZipEntry (final File file, final long offset) throws IOException {
jaroslav@705
   152
        RandomAccessFile  f = new RandomAccessFile (file, "r");     //NOI18N
jaroslav@705
   153
        try {
jaroslav@705
   154
            f.seek (offset);
jaroslav@705
   155
            ZipInputStream in = new ZipInputStream (new RandomAccessFileInputStream (f));
jaroslav@705
   156
            try {
jaroslav@705
   157
                return in.getNextEntry();
jaroslav@705
   158
            } finally {
jaroslav@705
   159
                in.close();
jaroslav@705
   160
            }
jaroslav@705
   161
        } finally {
jaroslav@705
   162
            f.close ();
jaroslav@705
   163
        }
jaroslav@705
   164
    }
jaroslav@705
   165
jaroslav@705
   166
    public static Iterable<? extends Entry> list(File f) throws IOException {
jaroslav@705
   167
        RandomAccessFile b = new RandomAccessFile (f,"r");      //NOI18N
jaroslav@705
   168
        try {
jaroslav@705
   169
            final long size = (int) b.length();
jaroslav@705
   170
            b.seek (size-ZipFile.ENDHDR);                                           
jaroslav@705
   171
jaroslav@705
   172
            byte[] data = new byte[ZipFile.ENDHDR];        
jaroslav@705
   173
            int giveup = 0;
jaroslav@705
   174
jaroslav@705
   175
            do {
jaroslav@705
   176
                if (b.read(data, 0, ZipFile.ENDHDR)!=ZipFile.ENDHDR) {
jaroslav@705
   177
                    throw new IOException ();
jaroslav@705
   178
                }
jaroslav@705
   179
                b.seek(b.getFilePointer()-(ZipFile.ENDHDR+1));
jaroslav@705
   180
                giveup++;
jaroslav@705
   181
                if (giveup > GIVE_UP) {
jaroslav@705
   182
                    throw new IOException ();
jaroslav@705
   183
                }
jaroslav@705
   184
            } while (getsig(data) != ZipFile.ENDSIG);
jaroslav@705
   185
jaroslav@705
   186
jaroslav@705
   187
            final long censize = endsiz(data);
jaroslav@705
   188
            final long cenoff  = endoff(data);
jaroslav@705
   189
            b.seek (cenoff);                                                        
jaroslav@705
   190
jaroslav@705
   191
            List<Entry> result = new LinkedList<Entry>();
jaroslav@705
   192
            int cenread = 0;
jaroslav@705
   193
            data = new byte[ZipFile.CENHDR];
jaroslav@705
   194
            while (cenread < censize) {
jaroslav@705
   195
                if (b.read(data, 0, ZipFile.CENHDR)!=ZipFile.CENHDR) {
jaroslav@705
   196
                    throw new IOException ("No central table");         //NOI18N
jaroslav@705
   197
                }             
jaroslav@705
   198
                if (getsig(data) != ZipFile.CENSIG) {
jaroslav@705
   199
                    throw new IOException("No central table");          //NOI18N
jaroslav@705
   200
                }
jaroslav@705
   201
                int cennam = cennam(data);
jaroslav@705
   202
                int cenext = cenext(data);
jaroslav@705
   203
                int cencom = cencom(data);
jaroslav@705
   204
                long lhoff = cenoff(data);
jaroslav@705
   205
                long centim = centim(data);
jaroslav@705
   206
                String name = name(b, cennam);
jaroslav@705
   207
                int seekby = cenext+cencom;
jaroslav@705
   208
                int cendatalen = ZipFile.CENHDR + cennam + seekby;
jaroslav@705
   209
                cenread+=cendatalen;
jaroslav@705
   210
                result.add(new Entry(name,lhoff, centim));
jaroslav@705
   211
                seekBy(b,seekby);
jaroslav@705
   212
            }
jaroslav@705
   213
            return result;
jaroslav@705
   214
        } finally {
jaroslav@705
   215
            b.close();
jaroslav@705
   216
        }
jaroslav@705
   217
    }
jaroslav@705
   218
jaroslav@705
   219
    private static final String name(final RandomAccessFile b, final int cennam) throws IOException {
jaroslav@705
   220
	byte[] name = new byte[cennam];
jaroslav@705
   221
	b.read(name, 0, cennam);
jaroslav@705
   222
	return new String(name, "UTF-8");       //NOI18N
jaroslav@705
   223
    }
jaroslav@705
   224
jaroslav@705
   225
    private static final long getsig(final byte[] b) throws IOException {return get32(b,0);}
jaroslav@705
   226
    private static final long endsiz(final byte[] b) throws IOException {return get32(b,ZipFile.ENDSIZ);}
jaroslav@705
   227
    private static final long endoff(final byte[] b) throws IOException {return get32(b,ZipFile.ENDOFF);}
jaroslav@705
   228
    private static final long  cenlen(final byte[] b) throws IOException {return get32(b,ZipFile.CENLEN);}
jaroslav@705
   229
    private static final long  censiz(final byte[] b) throws IOException {return get32(b,ZipFile.CENSIZ);}
jaroslav@705
   230
    private static final long centim(final byte[] b) throws IOException {return get32(b,ZipFile.CENTIM);}
jaroslav@705
   231
    private static final int  cennam(final byte[] b) throws IOException {return get16(b,ZipFile.CENNAM);}
jaroslav@705
   232
    private static final int  cenext(final byte[] b) throws IOException {return get16(b,ZipFile.CENEXT);}
jaroslav@705
   233
    private static final int  cencom(final byte[] b) throws IOException {return get16(b,ZipFile.CENCOM);}
jaroslav@705
   234
    private static final long cenoff (final byte[] b) throws IOException {return get32(b,ZipFile.CENOFF);}
jaroslav@705
   235
    private static final int lochow(final byte[] b) throws IOException {return get16(b,ZipFile.LOCHOW);}
jaroslav@705
   236
    private static final int locname(final byte[] b) throws IOException {return get16(b,ZipFile.LOCNAM);}
jaroslav@705
   237
    private static final int locext(final byte[] b) throws IOException {return get16(b,ZipFile.LOCEXT);}
jaroslav@705
   238
    private static final long locsiz(final byte[] b) throws IOException {return get32(b,ZipFile.LOCSIZ);}
jaroslav@705
   239
    
jaroslav@705
   240
    private static final void seekBy(final RandomAccessFile b, int offset) throws IOException {
jaroslav@705
   241
        b.seek(b.getFilePointer() + offset);
jaroslav@705
   242
    }
jaroslav@705
   243
jaroslav@705
   244
    private static final int get16(final byte[] b, int off) throws IOException {        
jaroslav@705
   245
        final int b1 = b[off];
jaroslav@705
   246
	final int b2 = b[off+1];
jaroslav@705
   247
        return (b1 & 0xff) | ((b2 & 0xff) << 8);
jaroslav@705
   248
    }
jaroslav@705
   249
jaroslav@705
   250
    private static final long get32(final byte[] b, int off) throws IOException {
jaroslav@705
   251
	final int s1 = get16(b, off);
jaroslav@705
   252
	final int s2 = get16(b, off+2);
jaroslav@705
   253
        return s1 | ((long)s2 << 16);
jaroslav@705
   254
    }
jaroslav@705
   255
jaroslav@705
   256
}