diff -r fd16c54261b3 -r 90ce3da70b43 jdk/src/share/classes/java/util/jar/JarInputStream.java --- /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 JarInputStream class is used to read the contents of + * a JAR file from any input stream. It extends the class + * java.util.zip.ZipInputStream with support for reading + * an optional Manifest entry. The Manifest + * 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 JarInputStream 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 JarInputStream 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 Manifest for this JAR file, or + * null if none. + * + * @return the Manifest for this JAR file, or + * null 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 len is not zero, the method + * blocks until some input is available; otherwise, no + * bytes are read and 0 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 b + * @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 b is null. + * @exception IndexOutOfBoundsException If off is negative, + * len is negative, or len is greater than + * b.length - off + * @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 JarEntry (ZipEntry) for the + * specified JAR file entry name. The manifest attributes of + * the specified JAR file entry name will be copied to the new + * JarEntry. + * + * @param name the name of the JAR/ZIP file entry + * @return the JarEntry object just created + */ + protected ZipEntry createZipEntry(String name) { + JarEntry e = new JarEntry(name); + if (man != null) { + e.attr = man.getAttributes(name); + } + return e; + } +}