KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > proguard > io > JarWriter


1 /*
2  * ProGuard -- shrinking, optimization, obfuscation, and preverification
3  * of Java bytecode.
4  *
5  * Copyright (c) 2002-2007 Eric Lafortune (eric@graphics.cornell.edu)
6  *
7  * This program is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License as published by the Free
9  * Software Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * This program is distributed in the hope that it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15  * more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with this program; if not, write to the Free Software Foundation, Inc.,
19  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20  */

21 package proguard.io;
22
23 import java.io.*;
24 import java.util.jar.*;
25 import java.util.*;
26 import java.util.zip.*;
27
28
29 /**
30  * This DataEntryWriter sends data entries to a given jar/zip file.
31  * The manifest and comment properties can optionally be set.
32  *
33  * @author Eric Lafortune
34  */

35 public class JarWriter implements DataEntryWriter, Finisher
36 {
37     private DataEntryWriter dataEntryWriter;
38     private Manifest manifest;
39     private String JavaDoc comment;
40
41     private OutputStream currentParentOutputStream;
42     private ZipOutputStream currentJarOutputStream;
43     private Finisher currentFinisher;
44     private String JavaDoc currentEntryName;
45
46     // The names of the jar entries that are already in the jar.
47
private Set jarEntryNames = new HashSet();
48
49
50     /**
51      * Creates a new JarWriter without manifest or comment.
52      */

53     public JarWriter(DataEntryWriter dataEntryWriter)
54     {
55         this(dataEntryWriter, null, null);
56     }
57
58
59     /**
60      * Creates a new JarWriter.
61      */

62     public JarWriter(DataEntryWriter dataEntryWriter,
63                      Manifest manifest,
64                      String JavaDoc comment)
65     {
66         this.dataEntryWriter = dataEntryWriter;
67         this.manifest = manifest;
68         this.comment = comment;
69     }
70
71
72     // Implementations for DataEntryWriter.
73

74     public OutputStream getOutputStream(DataEntry dataEntry) throws IOException
75     {
76         return getOutputStream(dataEntry, null);
77     }
78
79
80     public OutputStream getOutputStream(DataEntry dataEntry,
81                                         Finisher finisher) throws IOException
82     {
83         // Get the parent stream, new or exisiting.
84
// This may finish our own jar output stream.
85
OutputStream parentOutputStream =
86             dataEntryWriter.getOutputStream(dataEntry.getParent(), this);
87
88         // Did we get a stream?
89
if (parentOutputStream == null)
90         {
91             return null;
92         }
93
94         // Do we need a new stream?
95
if (currentParentOutputStream == null)
96         {
97             currentParentOutputStream = parentOutputStream;
98
99             // Create a new jar stream, with a manifest, if set.
100
currentJarOutputStream = manifest != null ?
101                 new JarOutputStream(parentOutputStream, manifest) :
102                 new ZipOutputStream(parentOutputStream);
103
104             // Add a comment, if set.
105
if (comment != null)
106             {
107                 currentJarOutputStream.setComment(comment);
108             }
109         }
110
111         // Get the entry name.
112
String JavaDoc name = dataEntry.getName();
113
114         // Do we need a new entry?
115
if (!name.equals(currentEntryName))
116         {
117             // Close the previous ZIP entry, if any.
118
closeEntry();
119
120             // We have to check if the name is already used, because ZipOutputStream
121
// doesn't handle this case properly (it throws an exception which can
122
// be caught, but the ZipDataEntry is remembered anyway).
123
if (!jarEntryNames.add(name))
124             {
125                 throw new IOException("Duplicate zip entry ["+dataEntry+"]");
126             }
127
128             // Create a new entry.
129
currentJarOutputStream.putNextEntry(new ZipEntry(name));
130
131             currentFinisher = finisher;
132             currentEntryName = name;
133         }
134
135         return currentJarOutputStream;
136     }
137
138
139     public void finish() throws IOException
140     {
141         // Finish the entire ZIP stream, if any.
142
if (currentJarOutputStream != null)
143         {
144             // Close the previous ZIP entry, if any.
145
closeEntry();
146
147             // Finish the entire ZIP stream.
148
currentJarOutputStream.finish();
149             currentJarOutputStream = null;
150             currentParentOutputStream = null;
151             jarEntryNames.clear();
152         }
153     }
154
155
156     public void close() throws IOException
157     {
158         // Close the parent stream.
159
dataEntryWriter.close();
160     }
161
162
163     // Small utility methods.
164

165     /**
166      * Closes the previous ZIP entry, if any.
167      */

168     private void closeEntry() throws IOException
169     {
170         if (currentEntryName != null)
171         {
172             // Let any finisher finish up first.
173
if (currentFinisher != null)
174             {
175                 currentFinisher.finish();
176                 currentFinisher = null;
177             }
178
179             currentJarOutputStream.closeEntry();
180             currentEntryName = null;
181         }
182     }
183 }
184
Popular Tags