001: /*
002: * @(#)JarInputStream.java 1.32 06/10/10
003: *
004: * Copyright 1990-2006 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: *
026: */
027:
028: package java.util.jar;
029:
030: import java.util.zip.*;
031: import java.io.*;
032: import sun.security.util.ManifestEntryVerifier;
033:
034: /**
035: * The <code>JarInputStream</code> class is used to read the contents of
036: * a JAR file from any input stream. It extends the class
037: * <code>java.util.zip.ZipInputStream</code> with support for reading
038: * an optional <code>Manifest</code> entry. The <code>Manifest</code>
039: * can be used to store meta-information about the JAR file and its entries.
040: *
041: * @author David Connelly
042: * @version 1.25, 02/02/00
043: * @see Manifest
044: * @see java.util.zip.ZipInputStream
045: * @since 1.2
046: */
047: public class JarInputStream extends ZipInputStream {
048: private Manifest man;
049: private JarEntry first;
050: private JarVerifier jv;
051: private ManifestEntryVerifier mev;
052:
053: /**
054: * Creates a new <code>JarInputStream</code> and reads the optional
055: * manifest. If a manifest is present, also attempts to verify
056: * the signatures if the JarInputStream is signed.
057: * @param in the actual input stream
058: * @exception IOException if an I/O error has occurred
059: */
060: public JarInputStream(InputStream in) throws IOException {
061: this (in, true);
062: }
063:
064: /**
065: * Creates a new <code>JarInputStream</code> and reads the optional
066: * manifest. If a manifest is present and verify is true, also attempts
067: * to verify the signatures if the JarInputStream is signed.
068: *
069: * @param in the actual input stream
070: * @param verify whether or not to verify the JarInputStream if
071: * it is signed.
072: * @exception IOException if an I/O error has occurred
073: */
074: public JarInputStream(InputStream in, boolean verify)
075: throws IOException {
076: super (in);
077: JarEntry e = (JarEntry) super .getNextEntry();
078:
079: if (e != null && e.getName().equalsIgnoreCase("META-INF/"))
080: e = (JarEntry) super .getNextEntry();
081:
082: if (e != null
083: && JarFile.MANIFEST_NAME.equalsIgnoreCase(e.getName())) {
084: man = new Manifest();
085: byte bytes[] = getBytes(new BufferedInputStream(this ));
086: man.read(new ByteArrayInputStream(bytes));
087: //man.read(new BufferedInputStream(this));
088: closeEntry();
089: if (verify) {
090: jv = new JarVerifier(man, bytes);
091: mev = new ManifestEntryVerifier(man);
092: }
093: first = getNextJarEntry();
094: } else {
095: first = e;
096: }
097: }
098:
099: private byte[] getBytes(InputStream is) throws IOException {
100: byte[] buffer = new byte[8192];
101: ByteArrayOutputStream baos = new ByteArrayOutputStream(2048);
102:
103: int n;
104:
105: baos.reset();
106: while ((n = is.read(buffer, 0, buffer.length)) != -1) {
107: baos.write(buffer, 0, n);
108: }
109: return baos.toByteArray();
110: }
111:
112: /**
113: * Returns the <code>Manifest</code> for this JAR file, or
114: * <code>null</code> if none.
115: *
116: * @return the <code>Manifest</code> for this JAR file, or
117: * <code>null</code> if none.
118: */
119: public Manifest getManifest() {
120: return man;
121: }
122:
123: /**
124: * Reads the next ZIP file entry and positions stream at the beginning
125: * of the entry data.
126: * @exception ZipException if a ZIP file error has occurred
127: * @exception IOException if an I/O error has occurred
128: */
129: public ZipEntry getNextEntry() throws IOException {
130: JarEntry e;
131: if (first == null) {
132: e = (JarEntry) super .getNextEntry();
133: } else {
134: e = first;
135: first = null;
136: }
137: if (jv != null && e != null) {
138: // At this point, we might have parsed all the meta-inf
139: // entries and have nothing to verify. If we have
140: // nothing to verify, get rid of the JarVerifier object.
141: if (jv.nothingToVerify() == true) {
142: jv = null;
143: mev = null;
144: } else {
145: jv.beginEntry(e, mev);
146: }
147: }
148: return e;
149: }
150:
151: /**
152: * Reads the next JAR file entry and positions the stream at the
153: * beginning of the entry data.
154: *
155: * @return the next JAR file entry
156: * @exception ZipException if a ZIP file error has occurred
157: * @exception IOException if an I/O error has occurred
158: */
159: public JarEntry getNextJarEntry() throws IOException {
160: return (JarEntry) getNextEntry();
161: }
162:
163: /**
164: * Reads from the current JAR file entry into an array of bytes.
165: * Blocks until some input is available.
166: * @param b the buffer into which the data is read
167: * @param off the start offset of the data
168: * @param len the maximum number of bytes to read
169: * @return the actual number of bytes read, or -1 if the end of the
170: * entry is reached
171: * @exception ZipException if a ZIP file error has occurred
172: * @exception IOException if an I/O error has occurred
173: */
174: public int read(byte[] b, int off, int len) throws IOException {
175: int n;
176: if (first == null) {
177: n = super .read(b, off, len);
178: } else {
179: n = -1;
180: }
181: if (jv != null) {
182: jv.update(n, b, off, len, mev);
183: }
184: return n;
185: }
186:
187: /**
188: * Creates a new <code>JarEntry</code> (<code>ZipEntry</code>) for the
189: * specified JAR file entry name.
190: *
191: * @param name the name of the JAR/ZIP file entry
192: * @return the <code>JarEntry</code> object just created
193: */
194: protected ZipEntry createZipEntry(String name) {
195: JarEntry e = new JarEntry(name);
196: if (man != null) {
197: e.attr = man.getAttributes(name);
198: }
199: return e;
200: }
201: }
|