KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > izforge > izpack > util > JarOutputStream


1 /*
2  * $Id: JarOutputStream.java 1708 2007-01-13 18:31:26Z jponge $
3  * IzPack - Copyright 2001-2007 Julien Ponge, All Rights Reserved.
4  *
5  * http://www.izforge.com/izpack/
6  * http://developer.berlios.de/projects/izpack/
7  *
8  * Copyright 2005 Klaus Bartz
9  *
10  * Licensed under the Apache License, Version 2.0 (the "License");
11  * you may not use this file except in compliance with the License.
12  * You may obtain a copy of the License at
13  *
14  * http://www.apache.org/licenses/LICENSE-2.0
15  *
16  * Unless required by applicable law or agreed to in writing, software
17  * distributed under the License is distributed on an "AS IS" BASIS,
18  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19  * See the License for the specific language governing permissions and
20  * limitations under the License.
21  */

22
23 package com.izforge.izpack.util;
24
25 import java.io.BufferedOutputStream JavaDoc;
26 import java.io.File JavaDoc;
27 import java.io.IOException JavaDoc;
28 import java.io.OutputStream JavaDoc;
29 import java.util.jar.JarFile JavaDoc;
30 import java.util.jar.Manifest JavaDoc;
31 //import java.util.zip.ZipException;
32

33 //The declarations for ZipOutputStreams will be done
34
//as full qualified to clear at the use point that
35
//we do not use the standard class else the extended
36
//from apache.
37
//import org.apache.tools.zip.ZipOutputStream;
38
//import org.apache.tools.zip.ZipEntry;
39

40 /**
41  * IzPack will be able to support different compression methods for the
42  * packs included in the installation jar file.
43  * For this a jar output stream will be needed with which the info
44  * data (size, CRC) can be written after the compressed data.
45  * This is not possible with the standard class
46  * java.util.jar.JarOutputStream. Therefore we create an own class
47  * which supports it. Really the hole work will be delegated to the
48  * ZipOutputStream from the apache team which solves the problem.
49  *
50  * @author Klaus Bartz
51  */

