1. /*
  2. * @(#)JarInputStream.java 1.21 01/11/29
  3. *
  4. * Copyright 2002 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.21, 11/29/01
  20. * @see Manifest
  21. * @see java.util.zip.ZipInputStream
  22. * @since JDK1.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. public Manifest getManifest() {
  87. return man;
  88. }
  89. /**
  90. * Reads the next ZIP file entry and positions stream at the beginning
  91. * of the entry data.
  92. * @exception ZipException if a ZIP file error has occurred
  93. * @exception IOException if an I/O error has occurred
  94. */
  95. public ZipEntry getNextEntry() throws IOException {
  96. JarEntry e;
  97. if (first == null) {
  98. e = (JarEntry)super.getNextEntry();
  99. } else {
  100. e = first;
  101. first = null;
  102. }
  103. if (jv != null && e != null) {
  104. // At this point, we might have parsed all the meta-inf
  105. // entries and have nothing to verify. If we have
  106. // nothing to verify, get rid of the JarVerifier object.
  107. if (jv.nothingToVerify() == true) {
  108. jv = null;
  109. mev = null;
  110. } else {
  111. jv.beginEntry(e, mev);
  112. }
  113. }
  114. return e;
  115. }
  116. /**
  117. * Reads the next JAR file entry and positions the stream at the
  118. * beginning of the entry data.
  119. * @exception ZipException if a ZIP file error has occurred
  120. * @exception IOException if an I/O error has occurred
  121. */
  122. public JarEntry getNextJarEntry() throws IOException {
  123. return (JarEntry)getNextEntry();
  124. }
  125. /**
  126. * Reads from the current JAR file entry into an array of bytes.
  127. * Blocks until some input is available.
  128. * @param b the buffer into which the data is read
  129. * @param off the start offset of the data
  130. * @param len the maximum number of bytes to read
  131. * @return the actual number of bytes read, or -1 if the end of the
  132. * entry is reached
  133. * @exception ZipException if a ZIP file error has occurred
  134. * @exception IOException if an I/O error has occurred
  135. */
  136. public int read(byte[] b, int off, int len) throws IOException {
  137. int n;
  138. if (first == null) {
  139. n = super.read(b, off, len);
  140. } else {
  141. n = -1;
  142. }
  143. if (jv != null) {
  144. jv.update(n, b, off, len, mev);
  145. }
  146. return n;
  147. }
  148. /**
  149. * Creates a new <code>JarEntry</code> (<code>ZipEntry</code>) for the
  150. * specified JAR file entry name.
  151. *
  152. * @param name the name of the JAR/ZIP file entry
  153. */
  154. protected ZipEntry createZipEntry(String name) {
  155. JarEntry e = new JarEntry(name);
  156. if (man != null) {
  157. e.attr = man.getAttributes(name);
  158. }
  159. return e;
  160. }
  161. }