1 /* |
1 /* |
2 * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. |
2 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 * |
4 * |
5 * This code is free software; you can redistribute it and/or modify it |
5 * This code is free software; you can redistribute it and/or modify it |
6 * under the terms of the GNU General Public License version 2 only, as |
6 * under the terms of the GNU General Public License version 2 only, as |
7 * published by the Free Software Foundation. Oracle designates this |
7 * published by the Free Software Foundation. Oracle designates this |
28 import java.util.*; |
28 import java.util.*; |
29 import java.util.jar.*; |
29 import java.util.jar.*; |
30 import java.util.zip.*; |
30 import java.util.zip.*; |
31 import java.io.*; |
31 import java.io.*; |
32 import java.beans.PropertyChangeListener; |
32 import java.beans.PropertyChangeListener; |
33 import java.beans.PropertyChangeEvent; |
|
34 |
33 |
35 /* |
34 /* |
36 * Implementation of the Pack provider. |
35 * Implementation of the Pack provider. |
37 * </pre></blockquote> |
36 * </pre></blockquote> |
38 * @author John Rose |
37 * @author John Rose |
39 * @author Kumar Srinivasan |
38 * @author Kumar Srinivasan |
40 */ |
39 */ |
41 |
40 |
42 |
41 |
43 public class UnpackerImpl implements Pack200.Unpacker { |
42 public class UnpackerImpl extends TLGlobals implements Pack200.Unpacker { |
44 |
43 |
45 |
44 |
46 /** |
45 /** |
47 * Register a listener for changes to options. |
46 * Register a listener for changes to options. |
48 * @param listener An object to be invoked when a property is changed. |
47 * @param listener An object to be invoked when a property is changed. |
49 */ |
48 */ |
50 public void addPropertyChangeListener(PropertyChangeListener listener) { |
49 public void addPropertyChangeListener(PropertyChangeListener listener) { |
51 _props.addListener(listener); |
50 props.addListener(listener); |
52 } |
51 } |
53 |
52 |
54 |
53 |
55 /** |
54 /** |
56 * Remove a listener for the PropertyChange event. |
55 * Remove a listener for the PropertyChange event. |
57 * @param listener The PropertyChange listener to be removed. |
56 * @param listener The PropertyChange listener to be removed. |
58 */ |
57 */ |
59 public void removePropertyChangeListener(PropertyChangeListener listener) { |
58 public void removePropertyChangeListener(PropertyChangeListener listener) { |
60 _props.removeListener(listener); |
59 props.removeListener(listener); |
61 } |
60 } |
62 |
61 |
63 public UnpackerImpl() { |
62 public UnpackerImpl() {} |
64 _props = new PropMap(); |
63 |
65 //_props.getProperty() consults defaultProps invisibly. |
|
66 //_props.putAll(defaultProps); |
|
67 } |
|
68 |
|
69 // Private stuff. |
|
70 final PropMap _props; |
|
71 |
64 |
72 |
65 |
73 /** |
66 /** |
74 * Get the set of options for the pack and unpack engines. |
67 * Get the set of options for the pack and unpack engines. |
75 * @return A sorted association of option key strings to option values. |
68 * @return A sorted association of option key strings to option values. |
76 */ |
69 */ |
77 public SortedMap properties() { |
70 public SortedMap<String, String> properties() { |
78 return _props; |
71 return props; |
79 } |
72 } |
80 |
73 |
81 // Back-pointer to NativeUnpacker, when active. |
74 // Back-pointer to NativeUnpacker, when active. |
82 Object _nunp; |
75 Object _nunp; |
83 |
76 |
99 * @param out a JarOutputStream. |
92 * @param out a JarOutputStream. |
100 * @exception IOException if an error is encountered. |
93 * @exception IOException if an error is encountered. |
101 */ |
94 */ |
102 public void unpack(InputStream in0, JarOutputStream out) throws IOException { |
95 public void unpack(InputStream in0, JarOutputStream out) throws IOException { |
103 assert(Utils.currentInstance.get() == null); |
96 assert(Utils.currentInstance.get() == null); |
104 TimeZone tz = (_props.getBoolean(Utils.PACK_DEFAULT_TIMEZONE)) ? null : |
97 TimeZone tz = (props.getBoolean(Utils.PACK_DEFAULT_TIMEZONE)) |
105 TimeZone.getDefault(); |
98 ? null |
|
99 : TimeZone.getDefault(); |
106 |
100 |
107 try { |
101 try { |
108 Utils.currentInstance.set(this); |
102 Utils.currentInstance.set(this); |
109 if (tz != null) TimeZone.setDefault(TimeZone.getTimeZone("UTC")); |
103 if (tz != null) TimeZone.setDefault(TimeZone.getTimeZone("UTC")); |
110 final int verbose = _props.getInteger(Utils.DEBUG_VERBOSE); |
104 final int verbose = props.getInteger(Utils.DEBUG_VERBOSE); |
111 BufferedInputStream in = new BufferedInputStream(in0); |
105 BufferedInputStream in = new BufferedInputStream(in0); |
112 if (Utils.isJarMagic(Utils.readMagic(in))) { |
106 if (Utils.isJarMagic(Utils.readMagic(in))) { |
113 if (verbose > 0) |
107 if (verbose > 0) |
114 Utils.log.info("Copying unpacked JAR file..."); |
108 Utils.log.info("Copying unpacked JAR file..."); |
115 Utils.copyJarFile(new JarInputStream(in), out); |
109 Utils.copyJarFile(new JarInputStream(in), out); |
116 } else if (_props.getBoolean(Utils.DEBUG_DISABLE_NATIVE)) { |
110 } else if (props.getBoolean(Utils.DEBUG_DISABLE_NATIVE)) { |
117 (new DoUnpack()).run(in, out); |
111 (new DoUnpack()).run(in, out); |
118 in.close(); |
112 in.close(); |
119 Utils.markJarFile(out); |
113 Utils.markJarFile(out); |
120 } else { |
114 } else { |
121 (new NativeUnpack(this)).run(in, out); |
115 (new NativeUnpack(this)).run(in, out); |
140 public void unpack(File in, JarOutputStream out) throws IOException { |
134 public void unpack(File in, JarOutputStream out) throws IOException { |
141 // Use the stream-based implementation. |
135 // Use the stream-based implementation. |
142 // %%% Reconsider if native unpacker learns to memory-map the file. |
136 // %%% Reconsider if native unpacker learns to memory-map the file. |
143 FileInputStream instr = new FileInputStream(in); |
137 FileInputStream instr = new FileInputStream(in); |
144 unpack(instr, out); |
138 unpack(instr, out); |
145 if (_props.getBoolean(Utils.UNPACK_REMOVE_PACKFILE)) { |
139 if (props.getBoolean(Utils.UNPACK_REMOVE_PACKFILE)) { |
146 in.delete(); |
140 in.delete(); |
147 } |
141 } |
148 } |
142 } |
149 |
143 |
150 private class DoUnpack { |
144 private class DoUnpack { |
151 final int verbose = _props.getInteger(Utils.DEBUG_VERBOSE); |
145 final int verbose = props.getInteger(Utils.DEBUG_VERBOSE); |
152 |
146 |
153 { |
147 { |
154 _props.setInteger(Pack200.Unpacker.PROGRESS, 0); |
148 props.setInteger(Pack200.Unpacker.PROGRESS, 0); |
155 } |
149 } |
156 |
150 |
157 // Here's where the bits are read from disk: |
151 // Here's where the bits are read from disk: |
158 final Package pkg = new Package(); |
152 final Package pkg = new Package(); |
159 |
153 |
160 final boolean keepModtime |
154 final boolean keepModtime |
161 = Pack200.Packer.KEEP.equals(_props.getProperty(Utils.UNPACK_MODIFICATION_TIME, Pack200.Packer.KEEP)); |
155 = Pack200.Packer.KEEP.equals( |
|
156 props.getProperty(Utils.UNPACK_MODIFICATION_TIME, Pack200.Packer.KEEP)); |
162 final boolean keepDeflateHint |
157 final boolean keepDeflateHint |
163 = Pack200.Packer.KEEP.equals(_props.getProperty(Pack200.Unpacker.DEFLATE_HINT, Pack200.Packer.KEEP)); |
158 = Pack200.Packer.KEEP.equals( |
|
159 props.getProperty(Pack200.Unpacker.DEFLATE_HINT, Pack200.Packer.KEEP)); |
164 final int modtime; |
160 final int modtime; |
165 final boolean deflateHint; |
161 final boolean deflateHint; |
166 { |
162 { |
167 if (!keepModtime) { |
163 if (!keepModtime) { |
168 modtime = _props.getTime(Utils.UNPACK_MODIFICATION_TIME); |
164 modtime = props.getTime(Utils.UNPACK_MODIFICATION_TIME); |
169 } else { |
165 } else { |
170 modtime = pkg.default_modtime; |
166 modtime = pkg.default_modtime; |
171 } |
167 } |
172 |
168 |
173 deflateHint = (keepDeflateHint) ? false : |
169 deflateHint = (keepDeflateHint) ? false : |
174 _props.getBoolean(java.util.jar.Pack200.Unpacker.DEFLATE_HINT); |
170 props.getBoolean(java.util.jar.Pack200.Unpacker.DEFLATE_HINT); |
175 } |
171 } |
176 |
172 |
177 // Checksum apparatus. |
173 // Checksum apparatus. |
178 final CRC32 crc = new CRC32(); |
174 final CRC32 crc = new CRC32(); |
179 final ByteArrayOutputStream bufOut = new ByteArrayOutputStream(); |
175 final ByteArrayOutputStream bufOut = new ByteArrayOutputStream(); |
180 final OutputStream crcOut = new CheckedOutputStream(bufOut, crc); |
176 final OutputStream crcOut = new CheckedOutputStream(bufOut, crc); |
181 |
177 |
182 public void run(BufferedInputStream in, JarOutputStream out) throws IOException { |
178 public void run(BufferedInputStream in, JarOutputStream out) throws IOException { |
183 if (verbose > 0) { |
179 if (verbose > 0) { |
184 _props.list(System.out); |
180 props.list(System.out); |
185 } |
181 } |
186 for (int seg = 1; ; seg++) { |
182 for (int seg = 1; ; seg++) { |
187 unpackSegment(in, out); |
183 unpackSegment(in, out); |
188 |
184 |
189 // Try to get another segment. |
185 // Try to get another segment. |
192 Utils.log.info("Finished segment #"+seg); |
188 Utils.log.info("Finished segment #"+seg); |
193 } |
189 } |
194 } |
190 } |
195 |
191 |
196 private void unpackSegment(InputStream in, JarOutputStream out) throws IOException { |
192 private void unpackSegment(InputStream in, JarOutputStream out) throws IOException { |
197 _props.setProperty(java.util.jar.Pack200.Unpacker.PROGRESS,"0"); |
193 props.setProperty(java.util.jar.Pack200.Unpacker.PROGRESS,"0"); |
198 // Process the output directory or jar output. |
194 // Process the output directory or jar output. |
199 new PackageReader(pkg, in).read(); |
195 new PackageReader(pkg, in).read(); |
200 |
196 |
201 if (_props.getBoolean("unpack.strip.debug")) pkg.stripAttributeKind("Debug"); |
197 if (props.getBoolean("unpack.strip.debug")) pkg.stripAttributeKind("Debug"); |
202 if (_props.getBoolean("unpack.strip.compile")) pkg.stripAttributeKind("Compile"); |
198 if (props.getBoolean("unpack.strip.compile")) pkg.stripAttributeKind("Compile"); |
203 _props.setProperty(java.util.jar.Pack200.Unpacker.PROGRESS,"50"); |
199 props.setProperty(java.util.jar.Pack200.Unpacker.PROGRESS,"50"); |
204 pkg.ensureAllClassFiles(); |
200 pkg.ensureAllClassFiles(); |
205 // Now write out the files. |
201 // Now write out the files. |
206 HashSet classesToWrite = new HashSet(pkg.getClasses()); |
202 HashSet<Package.Class> classesToWrite = new HashSet<>(pkg.getClasses()); |
207 for (Iterator i = pkg.getFiles().iterator(); i.hasNext(); ) { |
203 for (Iterator i = pkg.getFiles().iterator(); i.hasNext(); ) { |
208 Package.File file = (Package.File) i.next(); |
204 Package.File file = (Package.File) i.next(); |
209 String name = file.nameString; |
205 String name = file.nameString; |
210 JarEntry je = new JarEntry(Utils.getJarEntryName(name)); |
206 JarEntry je = new JarEntry(Utils.getJarEntryName(name)); |
211 boolean deflate; |
207 boolean deflate; |
212 |
208 |
213 deflate = (keepDeflateHint) ? (((file.options & Constants.FO_DEFLATE_HINT) != 0) || |
209 deflate = (keepDeflateHint) |
214 ((pkg.default_options & Constants.AO_DEFLATE_HINT) != 0)) : |
210 ? (((file.options & Constants.FO_DEFLATE_HINT) != 0) || |
215 deflateHint; |
211 ((pkg.default_options & Constants.AO_DEFLATE_HINT) != 0)) |
|
212 : deflateHint; |
216 |
213 |
217 boolean needCRC = !deflate; // STORE mode requires CRC |
214 boolean needCRC = !deflate; // STORE mode requires CRC |
218 |
215 |
219 if (needCRC) crc.reset(); |
216 if (needCRC) crc.reset(); |
220 bufOut.reset(); |
217 bufOut.reset(); |