jaroslav@705: /* jaroslav@705: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. jaroslav@705: * jaroslav@705: * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved. jaroslav@705: * jaroslav@705: * Oracle and Java are registered trademarks of Oracle and/or its affiliates. jaroslav@705: * Other names may be trademarks of their respective owners. jaroslav@705: * jaroslav@705: * The contents of this file are subject to the terms of either the GNU jaroslav@705: * General Public License Version 2 only ("GPL") or the Common jaroslav@705: * Development and Distribution License("CDDL") (collectively, the jaroslav@705: * "License"). You may not use this file except in compliance with the jaroslav@705: * License. You can obtain a copy of the License at jaroslav@705: * http://www.netbeans.org/cddl-gplv2.html jaroslav@705: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the jaroslav@705: * specific language governing permissions and limitations under the jaroslav@705: * License. When distributing the software, include this License Header jaroslav@705: * Notice in each file and include the License file at jaroslav@705: * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this jaroslav@705: * particular file as subject to the "Classpath" exception as provided jaroslav@705: * by Oracle in the GPL Version 2 section of the License file that jaroslav@705: * accompanied this code. If applicable, add the following below the jaroslav@705: * License Header, with the fields enclosed by brackets [] replaced by jaroslav@705: * your own identifying information: jaroslav@705: * "Portions Copyrighted [year] [name of copyright owner]" jaroslav@705: * jaroslav@705: * Contributor(s): jaroslav@705: * jaroslav@705: * Portions Copyrighted 2007 Sun Microsystems, Inc. jaroslav@705: */ jaroslav@705: package org.netbeans.modules.java.source.parsing; jaroslav@705: jaroslav@705: import java.io.File; jaroslav@705: import java.io.IOException; jaroslav@705: import java.io.InputStream; jaroslav@705: import java.io.RandomAccessFile; jaroslav@705: import java.util.Date; jaroslav@705: import java.util.LinkedList; jaroslav@705: import java.util.List; jaroslav@705: import java.util.zip.ZipEntry; jaroslav@705: import java.util.zip.ZipFile; jaroslav@705: import java.util.zip.ZipInputStream; jaroslav@705: jaroslav@705: /** jaroslav@705: * jaroslav@705: * @author Tomas Zezula jaroslav@705: */ jaroslav@705: public final class FastJar { jaroslav@705: jaroslav@705: private FastJar() { jaroslav@705: } jaroslav@705: jaroslav@705: jaroslav@705: private static final int GIVE_UP = 1<<16; jaroslav@705: jaroslav@705: jaroslav@705: private static class RandomAccessFileInputStream extends InputStream { jaroslav@705: jaroslav@705: private final RandomAccessFile b; jaroslav@705: private final long len; jaroslav@705: jaroslav@705: public RandomAccessFileInputStream (RandomAccessFile b) throws IOException { jaroslav@705: assert b != null; jaroslav@705: this.b = b; jaroslav@705: this.len = b.length(); jaroslav@705: } jaroslav@705: jaroslav@705: public RandomAccessFileInputStream (RandomAccessFile b, long len) throws IOException { jaroslav@705: assert b != null; jaroslav@705: assert len >=0; jaroslav@705: this.b = b; jaroslav@705: this.len = b.getFilePointer()+len; jaroslav@705: } jaroslav@705: jaroslav@705: public int read (byte[] data, int offset, int size) throws IOException { jaroslav@705: int rem = available(); jaroslav@705: if (rem == 0) { jaroslav@705: return -1; jaroslav@705: } jaroslav@705: int rlen; jaroslav@705: if (size> 25) & 0x7f) + 80), jaroslav@705: (int)(((dosTime >> 21) & 0x0f) - 1), jaroslav@705: (int)((dosTime >> 16) & 0x1f), jaroslav@705: (int)((dosTime >> 11) & 0x1f), jaroslav@705: (int)((dosTime >> 5) & 0x3f), jaroslav@705: (int)((dosTime << 1) & 0x3e)); jaroslav@705: return d.getTime(); jaroslav@705: } jaroslav@705: } jaroslav@705: jaroslav@705: public static InputStream getInputStream (final File file, final Entry e) throws IOException { jaroslav@705: return getInputStream(file, e.offset); jaroslav@705: } jaroslav@705: jaroslav@705: static InputStream getInputStream (final File file, final long offset) throws IOException { jaroslav@705: RandomAccessFile f = new RandomAccessFile (file, "r"); //NOI18N jaroslav@705: f.seek (offset); jaroslav@705: ZipInputStream in = new ZipInputStream (new RandomAccessFileInputStream (f)); jaroslav@705: ZipEntry e = in.getNextEntry(); jaroslav@705: if (e != null && e.getCrc() == 0L && e.getMethod() == ZipEntry.STORED) { jaroslav@705: long cp = f.getFilePointer(); jaroslav@705: in.close(); jaroslav@705: f = new RandomAccessFile (file, "r"); //NOI18N jaroslav@705: f.seek (cp); jaroslav@705: return new RandomAccessFileInputStream (f, e.getSize()); jaroslav@705: } jaroslav@705: return in; jaroslav@705: } jaroslav@705: jaroslav@705: static ZipEntry getZipEntry (final File file, final long offset) throws IOException { jaroslav@705: RandomAccessFile f = new RandomAccessFile (file, "r"); //NOI18N jaroslav@705: try { jaroslav@705: f.seek (offset); jaroslav@705: ZipInputStream in = new ZipInputStream (new RandomAccessFileInputStream (f)); jaroslav@705: try { jaroslav@705: return in.getNextEntry(); jaroslav@705: } finally { jaroslav@705: in.close(); jaroslav@705: } jaroslav@705: } finally { jaroslav@705: f.close (); jaroslav@705: } jaroslav@705: } jaroslav@705: jaroslav@705: public static Iterable list(File f) throws IOException { jaroslav@705: RandomAccessFile b = new RandomAccessFile (f,"r"); //NOI18N jaroslav@705: try { jaroslav@705: final long size = (int) b.length(); jaroslav@705: b.seek (size-ZipFile.ENDHDR); jaroslav@705: jaroslav@705: byte[] data = new byte[ZipFile.ENDHDR]; jaroslav@705: int giveup = 0; jaroslav@705: jaroslav@705: do { jaroslav@705: if (b.read(data, 0, ZipFile.ENDHDR)!=ZipFile.ENDHDR) { jaroslav@705: throw new IOException (); jaroslav@705: } jaroslav@705: b.seek(b.getFilePointer()-(ZipFile.ENDHDR+1)); jaroslav@705: giveup++; jaroslav@705: if (giveup > GIVE_UP) { jaroslav@705: throw new IOException (); jaroslav@705: } jaroslav@705: } while (getsig(data) != ZipFile.ENDSIG); jaroslav@705: jaroslav@705: jaroslav@705: final long censize = endsiz(data); jaroslav@705: final long cenoff = endoff(data); jaroslav@705: b.seek (cenoff); jaroslav@705: jaroslav@705: List result = new LinkedList(); jaroslav@705: int cenread = 0; jaroslav@705: data = new byte[ZipFile.CENHDR]; jaroslav@705: while (cenread < censize) { jaroslav@705: if (b.read(data, 0, ZipFile.CENHDR)!=ZipFile.CENHDR) { jaroslav@705: throw new IOException ("No central table"); //NOI18N jaroslav@705: } jaroslav@705: if (getsig(data) != ZipFile.CENSIG) { jaroslav@705: throw new IOException("No central table"); //NOI18N jaroslav@705: } jaroslav@705: int cennam = cennam(data); jaroslav@705: int cenext = cenext(data); jaroslav@705: int cencom = cencom(data); jaroslav@705: long lhoff = cenoff(data); jaroslav@705: long centim = centim(data); jaroslav@705: String name = name(b, cennam); jaroslav@705: int seekby = cenext+cencom; jaroslav@705: int cendatalen = ZipFile.CENHDR + cennam + seekby; jaroslav@705: cenread+=cendatalen; jaroslav@705: result.add(new Entry(name,lhoff, centim)); jaroslav@705: seekBy(b,seekby); jaroslav@705: } jaroslav@705: return result; jaroslav@705: } finally { jaroslav@705: b.close(); jaroslav@705: } jaroslav@705: } jaroslav@705: jaroslav@705: private static final String name(final RandomAccessFile b, final int cennam) throws IOException { jaroslav@705: byte[] name = new byte[cennam]; jaroslav@705: b.read(name, 0, cennam); jaroslav@705: return new String(name, "UTF-8"); //NOI18N jaroslav@705: } jaroslav@705: jaroslav@705: private static final long getsig(final byte[] b) throws IOException {return get32(b,0);} jaroslav@705: private static final long endsiz(final byte[] b) throws IOException {return get32(b,ZipFile.ENDSIZ);} jaroslav@705: private static final long endoff(final byte[] b) throws IOException {return get32(b,ZipFile.ENDOFF);} jaroslav@705: private static final long cenlen(final byte[] b) throws IOException {return get32(b,ZipFile.CENLEN);} jaroslav@705: private static final long censiz(final byte[] b) throws IOException {return get32(b,ZipFile.CENSIZ);} jaroslav@705: private static final long centim(final byte[] b) throws IOException {return get32(b,ZipFile.CENTIM);} jaroslav@705: private static final int cennam(final byte[] b) throws IOException {return get16(b,ZipFile.CENNAM);} jaroslav@705: private static final int cenext(final byte[] b) throws IOException {return get16(b,ZipFile.CENEXT);} jaroslav@705: private static final int cencom(final byte[] b) throws IOException {return get16(b,ZipFile.CENCOM);} jaroslav@705: private static final long cenoff (final byte[] b) throws IOException {return get32(b,ZipFile.CENOFF);} jaroslav@705: private static final int lochow(final byte[] b) throws IOException {return get16(b,ZipFile.LOCHOW);} jaroslav@705: private static final int locname(final byte[] b) throws IOException {return get16(b,ZipFile.LOCNAM);} jaroslav@705: private static final int locext(final byte[] b) throws IOException {return get16(b,ZipFile.LOCEXT);} jaroslav@705: private static final long locsiz(final byte[] b) throws IOException {return get32(b,ZipFile.LOCSIZ);} jaroslav@705: jaroslav@705: private static final void seekBy(final RandomAccessFile b, int offset) throws IOException { jaroslav@705: b.seek(b.getFilePointer() + offset); jaroslav@705: } jaroslav@705: jaroslav@705: private static final int get16(final byte[] b, int off) throws IOException { jaroslav@705: final int b1 = b[off]; jaroslav@705: final int b2 = b[off+1]; jaroslav@705: return (b1 & 0xff) | ((b2 & 0xff) << 8); jaroslav@705: } jaroslav@705: jaroslav@705: private static final long get32(final byte[] b, int off) throws IOException { jaroslav@705: final int s1 = get16(b, off); jaroslav@705: final int s2 = get16(b, off+2); jaroslav@705: return s1 | ((long)s2 << 16); jaroslav@705: } jaroslav@705: jaroslav@705: }