1 /*
2 * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
39 *
40 * @author David Connelly
41 * @see Manifest
42 * @see java.util.zip.ZipInputStream
43 * @since 1.2
44 */
45 public
46 class JarInputStream extends ZipInputStream {
47 private Manifest man;
48 private JarEntry first;
49 private JarVerifier jv;
50 private ManifestEntryVerifier mev;
51 private final boolean doVerify;
52 private boolean tryManifest;
53
54 /**
55 * Creates a new <code>JarInputStream</code> and reads the optional
56 * manifest. If a manifest is present, also attempts to verify
57 * the signatures if the JarInputStream is signed.
58 * @param in the actual input stream
59 * @exception IOException if an I/O error has occurred
60 */
61 public JarInputStream(InputStream in) throws IOException {
62 this(in, true);
63 }
64
65 /**
66 * Creates a new <code>JarInputStream</code> and reads the optional
67 * manifest. If a manifest is present and verify is true, also attempts
68 * to verify the signatures if the JarInputStream is signed.
69 *
70 * @param in the actual input stream
71 * @param verify whether or not to verify the JarInputStream if
72 * it is signed.
73 * @exception IOException if an I/O error has occurred
74 */
75 public JarInputStream(InputStream in, boolean verify) throws IOException {
76 super(in);
77 this.doVerify = verify;
78
79 // This implementation assumes the META-INF/MANIFEST.MF entry
80 // should be either the first or the second entry (when preceded
81 // by the dir META-INF/). It skips the META-INF/ and then
82 // "consumes" the MANIFEST.MF to initialize the Manifest object.
83 JarEntry e = (JarEntry)super.getNextEntry();
84 if (e != null && e.getName().equalsIgnoreCase("META-INF/"))
85 e = (JarEntry)super.getNextEntry();
86 first = checkManifest(e);
87 }
88
89 private JarEntry checkManifest(JarEntry e)
90 throws IOException
91 {
92 if (e != null && JarFile.MANIFEST_NAME.equalsIgnoreCase(e.getName())) {
93 man = new Manifest();
114 }
115 return baos.toByteArray();
116 }
117
118 /**
119 * Returns the <code>Manifest</code> for this JAR file, or
120 * <code>null</code> if none.
121 *
122 * @return the <code>Manifest</code> for this JAR file, or
123 * <code>null</code> if none.
124 */
125 public Manifest getManifest() {
126 return man;
127 }
128
129 /**
130 * Reads the next ZIP file entry and positions the stream at the
131 * beginning of the entry data. If verification has been enabled,
132 * any invalid signature detected while positioning the stream for
133 * the next entry will result in an exception.
134 * @exception ZipException if a ZIP file error has occurred
135 * @exception IOException if an I/O error has occurred
136 * @exception SecurityException if any of the jar file entries
137 * are incorrectly signed.
138 */
139 public ZipEntry getNextEntry() throws IOException {
140 JarEntry e;
141 if (first == null) {
142 e = (JarEntry)super.getNextEntry();
143 if (tryManifest) {
144 e = checkManifest(e);
145 tryManifest = false;
146 }
147 } else {
148 e = first;
149 if (first.getName().equalsIgnoreCase(JarIndex.INDEX_NAME))
150 tryManifest = true;
151 first = null;
152 }
153 if (jv != null && e != null) {
154 // At this point, we might have parsed all the meta-inf
155 // entries and have nothing to verify. If we have
156 // nothing to verify, get rid of the JarVerifier object.
157 if (jv.nothingToVerify() == true) {
158 jv = null;
159 mev = null;
160 } else {
161 jv.beginEntry(e, mev);
162 }
163 }
164 return e;
165 }
166
167 /**
168 * Reads the next JAR file entry and positions the stream at the
169 * beginning of the entry data. If verification has been enabled,
170 * any invalid signature detected while positioning the stream for
171 * the next entry will result in an exception.
172 * @return the next JAR file entry, or null if there are no more entries
173 * @exception ZipException if a ZIP file error has occurred
174 * @exception IOException if an I/O error has occurred
175 * @exception SecurityException if any of the jar file entries
176 * are incorrectly signed.
177 */
178 public JarEntry getNextJarEntry() throws IOException {
179 return (JarEntry)getNextEntry();
180 }
181
182 /**
183 * Reads from the current JAR file entry into an array of bytes.
184 * If <code>len</code> is not zero, the method
185 * blocks until some input is available; otherwise, no
186 * bytes are read and <code>0</code> is returned.
187 * If verification has been enabled, any invalid signature
188 * on the current entry will be reported at some point before the
189 * end of the entry is reached.
190 * @param b the buffer into which the data is read
191 * @param off the start offset in the destination array <code>b</code>
192 * @param len the maximum number of bytes to read
193 * @return the actual number of bytes read, or -1 if the end of the
194 * entry is reached
195 * @exception NullPointerException If <code>b</code> is <code>null</code>.
196 * @exception IndexOutOfBoundsException If <code>off</code> is negative,
197 * <code>len</code> is negative, or <code>len</code> is greater than
198 * <code>b.length - off</code>
199 * @exception ZipException if a ZIP file error has occurred
200 * @exception IOException if an I/O error has occurred
201 * @exception SecurityException if any of the jar file entries
202 * are incorrectly signed.
203 */
204 public int read(byte[] b, int off, int len) throws IOException {
205 int n;
206 if (first == null) {
207 n = super.read(b, off, len);
208 } else {
209 n = -1;
210 }
211 if (jv != null) {
212 jv.update(n, b, off, len, mev);
213 }
214 return n;
215 }
216
217 /**
218 * Creates a new <code>JarEntry</code> (<code>ZipEntry</code>) for the
219 * specified JAR file entry name. The manifest attributes of
220 * the specified JAR file entry name will be copied to the new
221 * <CODE>JarEntry</CODE>.
|
1 /*
2 * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
39 *
40 * @author David Connelly
41 * @see Manifest
42 * @see java.util.zip.ZipInputStream
43 * @since 1.2
44 */
45 public
46 class JarInputStream extends ZipInputStream {
47 private Manifest man;
48 private JarEntry first;
49 private JarVerifier jv;
50 private ManifestEntryVerifier mev;
51 private final boolean doVerify;
52 private boolean tryManifest;
53
54 /**
55 * Creates a new <code>JarInputStream</code> and reads the optional
56 * manifest. If a manifest is present, also attempts to verify
57 * the signatures if the JarInputStream is signed.
58 * @param in the actual input stream
59 * @throws IOException if an I/O error has occurred
60 */
61 public JarInputStream(InputStream in) throws IOException {
62 this(in, true);
63 }
64
65 /**
66 * Creates a new <code>JarInputStream</code> and reads the optional
67 * manifest. If a manifest is present and verify is true, also attempts
68 * to verify the signatures if the JarInputStream is signed.
69 *
70 * @param in the actual input stream
71 * @param verify whether or not to verify the JarInputStream if
72 * it is signed.
73 * @throws IOException if an I/O error has occurred
74 */
75 public JarInputStream(InputStream in, boolean verify) throws IOException {
76 super(in);
77 this.doVerify = verify;
78
79 // This implementation assumes the META-INF/MANIFEST.MF entry
80 // should be either the first or the second entry (when preceded
81 // by the dir META-INF/). It skips the META-INF/ and then
82 // "consumes" the MANIFEST.MF to initialize the Manifest object.
83 JarEntry e = (JarEntry)super.getNextEntry();
84 if (e != null && e.getName().equalsIgnoreCase("META-INF/"))
85 e = (JarEntry)super.getNextEntry();
86 first = checkManifest(e);
87 }
88
89 private JarEntry checkManifest(JarEntry e)
90 throws IOException
91 {
92 if (e != null && JarFile.MANIFEST_NAME.equalsIgnoreCase(e.getName())) {
93 man = new Manifest();
114 }
115 return baos.toByteArray();
116 }
117
118 /**
119 * Returns the <code>Manifest</code> for this JAR file, or
120 * <code>null</code> if none.
121 *
122 * @return the <code>Manifest</code> for this JAR file, or
123 * <code>null</code> if none.
124 */
125 public Manifest getManifest() {
126 return man;
127 }
128
129 /**
130 * Reads the next ZIP file entry and positions the stream at the
131 * beginning of the entry data. If verification has been enabled,
132 * any invalid signature detected while positioning the stream for
133 * the next entry will result in an exception.
134 * @throws ZipException if a ZIP file error has occurred
135 * @throws IOException if an I/O error has occurred
136 * @throws SecurityException if any of the jar file entries
137 * are incorrectly signed.
138 */
139 public ZipEntry getNextEntry() throws IOException {
140 JarEntry e;
141 if (first == null) {
142 e = (JarEntry)super.getNextEntry();
143 if (tryManifest) {
144 e = checkManifest(e);
145 tryManifest = false;
146 }
147 } else {
148 e = first;
149 if (first.getName().equalsIgnoreCase(JarIndex.INDEX_NAME))
150 tryManifest = true;
151 first = null;
152 }
153 if (jv != null && e != null) {
154 // At this point, we might have parsed all the meta-inf
155 // entries and have nothing to verify. If we have
156 // nothing to verify, get rid of the JarVerifier object.
157 if (jv.nothingToVerify() == true) {
158 jv = null;
159 mev = null;
160 } else {
161 jv.beginEntry(e, mev);
162 }
163 }
164 return e;
165 }
166
167 /**
168 * Reads the next JAR file entry and positions the stream at the
169 * beginning of the entry data. If verification has been enabled,
170 * any invalid signature detected while positioning the stream for
171 * the next entry will result in an exception.
172 * @return the next JAR file entry, or null if there are no more entries
173 * @throws ZipException if a ZIP file error has occurred
174 * @throws IOException if an I/O error has occurred
175 * @throws SecurityException if any of the jar file entries
176 * are incorrectly signed.
177 */
178 public JarEntry getNextJarEntry() throws IOException {
179 return (JarEntry)getNextEntry();
180 }
181
182 /**
183 * Reads from the current JAR file entry into an array of bytes.
184 * If <code>len</code> is not zero, the method
185 * blocks until some input is available; otherwise, no
186 * bytes are read and <code>0</code> is returned.
187 * If verification has been enabled, any invalid signature
188 * on the current entry will be reported at some point before the
189 * end of the entry is reached.
190 * @param b the buffer into which the data is read
191 * @param off the start offset in the destination array <code>b</code>
192 * @param len the maximum number of bytes to read
193 * @return the actual number of bytes read, or -1 if the end of the
194 * entry is reached
195 * @throws NullPointerException If <code>b</code> is <code>null</code>.
196 * @throws IndexOutOfBoundsException If <code>off</code> is negative,
197 * <code>len</code> is negative, or <code>len</code> is greater than
198 * <code>b.length - off</code>
199 * @throws ZipException if a ZIP file error has occurred
200 * @throws IOException if an I/O error has occurred
201 * @throws SecurityException if any of the jar file entries
202 * are incorrectly signed.
203 */
204 public int read(byte[] b, int off, int len) throws IOException {
205 int n;
206 if (first == null) {
207 n = super.read(b, off, len);
208 } else {
209 n = -1;
210 }
211 if (jv != null) {
212 jv.update(n, b, off, len, mev);
213 }
214 return n;
215 }
216
217 /**
218 * Creates a new <code>JarEntry</code> (<code>ZipEntry</code>) for the
219 * specified JAR file entry name. The manifest attributes of
220 * the specified JAR file entry name will be copied to the new
221 * <CODE>JarEntry</CODE>.
|