KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > java > util > jar > JarOutputStream


1 /*
2  * @(#)JarOutputStream.java 1.22 03/12/19
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package java.util.jar;
9
10 import java.util.zip.*;
11 import java.io.*;
12
13 /**
14  * The <code>JarOutputStream</code> class is used to write the contents
15  * of a JAR file to any output stream. It extends the class
16  * <code>java.util.zip.ZipOutputStream</code> with support
17  * for writing an optional <code>Manifest</code> entry. The
18  * <code>Manifest</code> can be used to specify meta-information about
19  * the JAR file and its entries.
20  *
21  * @author David Connelly
22  * @version 1.22, 12/19/03
23  * @see Manifest
24  * @see java.util.zip.ZipOutputStream
25  * @since 1.2
26  */

27 public
28 class JarOutputStream extends ZipOutputStream {
29     private static final int JAR_MAGIC = 0xCAFE;
30
31     /**
32      * Creates a new <code>JarOutputStream</code> with the specified
33      * <code>Manifest</code>. The manifest is written as the first
34      * entry to the output stream.
35      *
36      * @param out the actual output stream
37      * @param man the optional <code>Manifest</code>
38      * @exception IOException if an I/O error has occurred
39      */

40     public JarOutputStream(OutputStream out, Manifest JavaDoc man) throws IOException {
41     super(out);
42     if (man == null) {
43         throw new NullPointerException JavaDoc("man");
44     }
45     ZipEntry e = new ZipEntry(JarFile.MANIFEST_NAME);
46     putNextEntry(e);
47     man.write(new BufferedOutputStream(this));
48     closeEntry();
49     }
50
51     /**
52      * Creates a new <code>JarOutputStream</code> with no manifest.
53      * @param out the actual output stream
54      * @exception IOException if an I/O error has occurred
55      */

56     public JarOutputStream(OutputStream out) throws IOException {
57     super(out);
58     }
59
60     /**
61      * Begins writing a new JAR file entry and positions the stream
62      * to the start of the entry data. This method will also close
63      * any previous entry. The default compression method will be
64      * used if no compression method was specified for the entry.
65      * The current time will be used if the entry has no set modification
66      * time.
67      *
68      * @param ze the ZIP/JAR entry to be written
69      * @exception ZipException if a ZIP error has occurred
70      * @exception IOException if an I/O error has occurred
71      */

72     public void putNextEntry(ZipEntry ze) throws IOException {
73     if (firstEntry) {
74         // Make sure that extra field data for first JAR
75
// entry includes JAR magic number id.
76
byte[] edata = ze.getExtra();
77         if (edata != null && !hasMagic(edata)) {
78         // Prepend magic to existing extra data
79
byte[] tmp = new byte[edata.length + 4];
80         System.arraycopy(tmp, 4, edata, 0, edata.length);
81         edata = tmp;
82         } else {
83         edata = new byte[4];
84         }
85         set16(edata, 0, JAR_MAGIC); // extra field id
86
set16(edata, 2, 0); // extra field size
87
ze.setExtra(edata);
88         firstEntry = false;
89     }
90     super.putNextEntry(ze);
91     }
92
93     private boolean firstEntry = true;
94
95     /*
96      * Returns true if specified byte array contains the
97      * jar magic extra field id.
98      */

99     private static boolean hasMagic(byte[] edata) {
100     try {
101         int i = 0;
102         while (i < edata.length) {
103         if (get16(edata, i) == JAR_MAGIC) {
104             return true;
105         }
106         i += get16(edata, i + 2) + 4;
107         }
108     } catch (ArrayIndexOutOfBoundsException JavaDoc e) {
109         // Invalid extra field data
110
}
111     return false;
112     }
113
114     /*
115      * Fetches unsigned 16-bit value from byte array at specified offset.
116      * The bytes are assumed to be in Intel (little-endian) byte order.
117      */

118     private static int get16(byte[] b, int off) {
119     return (b[off] & 0xff) | ((b[off+1] & 0xff) << 8);
120     }
121
122     /*
123      * Sets 16-bit value at specified offset. The bytes are assumed to
124      * be in Intel (little-endian) byte order.
125      */

126     private static void set16(byte[] b, int off, int value) {
127     b[off+0] = (byte)value;
128     b[off+1] = (byte)(value >> 8);
129     }
130 }
131
Popular Tags