--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/util/jar/JarInputStream.java Sat Dec 01 00:00:00 2007 +0000
@@ -0,0 +1,220 @@
+/*
+ * Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.util.jar;
+
+import java.util.zip.*;
+import java.io.*;
+import sun.security.util.ManifestEntryVerifier;
+
+/**
+ * The <code>JarInputStream</code> class is used to read the contents of
+ * a JAR file from any input stream. It extends the class
+ * <code>java.util.zip.ZipInputStream</code> with support for reading
+ * an optional <code>Manifest</code> entry. The <code>Manifest</code>
+ * can be used to store meta-information about the JAR file and its entries.
+ *
+ * @author David Connelly
+ * @see Manifest
+ * @see java.util.zip.ZipInputStream
+ * @since 1.2
+ */
+public
+class JarInputStream extends ZipInputStream {
+ private Manifest man;
+ private JarEntry first;
+ private JarVerifier jv;
+ private ManifestEntryVerifier mev;
+
+
+ /**
+ * Creates a new <code>JarInputStream</code> and reads the optional
+ * manifest. If a manifest is present, also attempts to verify
+ * the signatures if the JarInputStream is signed.
+ * @param in the actual input stream
+ * @exception IOException if an I/O error has occurred
+ */
+ public JarInputStream(InputStream in) throws IOException {
+ this(in, true);
+ }
+
+ /**
+ * Creates a new <code>JarInputStream</code> and reads the optional
+ * manifest. If a manifest is present and verify is true, also attempts
+ * to verify the signatures if the JarInputStream is signed.
+ *
+ * @param in the actual input stream
+ * @param verify whether or not to verify the JarInputStream if
+ * it is signed.
+ * @exception IOException if an I/O error has occurred
+ */
+ public JarInputStream(InputStream in, boolean verify) throws IOException {
+ super(in);
+ JarEntry e = (JarEntry)super.getNextEntry();
+
+ if (e != null && e.getName().equalsIgnoreCase("META-INF/"))
+ e = (JarEntry)super.getNextEntry();
+
+ if (e != null && JarFile.MANIFEST_NAME.equalsIgnoreCase(e.getName())) {
+ man = new Manifest();
+ byte bytes[] = getBytes(new BufferedInputStream(this));
+ man.read(new ByteArrayInputStream(bytes));
+ //man.read(new BufferedInputStream(this));
+ closeEntry();
+ if (verify) {
+ jv = new JarVerifier(bytes);
+ mev = new ManifestEntryVerifier(man);
+ }
+ first = getNextJarEntry();
+ } else {
+ first = e;
+ }
+ }
+
+ private byte[] getBytes(InputStream is)
+ throws IOException
+ {
+ byte[] buffer = new byte[8192];
+ ByteArrayOutputStream baos = new ByteArrayOutputStream(2048);
+
+ int n;
+
+ baos.reset();
+ while ((n = is.read(buffer, 0, buffer.length)) != -1) {
+ baos.write(buffer, 0, n);
+ }
+ return baos.toByteArray();
+ }
+
+ /**
+ * Returns the <code>Manifest</code> for this JAR file, or
+ * <code>null</code> if none.
+ *
+ * @return the <code>Manifest</code> for this JAR file, or
+ * <code>null</code> if none.
+ */
+ public Manifest getManifest() {
+ return man;
+ }
+
+ /**
+ * Reads the next ZIP file entry and positions the stream at the
+ * beginning of the entry data. If verification has been enabled,
+ * any invalid signature detected while positioning the stream for
+ * the next entry will result in an exception.
+ * @exception ZipException if a ZIP file error has occurred
+ * @exception IOException if an I/O error has occurred
+ * @exception SecurityException if any of the jar file entries
+ * are incorrectly signed.
+ */
+ public ZipEntry getNextEntry() throws IOException {
+ JarEntry e;
+ if (first == null) {
+ e = (JarEntry)super.getNextEntry();
+ } else {
+ e = first;
+ first = null;
+ }
+ if (jv != null && e != null) {
+ // At this point, we might have parsed all the meta-inf
+ // entries and have nothing to verify. If we have
+ // nothing to verify, get rid of the JarVerifier object.
+ if (jv.nothingToVerify() == true) {
+ jv = null;
+ mev = null;
+ } else {
+ jv.beginEntry(e, mev);
+ }
+ }
+ return e;
+ }
+
+ /**
+ * Reads the next JAR file entry and positions the stream at the
+ * beginning of the entry data. If verification has been enabled,
+ * any invalid signature detected while positioning the stream for
+ * the next entry will result in an exception.
+ * @return the next JAR file entry, or null if there are no more entries
+ * @exception ZipException if a ZIP file error has occurred
+ * @exception IOException if an I/O error has occurred
+ * @exception SecurityException if any of the jar file entries
+ * are incorrectly signed.
+ */
+ public JarEntry getNextJarEntry() throws IOException {
+ return (JarEntry)getNextEntry();
+ }
+
+ /**
+ * Reads from the current JAR file entry into an array of bytes.
+ * If <code>len</code> is not zero, the method
+ * blocks until some input is available; otherwise, no
+ * bytes are read and <code>0</code> is returned.
+ * If verification has been enabled, any invalid signature
+ * on the current entry will be reported at some point before the
+ * end of the entry is reached.
+ * @param b the buffer into which the data is read
+ * @param off the start offset in the destination array <code>b</code>
+ * @param len the maximum number of bytes to read
+ * @return the actual number of bytes read, or -1 if the end of the
+ * entry is reached
+ * @exception NullPointerException If <code>b</code> is <code>null</code>.
+ * @exception IndexOutOfBoundsException If <code>off</code> is negative,
+ * <code>len</code> is negative, or <code>len</code> is greater than
+ * <code>b.length - off</code>
+ * @exception ZipException if a ZIP file error has occurred
+ * @exception IOException if an I/O error has occurred
+ * @exception SecurityException if any of the jar file entries
+ * are incorrectly signed.
+ */
+ public int read(byte[] b, int off, int len) throws IOException {
+ int n;
+ if (first == null) {
+ n = super.read(b, off, len);
+ } else {
+ n = -1;
+ }
+ if (jv != null) {
+ jv.update(n, b, off, len, mev);
+ }
+ return n;
+ }
+
+ /**
+ * Creates a new <code>JarEntry</code> (<code>ZipEntry</code>) for the
+ * specified JAR file entry name. The manifest attributes of
+ * the specified JAR file entry name will be copied to the new
+ * <CODE>JarEntry</CODE>.
+ *
+ * @param name the name of the JAR/ZIP file entry
+ * @return the <code>JarEntry</code> object just created
+ */
+ protected ZipEntry createZipEntry(String name) {
+ JarEntry e = new JarEntry(name);
+ if (man != null) {
+ e.attr = man.getAttributes(name);
+ }
+ return e;
+ }
+}