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