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 |
}
|