1. /*
  2. * @(#)JarInputStream.java 1.33 04/04/21
  3. *
  4. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package java.util.jar;
  8. import java.util.zip.*;
  9. import java.io.*;
  10. import sun.security.util.ManifestEntryVerifier;
  11. /**
  12. * The <code>JarInputStream</code> class is used to read the contents of
  13. * a JAR file from any input stream. It extends the class
  14. * <code>java.util.zip.ZipInputStream</code> with support for reading
  15. * an optional <code>Manifest</code> entry. The <code>Manifest</code>
  16. * can be used to store meta-information about the JAR file and its entries.
  17. *
  18. * @author David Connelly
  19. * @version 1.33, 04/21/04
  20. * @see Manifest
  21. * @see java.util.zip.ZipInputStream
  22. * @since 1.2
  23. */
  24. public
  25. class JarInputStream extends ZipInputStream {
  26. private Manifest man;
  27. private JarEntry first;
  28. private JarVerifier jv;
  29. private ManifestEntryVerifier mev;
  30. /**
  31. * Creates a new <code>JarInputStream</code> and reads the optional
  32. * manifest. If a manifest is present, also attempts to verify
  33. * the signatures if the JarInputStream is signed.
  34. * @param in the actual input stream
  35. * @exception IOException if an I/O error has occurred
  36. */
  37. public JarInputStream(InputStream in) throws IOException {
  38. this(in, true);
  39. }
  40. /**
  41. * Creates a new <code>JarInputStream</code> and reads the optional
  42. * manifest. If a manifest is present and verify is true, also attempts
  43. * to verify the signatures if the JarInputStream is signed.
  44. *
  45. * @param in the actual input stream
  46. * @param verify whether or not to verify the JarInputStream if
  47. * it is signed.
  48. * @exception IOException if an I/O error has occurred
  49. */
  50. public JarInputStream(InputStream in, boolean verify) throws IOException {
  51. super(in);
  52. JarEntry e = (JarEntry)super.getNextEntry();
  53. if (e != null && e.getName().equalsIgnoreCase("META-INF/"))
  54. e = (JarEntry)super.getNextEntry();
  55. if (e != null && JarFile.MANIFEST_NAME.equalsIgnoreCase(e.getName())) {
  56. man = new Manifest();
  57. byte bytes[] = getBytes(new BufferedInputStream(this));
  58. man.read(new ByteArrayInputStream(bytes));
  59. //man.read(new BufferedInputStream(this));
  60. closeEntry();
  61. if (verify) {
  62. jv = new JarVerifier(man, bytes);
  63. mev = new ManifestEntryVerifier(man);
  64. }
  65. first = getNextJarEntry();
  66. } else {
  67. first = e;
  68. }
  69. }
  70. private byte[] getBytes(InputStream is)
  71. throws IOException
  72. {
  73. byte[] buffer = new byte[8192];
  74. ByteArrayOutputStream baos = new ByteArrayOutputStream(2048);
  75. int n;
  76. baos.reset();
  77. while ((n = is.read(buffer, 0, buffer.length)) != -1) {
  78. baos.write(buffer, 0, n);
  79. }
  80. return baos.toByteArray();
  81. }
  82. /**
  83. * Returns the <code>Manifest</code> for this JAR file, or
  84. * <code>null</code> if none.
  85. *
  86. * @return the <code>Manifest</code> for this JAR file, or
  87. * <code>null</code> if none.
  88. */
  89. public Manifest getManifest() {
  90. return man;
  91. }
  92. /**
  93. * Reads the next ZIP file entry and positions the stream at the
  94. * beginning of the entry data. If verification has been enabled,
  95. * any invalid signature detected while positioning the stream for
  96. * the next entry will result in an exception.
  97. * @exception ZipException if a ZIP file error has occurred
  98. * @exception IOException if an I/O error has occurred
  99. * @exception SecurityException if any of the jar file entries
  100. * are incorrectly signed.
  101. */
  102. public ZipEntry getNextEntry() throws IOException {
  103. JarEntry e;
  104. if (first == null) {
  105. e = (JarEntry)super.getNextEntry();
  106. } else {
  107. e = first;
  108. first = null;
  109. }
  110. if (jv != null && e != null) {
  111. // At this point, we might have parsed all the meta-inf
  112. // entries and have nothing to verify. If we have
  113. // nothing to verify, get rid of the JarVerifier object.
  114. if (jv.nothingToVerify() == true) {
  115. jv = null;
  116. mev = null;
  117. } else {
  118. jv.beginEntry(e, mev);
  119. }
  120. }
  121. return e;
  122. }
  123. /**
  124. * Reads the next JAR file entry and positions the stream at the
  125. * beginning of the entry data. If verification has been enabled,
  126. * any invalid signature detected while positioning the stream for
  127. * the next entry will result in an exception.
  128. * @return the next JAR file entry, or null if there are no more entries
  129. * @exception ZipException if a ZIP file error has occurred
  130. * @exception IOException if an I/O error has occurred
  131. * @exception SecurityException if any of the jar file entries
  132. * are incorrectly signed.
  133. */
  134. public JarEntry getNextJarEntry() throws IOException {
  135. return (JarEntry)getNextEntry();
  136. }
  137. /**
  138. * Reads from the current JAR file entry into an array of bytes.
  139. * Blocks until some input is available.
  140. * If verification has been enabled, any invalid signature
  141. * on the current entry will be reported at some point before the
  142. * end of the entry is reached.
  143. * @param b the buffer into which the data is read
  144. * @param off the start offset of the data
  145. * @param len the maximum number of bytes to read
  146. * @return the actual number of bytes read, or -1 if the end of the
  147. * entry is reached
  148. * @exception ZipException if a ZIP file error has occurred
  149. * @exception IOException if an I/O error has occurred
  150. * @exception SecurityException if any of the jar file entries
  151. * are incorrectly signed.
  152. */
  153. public int read(byte[] b, int off, int len) throws IOException {
  154. int n;
  155. if (first == null) {
  156. n = super.read(b, off, len);
  157. } else {
  158. n = -1;
  159. }
  160. if (jv != null) {
  161. jv.update(n, b, off, len, mev);
  162. }
  163. return n;
  164. }
  165. /**
  166. * Creates a new <code>JarEntry</code> (<code>ZipEntry</code>) for the
  167. * specified JAR file entry name. The manifest attributes of
  168. * the specified JAR file entry name will be copied to the new
  169. * <CODE>JarEntry</CODE>.
  170. *
  171. * @param name the name of the JAR/ZIP file entry
  172. * @return the <code>JarEntry</code> object just created
  173. */
  174. protected ZipEntry createZipEntry(String name) {
  175. JarEntry e = new JarEntry(name);
  176. if (man != null) {
  177. e.attr = man.getAttributes(name);
  178. }
  179. return e;
  180. }
  181. }