52 public class JarOutputStream extends org.apache.tools.zip.ZipOutputStream
53 {
54     private static final int JAR_MAGIC = 0xCAFE;
55     private boolean firstEntry = true;
56     private boolean preventClose = false;
57
58     /**
59      * Creates a new <code>JarOutputStream</code> with no manifest.
60      * Using this constructor it will be NOT possible to write
61      * data with compression format STORED to the stream without
62      * declare the info data (size, CRC) at <code>putNextEntry</code>.
63      * @param out the actual output stream
64      * @exception IOException if an I/O error has occurred
65      */

66     public JarOutputStream(OutputStream JavaDoc out) throws IOException JavaDoc
67     {
68         super(out);
69     }
70
71     /**
72      * Creates a new <code>JarOutputStream</code> with the specified
73      * <code>Manifest</code>. The manifest is written as the first
74      * entry to the output stream which will be created from the
75      * file argument.
76      *
77      * @param fout the file object with which the output stream
78      * should be created
79      * @param man the <code>Manifest</code>
80      * @exception IOException if an I/O error has occurred
81      */

82     public JarOutputStream(File JavaDoc fout, Manifest JavaDoc man) throws IOException JavaDoc
83     {
84         super( fout );
85         if (man == null)
86         {
87             throw new NullPointerException JavaDoc("man");
88         }
89         org.apache.tools.zip.ZipEntry e =
90             new org.apache.tools.zip.ZipEntry(JarFile.MANIFEST_NAME);
91         putNextEntry(e);
92         man.write(new BufferedOutputStream JavaDoc(this));
93         closeEntry();
94     }
95     /**
96      * Creates a new <code>JarOutputStream</code> with no manifest.
97      * Will use random access if possible.
98      * @param arg0 the file object with which the output stream
99      * should be created
100      * @throws java.io.IOException
101      */

102     public JarOutputStream(File JavaDoc arg0) throws IOException JavaDoc
103     {
104         super(arg0);
105     }
106     /**
107      * Begins writing a new JAR file entry and positions the stream
108      * to the start of the entry data. This method will also close
109      * any previous entry. The default compression method will be
110      * used if no compression method was specified for the entry.
111      * The current time will be used if the entry has no set modification
112      * time.
113      *
114      * @param ze the ZIP/JAR entry to be written
115      * @exception java.util.zip.ZipException if a ZIP error has occurred
116      * @exception IOException if an I/O error has occurred
117      */

118     public void putNextEntry(org.apache.tools.zip.ZipEntry ze) throws IOException JavaDoc
119     {
120         if (firstEntry)
121         {
122             // Make sure that extra field data for first JAR
123
// entry includes JAR magic number id.
124
byte[] edata = ze.getExtra();
125             if (edata != null && !hasMagic(edata))
126             {
127                 // Prepend magic to existing extra data
128
byte[] tmp = new byte[edata.length + 4];
129                 System.arraycopy(tmp, 4, edata, 0, edata.length);
130                 edata = tmp;
131             }
132             else
133             {
134                 edata = new byte[4];
135             }
136             set16(edata, 0, JAR_MAGIC); // extra field id
137
set16(edata, 2, 0); // extra field size
138
ze.setExtra(edata);
139             firstEntry = false;
140         }
141         super.putNextEntry(ze);
142     }
143
144     /**
145      * @return Returns the preventClose.
146      */

147     public boolean isPreventClose()
148     {
149         return preventClose;
150     }
151     /**
152      * Determine whether a call of the close method
153      * will be performed or not. This is a hack for
154      * FilterOutputStreams like the CBZip2OutputStream
155      * of apache which calls close of the slave via
156      * the final method which will be called from
157      * the garbage collector.
158      * @param preventClose The preventClose to set.
159      */

160     public void setPreventClose(boolean preventClose)
161     {
162         this.preventClose = preventClose;
163     }
164
165     /**
166      * Closes this output stream and releases any system resources
167      * associated with the stream if isPreventClose is not true.
168      * Else nothing will be done. This is a hack for
169      * FilterOutputStreams like the CBZip2OutputStream which
170      * calls the close method of the slave at finalizing the class
171      * may be triggert by the GC.
172      *
173      * @exception IOException if an I/O error occurs.
174      */

175     public void close() throws IOException JavaDoc
176     {
177         if( ! isPreventClose() )
178             super.close();
179     }
180
181     /**
182      * Closes this output stream and releases any system resources
183      * associated with the stream also isPreventClose is true.
184      * This is a hack for FilterOutputStreams like the CBZip2OutputStream which
185      * calls the close method of the slave at finalizing the class
186      * may be triggert by the GC.
187      *
188      * @exception IOException if an I/O error occurs.
189      */

190     public void closeAlways() throws IOException JavaDoc
191     {
192         setPreventClose( false );
193         close();
194     }
195
196     /*
197      * Returns true if specified byte array contains the
198      * jar magic extra field id.
199      */

200     private static boolean hasMagic(byte[] edata)
201     {
202          
203         try
204         {
205             int i = 0;
206             while (i < edata.length)
207             {
208                 if (get16(edata, i) == JAR_MAGIC)
209                 {
210                     return true;
211                 }
212                 i += get16(edata, i + 2) + 4;
213             }
214         }
215         catch (ArrayIndexOutOfBoundsException JavaDoc e)
216         {
217             // Invalid extra field data
218
}
219         return false;
220     }
221
222     /*
223      * Fetches unsigned 16-bit value from byte array at specified offset.
224      * The bytes are assumed to be in Intel (little-endian) byte order.
225      */

226     private static int get16(byte[] b, int off)
227     {
228         return (b[off] & 0xff) | ((b[off+1] & 0xff) << 8);
229     }
230
231     /*
232      * Sets 16-bit value at specified offset. The bytes are assumed to
233      * be in Intel (little-endian) byte order.
234      */

235     private static void set16(byte[] b, int off, int value)
236     {
237         b[off] = (byte)value;
238         b[off+1] = (byte)(value >> 8);
239     }
240
241 }
242
Popular Tags