2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
4 * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
6 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
7 * Other names may be trademarks of their respective owners.
9 * The contents of this file are subject to the terms of either the GNU
10 * General Public License Version 2 only ("GPL") or the Common
11 * Development and Distribution License("CDDL") (collectively, the
12 * "License"). You may not use this file except in compliance with the
13 * License. You can obtain a copy of the License at
14 * http://www.netbeans.org/cddl-gplv2.html
15 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
16 * specific language governing permissions and limitations under the
17 * License. When distributing the software, include this License Header
18 * Notice in each file and include the License file at
19 * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
20 * particular file as subject to the "Classpath" exception as provided
21 * by Oracle in the GPL Version 2 section of the License file that
22 * accompanied this code. If applicable, add the following below the
23 * License Header, with the fields enclosed by brackets [] replaced by
24 * your own identifying information:
25 * "Portions Copyrighted [year] [name of copyright owner]"
29 * Portions Copyrighted 2007 Sun Microsystems, Inc.
31 package org.netbeans.modules.java.source.parsing;
34 import java.io.IOException;
35 import java.io.InputStream;
36 import java.io.RandomAccessFile;
37 import java.util.Date;
38 import java.util.LinkedList;
39 import java.util.List;
40 import java.util.zip.ZipEntry;
41 import java.util.zip.ZipFile;
42 import java.util.zip.ZipInputStream;
46 * @author Tomas Zezula
48 public final class FastJar {
54 private static final int GIVE_UP = 1<<16;
57 private static class RandomAccessFileInputStream extends InputStream {
59 private final RandomAccessFile b;
60 private final long len;
62 public RandomAccessFileInputStream (RandomAccessFile b) throws IOException {
65 this.len = b.length();
68 public RandomAccessFileInputStream (RandomAccessFile b, long len) throws IOException {
72 this.len = b.getFilePointer()+len;
75 public int read (byte[] data, int offset, int size) throws IOException {
76 int rem = available();
87 return this.b.read(data, offset, rlen);
90 public int read() throws java.io.IOException {
99 public int available () throws IOException {
100 return (int) (len - this.b.getFilePointer());
103 public void close () throws IOException {
108 public static final class Entry {
110 public final String name;
112 private final long dosTime;
114 public Entry (String name, long offset, long time) {
117 this.offset = offset;
121 public long getTime () {
122 Date d = new Date((int)(((dosTime >> 25) & 0x7f) + 80),
123 (int)(((dosTime >> 21) & 0x0f) - 1),
124 (int)((dosTime >> 16) & 0x1f),
125 (int)((dosTime >> 11) & 0x1f),
126 (int)((dosTime >> 5) & 0x3f),
127 (int)((dosTime << 1) & 0x3e));
132 public static InputStream getInputStream (final File file, final Entry e) throws IOException {
133 return getInputStream(file, e.offset);
136 static InputStream getInputStream (final File file, final long offset) throws IOException {
137 RandomAccessFile f = new RandomAccessFile (file, "r"); //NOI18N
139 ZipInputStream in = new ZipInputStream (new RandomAccessFileInputStream (f));
140 ZipEntry e = in.getNextEntry();
141 if (e != null && e.getCrc() == 0L && e.getMethod() == ZipEntry.STORED) {
142 long cp = f.getFilePointer();
144 f = new RandomAccessFile (file, "r"); //NOI18N
146 return new RandomAccessFileInputStream (f, e.getSize());
151 static ZipEntry getZipEntry (final File file, final long offset) throws IOException {
152 RandomAccessFile f = new RandomAccessFile (file, "r"); //NOI18N
155 ZipInputStream in = new ZipInputStream (new RandomAccessFileInputStream (f));
157 return in.getNextEntry();
166 public static Iterable<? extends Entry> list(File f) throws IOException {
167 RandomAccessFile b = new RandomAccessFile (f,"r"); //NOI18N
169 final long size = (int) b.length();
170 b.seek (size-ZipFile.ENDHDR);
172 byte[] data = new byte[ZipFile.ENDHDR];
176 if (b.read(data, 0, ZipFile.ENDHDR)!=ZipFile.ENDHDR) {
177 throw new IOException ();
179 b.seek(b.getFilePointer()-(ZipFile.ENDHDR+1));
181 if (giveup > GIVE_UP) {
182 throw new IOException ();
184 } while (getsig(data) != ZipFile.ENDSIG);
187 final long censize = endsiz(data);
188 final long cenoff = endoff(data);
191 List<Entry> result = new LinkedList<Entry>();
193 data = new byte[ZipFile.CENHDR];
194 while (cenread < censize) {
195 if (b.read(data, 0, ZipFile.CENHDR)!=ZipFile.CENHDR) {
196 throw new IOException ("No central table"); //NOI18N
198 if (getsig(data) != ZipFile.CENSIG) {
199 throw new IOException("No central table"); //NOI18N
201 int cennam = cennam(data);
202 int cenext = cenext(data);
203 int cencom = cencom(data);
204 long lhoff = cenoff(data);
205 long centim = centim(data);
206 String name = name(b, cennam);
207 int seekby = cenext+cencom;
208 int cendatalen = ZipFile.CENHDR + cennam + seekby;
210 result.add(new Entry(name,lhoff, centim));
219 private static final String name(final RandomAccessFile b, final int cennam) throws IOException {
220 byte[] name = new byte[cennam];
221 b.read(name, 0, cennam);
222 return new String(name, "UTF-8"); //NOI18N
225 private static final long getsig(final byte[] b) throws IOException {return get32(b,0);}
226 private static final long endsiz(final byte[] b) throws IOException {return get32(b,ZipFile.ENDSIZ);}
227 private static final long endoff(final byte[] b) throws IOException {return get32(b,ZipFile.ENDOFF);}
228 private static final long cenlen(final byte[] b) throws IOException {return get32(b,ZipFile.CENLEN);}
229 private static final long censiz(final byte[] b) throws IOException {return get32(b,ZipFile.CENSIZ);}
230 private static final long centim(final byte[] b) throws IOException {return get32(b,ZipFile.CENTIM);}
231 private static final int cennam(final byte[] b) throws IOException {return get16(b,ZipFile.CENNAM);}
232 private static final int cenext(final byte[] b) throws IOException {return get16(b,ZipFile.CENEXT);}
233 private static final int cencom(final byte[] b) throws IOException {return get16(b,ZipFile.CENCOM);}
234 private static final long cenoff (final byte[] b) throws IOException {return get32(b,ZipFile.CENOFF);}
235 private static final int lochow(final byte[] b) throws IOException {return get16(b,ZipFile.LOCHOW);}
236 private static final int locname(final byte[] b) throws IOException {return get16(b,ZipFile.LOCNAM);}
237 private static final int locext(final byte[] b) throws IOException {return get16(b,ZipFile.LOCEXT);}
238 private static final long locsiz(final byte[] b) throws IOException {return get32(b,ZipFile.LOCSIZ);}
240 private static final void seekBy(final RandomAccessFile b, int offset) throws IOException {
241 b.seek(b.getFilePointer() + offset);
244 private static final int get16(final byte[] b, int off) throws IOException {
245 final int b1 = b[off];
246 final int b2 = b[off+1];
247 return (b1 & 0xff) | ((b2 & 0xff) << 8);
250 private static final long get32(final byte[] b, int off) throws IOException {
251 final int s1 = get16(b, off);
252 final int s2 = get16(b, off+2);
253 return s1 | ((long)s2 << 16);