blob: c595e799a40ef59174c6fdd74df65959ad16b927 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2003-2005 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
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
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package com.sun.java.util.jar.pack;
27
28import java.util.*;
29import java.util.jar.*;
30import java.util.zip.*;
31import java.util.logging.*;
32import java.io.*;
33
34class Utils {
35 static final String COM_PREFIX = "com.sun.java.util.jar.pack.";
36 static final String METAINF = "META-INF";
37
38 /*
39 * Outputs various diagnostic support information.
40 * If >0, print summary comments (e.g., constant pool info).
41 * If >1, print unit comments (e.g., processing of classes).
42 * If >2, print many comments (e.g., processing of members).
43 * If >3, print tons of comments (e.g., processing of references).
44 * (installer only)
45 */
46 static final String DEBUG_VERBOSE = Utils.COM_PREFIX+"verbose";
47
48 /*
49 * Disables use of native code, prefers the Java-coded implementation.
50 * (installer only)
51 */
52 static final String DEBUG_DISABLE_NATIVE = COM_PREFIX+"disable.native";
53
54 /*
55 * Use the default working TimeZone instead of UTC.
56 * Note: This has installer unpacker implications.
57 * see: zip.cpp which uses gmtime vs. localtime.
58 */
59 static final String PACK_DEFAULT_TIMEZONE = COM_PREFIX+"default.timezone";
60
61 /*
62 * Property indicating that the unpacker should
63 * ignore the transmitted PACK_MODIFICATION_TIME,
64 * replacing it by the given value. The value can
65 * be a numeric string, representing the number of
66 * mSecs since the epoch (UTC), or the special string
67 * {@link #NOW}, meaning the current time (UTC).
68 * The default value is the special string {@link #KEEP},
69 * which asks the unpacker to preserve all transmitted
70 * modification time information.
71 * (installer only)
72 */
73 static final String UNPACK_MODIFICATION_TIME = COM_PREFIX+"unpack.modification.time";
74
75 /*
76 * Property indicating that the unpacker strip the
77 * Debug Attributes, if they are present, in the pack stream.
78 * The default value is false.
79 * (installer only)
80 */
81 static final String UNPACK_STRIP_DEBUG = COM_PREFIX+"unpack.strip.debug";
82
83 /*
84 * Remove the input file after unpacking.
85 * (installer only)
86 */
87 static final String UNPACK_REMOVE_PACKFILE = COM_PREFIX+"unpack.remove.packfile";
88
89 /*
90 * A possible value for MODIFICATION_TIME
91 */
92 static final String NOW = "now";
93 // Other debug options:
94 // com...debug.bands=false add band IDs to pack file, to verify sync
95 // com...dump.bands=false dump band contents to local disk
96 // com...no.vary.codings=false turn off coding variation heuristics
97 // com...no.big.strings=false turn off "big string" feature
98
99 /*
100 * If this property is set to {@link #TRUE}, the packer will preserve
101 * the ordering of class files of the original jar in the output archive.
102 * The ordering is preserved only for class-files; resource files
103 * may be reordered.
104 * <p>
105 * If the packer is allowed to reorder class files, it can marginally
106 * decrease the transmitted size of the archive.
107 */
108 static final String PACK_KEEP_CLASS_ORDER = COM_PREFIX+"keep.class.order";
109 /*
110 * This string PACK200 is given as a zip comment on all JAR files
111 * produced by this utility.
112 */
113 static final String PACK_ZIP_ARCHIVE_MARKER_COMMENT = "PACK200";
114
115 // Keep a TLS point to the current Packer or Unpacker.
116 // This makes it simpler to supply environmental options
117 // to the engine code, especially the native code.
118 static final ThreadLocal currentInstance = new ThreadLocal();
119
120 static PropMap currentPropMap() {
121 Object obj = currentInstance.get();
122 if (obj instanceof PackerImpl)
123 return ((PackerImpl)obj)._props;
124 if (obj instanceof UnpackerImpl)
125 return ((UnpackerImpl)obj)._props;
126 return null;
127 }
128
129 static final boolean nolog
130 = Boolean.getBoolean(Utils.COM_PREFIX+"nolog");
131
132
133 static final Logger log
134 = new Logger("java.util.jar.Pack200", null) {
135 public void log(LogRecord record) {
136 int verbose = currentPropMap().getInteger(DEBUG_VERBOSE);
137 if (verbose > 0) {
138 if (nolog &&
139 record.getLevel().intValue() < Level.WARNING.intValue()) {
140 System.out.println(record.getMessage());
141 } else {
142 super.log(record);
143 }
144 }
145 }
146
147 public void fine(String msg) {
148 int verbose = currentPropMap().getInteger(DEBUG_VERBOSE);
149 if (verbose > 0) {
150 System.out.println(msg);
151 }
152 }
153 };
154 static {
155 LogManager.getLogManager().addLogger(log);
156 }
157
158 // Returns the Max Version String of this implementation
159 static String getVersionString() {
160 return "Pack200, Vendor: Sun Microsystems, Version: " +
161 Constants.JAVA6_PACKAGE_MAJOR_VERSION + "." +
162 Constants.JAVA6_PACKAGE_MINOR_VERSION;
163 }
164
165 static void markJarFile(JarOutputStream out) throws IOException {
166 out.setComment(PACK_ZIP_ARCHIVE_MARKER_COMMENT);
167 }
168
169 // -0 mode helper
170 static void copyJarFile(JarInputStream in, JarOutputStream out) throws IOException {
171 if (in.getManifest() != null) {
172 ZipEntry me = new ZipEntry(JarFile.MANIFEST_NAME);
173 out.putNextEntry(me);
174 in.getManifest().write(out);
175 out.closeEntry();
176 }
177 byte[] buffer = new byte[1 << 14];
178 for (JarEntry je; (je = in.getNextJarEntry()) != null; ) {
179 out.putNextEntry(je);
180 for (int nr; 0 < (nr = in.read(buffer)); ) {
181 out.write(buffer, 0, nr);
182 }
183 }
184 in.close();
185 markJarFile(out); // add PACK200 comment
186 }
187 static void copyJarFile(JarFile in, JarOutputStream out) throws IOException {
188 byte[] buffer = new byte[1 << 14];
189 for (Enumeration e = in.entries(); e.hasMoreElements(); ) {
190 JarEntry je = (JarEntry) e.nextElement();
191 out.putNextEntry(je);
192 InputStream ein = in.getInputStream(je);
193 for (int nr; 0 < (nr = ein.read(buffer)); ) {
194 out.write(buffer, 0, nr);
195 }
196 }
197 in.close();
198 markJarFile(out); // add PACK200 comment
199 }
200 static void copyJarFile(JarInputStream in, OutputStream out) throws IOException {
201 // 4947205 : Peformance is slow when using pack-effort=0
202 out = new BufferedOutputStream(out);
203 out = new NonCloser(out); // protect from JarOutputStream.close()
204 JarOutputStream jout = new JarOutputStream(out);
205 copyJarFile(in, jout);
206 jout.close();
207 }
208 static void copyJarFile(JarFile in, OutputStream out) throws IOException {
209
210 // 4947205 : Peformance is slow when using pack-effort=0
211 out = new BufferedOutputStream(out);
212 out = new NonCloser(out); // protect from JarOutputStream.close()
213 JarOutputStream jout = new JarOutputStream(out);
214 copyJarFile(in, jout);
215 jout.close();
216 }
217 // Wrapper to prevent closing of client-supplied stream.
218 static private
219 class NonCloser extends FilterOutputStream {
220 NonCloser(OutputStream out) { super(out); }
221 public void close() throws IOException { flush(); }
222 }
223 static String getJarEntryName(String name) {
224 if (name == null) return null;
225 return name.replace(File.separatorChar, '/');
226 }
227
228 static String zeString(ZipEntry ze) {
229 int store = (ze.getCompressedSize() > 0) ?
230 (int)( (1.0 - ((double)ze.getCompressedSize()/(double)ze.getSize()))*100 )
231 : 0 ;
232 // Follow unzip -lv output
233 return (long)ze.getSize() + "\t" + ze.getMethod()
234 + "\t" + ze.getCompressedSize() + "\t"
235 + store + "%\t"
236 + new Date(ze.getTime()) + "\t"
237 + Long.toHexString(ze.getCrc()) + "\t"
238 + ze.getName() ;
239 }
240
241
242
243 static byte[] readMagic(BufferedInputStream in) throws IOException {
244 in.mark(4);
245 byte[] magic = new byte[4];
246 for (int i = 0; i < magic.length; i++) {
247 // read 1 byte at a time, so we always get 4
248 if (1 != in.read(magic, i, 1))
249 break;
250 }
251 in.reset();
252 return magic;
253 }
254
255 // magic number recognizers
256 static boolean isJarMagic(byte[] magic) {
257 return (magic[0] == (byte)'P' &&
258 magic[1] == (byte)'K' &&
259 magic[2] >= 1 &&
260 magic[2] < 8 &&
261 magic[3] == magic[2] + 1);
262 }
263 static boolean isPackMagic(byte[] magic) {
264 return (magic[0] == (byte)0xCA &&
265 magic[1] == (byte)0xFE &&
266 magic[2] == (byte)0xD0 &&
267 magic[3] == (byte)0x0D);
268 }
269 static boolean isGZIPMagic(byte[] magic) {
270 return (magic[0] == (byte)0x1F &&
271 magic[1] == (byte)0x8B &&
272 magic[2] == (byte)0x08);
273 // fourth byte is variable "flg" field
274 }
275
276 private Utils() { } // do not instantiate
277}