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