001: /*
002: * Copyright 2003-2005 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package com.sun.java.util.jar.pack;
027:
028: import java.util.*;
029: import java.util.jar.*;
030: import java.util.zip.*;
031: import java.util.logging.*;
032: import java.io.*;
033:
034: class Utils {
035: static final String COM_PREFIX = "com.sun.java.util.jar.pack.";
036: static final String METAINF = "META-INF";
037:
038: /*
039: * Outputs various diagnostic support information.
040: * If >0, print summary comments (e.g., constant pool info).
041: * If >1, print unit comments (e.g., processing of classes).
042: * If >2, print many comments (e.g., processing of members).
043: * If >3, print tons of comments (e.g., processing of references).
044: * (installer only)
045: */
046: static final String DEBUG_VERBOSE = Utils.COM_PREFIX + "verbose";
047:
048: /*
049: * Disables use of native code, prefers the Java-coded implementation.
050: * (installer only)
051: */
052: static final String DEBUG_DISABLE_NATIVE = COM_PREFIX
053: + "disable.native";
054:
055: /*
056: * Use the default working TimeZone instead of UTC.
057: * Note: This has installer unpacker implications.
058: * see: zip.cpp which uses gmtime vs. localtime.
059: */
060: static final String PACK_DEFAULT_TIMEZONE = COM_PREFIX
061: + "default.timezone";
062:
063: /*
064: * Property indicating that the unpacker should
065: * ignore the transmitted PACK_MODIFICATION_TIME,
066: * replacing it by the given value. The value can
067: * be a numeric string, representing the number of
068: * mSecs since the epoch (UTC), or the special string
069: * {@link #NOW}, meaning the current time (UTC).
070: * The default value is the special string {@link #KEEP},
071: * which asks the unpacker to preserve all transmitted
072: * modification time information.
073: * (installer only)
074: */
075: static final String UNPACK_MODIFICATION_TIME = COM_PREFIX
076: + "unpack.modification.time";
077:
078: /*
079: * Property indicating that the unpacker strip the
080: * Debug Attributes, if they are present, in the pack stream.
081: * The default value is false.
082: * (installer only)
083: */
084: static final String UNPACK_STRIP_DEBUG = COM_PREFIX
085: + "unpack.strip.debug";
086:
087: /*
088: * Remove the input file after unpacking.
089: * (installer only)
090: */
091: static final String UNPACK_REMOVE_PACKFILE = COM_PREFIX
092: + "unpack.remove.packfile";
093:
094: /*
095: * A possible value for MODIFICATION_TIME
096: */
097: static final String NOW = "now";
098: // Other debug options:
099: // com...debug.bands=false add band IDs to pack file, to verify sync
100: // com...dump.bands=false dump band contents to local disk
101: // com...no.vary.codings=false turn off coding variation heuristics
102: // com...no.big.strings=false turn off "big string" feature
103:
104: /*
105: * If this property is set to {@link #TRUE}, the packer will preserve
106: * the ordering of class files of the original jar in the output archive.
107: * The ordering is preserved only for class-files; resource files
108: * may be reordered.
109: * <p>
110: * If the packer is allowed to reorder class files, it can marginally
111: * decrease the transmitted size of the archive.
112: */
113: static final String PACK_KEEP_CLASS_ORDER = COM_PREFIX
114: + "keep.class.order";
115: /*
116: * This string PACK200 is given as a zip comment on all JAR files
117: * produced by this utility.
118: */
119: static final String PACK_ZIP_ARCHIVE_MARKER_COMMENT = "PACK200";
120:
121: // Keep a TLS point to the current Packer or Unpacker.
122: // This makes it simpler to supply environmental options
123: // to the engine code, especially the native code.
124: static final ThreadLocal currentInstance = new ThreadLocal();
125:
126: static PropMap currentPropMap() {
127: Object obj = currentInstance.get();
128: if (obj instanceof PackerImpl)
129: return ((PackerImpl) obj)._props;
130: if (obj instanceof UnpackerImpl)
131: return ((UnpackerImpl) obj)._props;
132: return null;
133: }
134:
135: static final boolean nolog = Boolean.getBoolean(Utils.COM_PREFIX
136: + "nolog");
137:
138: static final Logger log = new Logger("java.util.jar.Pack200", null) {
139: public void log(LogRecord record) {
140: int verbose = currentPropMap().getInteger(DEBUG_VERBOSE);
141: if (verbose > 0) {
142: if (nolog
143: && record.getLevel().intValue() < Level.WARNING
144: .intValue()) {
145: System.out.println(record.getMessage());
146: } else {
147: super .log(record);
148: }
149: }
150: }
151:
152: public void fine(String msg) {
153: int verbose = currentPropMap().getInteger(DEBUG_VERBOSE);
154: if (verbose > 0) {
155: System.out.println(msg);
156: }
157: }
158: };
159: static {
160: LogManager.getLogManager().addLogger(log);
161: }
162:
163: // Returns the Max Version String of this implementation
164: static String getVersionString() {
165: return "Pack200, Vendor: Sun Microsystems, Version: "
166: + Constants.JAVA6_PACKAGE_MAJOR_VERSION + "."
167: + Constants.JAVA6_PACKAGE_MINOR_VERSION;
168: }
169:
170: static void markJarFile(JarOutputStream out) throws IOException {
171: out.setComment(PACK_ZIP_ARCHIVE_MARKER_COMMENT);
172: }
173:
174: // -0 mode helper
175: static void copyJarFile(JarInputStream in, JarOutputStream out)
176: throws IOException {
177: if (in.getManifest() != null) {
178: ZipEntry me = new ZipEntry(JarFile.MANIFEST_NAME);
179: out.putNextEntry(me);
180: in.getManifest().write(out);
181: out.closeEntry();
182: }
183: byte[] buffer = new byte[1 << 14];
184: for (JarEntry je; (je = in.getNextJarEntry()) != null;) {
185: out.putNextEntry(je);
186: for (int nr; 0 < (nr = in.read(buffer));) {
187: out.write(buffer, 0, nr);
188: }
189: }
190: in.close();
191: markJarFile(out); // add PACK200 comment
192: }
193:
194: static void copyJarFile(JarFile in, JarOutputStream out)
195: throws IOException {
196: byte[] buffer = new byte[1 << 14];
197: for (Enumeration e = in.entries(); e.hasMoreElements();) {
198: JarEntry je = (JarEntry) e.nextElement();
199: out.putNextEntry(je);
200: InputStream ein = in.getInputStream(je);
201: for (int nr; 0 < (nr = ein.read(buffer));) {
202: out.write(buffer, 0, nr);
203: }
204: }
205: in.close();
206: markJarFile(out); // add PACK200 comment
207: }
208:
209: static void copyJarFile(JarInputStream in, OutputStream out)
210: throws IOException {
211: // 4947205 : Peformance is slow when using pack-effort=0
212: out = new BufferedOutputStream(out);
213: out = new NonCloser(out); // protect from JarOutputStream.close()
214: JarOutputStream jout = new JarOutputStream(out);
215: copyJarFile(in, jout);
216: jout.close();
217: }
218:
219: static void copyJarFile(JarFile in, OutputStream out)
220: throws IOException {
221:
222: // 4947205 : Peformance is slow when using pack-effort=0
223: out = new BufferedOutputStream(out);
224: out = new NonCloser(out); // protect from JarOutputStream.close()
225: JarOutputStream jout = new JarOutputStream(out);
226: copyJarFile(in, jout);
227: jout.close();
228: }
229:
230: // Wrapper to prevent closing of client-supplied stream.
231: static private class NonCloser extends FilterOutputStream {
232: NonCloser(OutputStream out) {
233: super (out);
234: }
235:
236: public void close() throws IOException {
237: flush();
238: }
239: }
240:
241: static String getJarEntryName(String name) {
242: if (name == null)
243: return null;
244: return name.replace(File.separatorChar, '/');
245: }
246:
247: static String zeString(ZipEntry ze) {
248: int store = (ze.getCompressedSize() > 0) ? (int) ((1.0 - ((double) ze
249: .getCompressedSize() / (double) ze.getSize())) * 100)
250: : 0;
251: // Follow unzip -lv output
252: return (long) ze.getSize() + "\t" + ze.getMethod() + "\t"
253: + ze.getCompressedSize() + "\t" + store + "%\t"
254: + new Date(ze.getTime()) + "\t"
255: + Long.toHexString(ze.getCrc()) + "\t" + ze.getName();
256: }
257:
258: static byte[] readMagic(BufferedInputStream in) throws IOException {
259: in.mark(4);
260: byte[] magic = new byte[4];
261: for (int i = 0; i < magic.length; i++) {
262: // read 1 byte at a time, so we always get 4
263: if (1 != in.read(magic, i, 1))
264: break;
265: }
266: in.reset();
267: return magic;
268: }
269:
270: // magic number recognizers
271: static boolean isJarMagic(byte[] magic) {
272: return (magic[0] == (byte) 'P' && magic[1] == (byte) 'K'
273: && magic[2] >= 1 && magic[2] < 8 && magic[3] == magic[2] + 1);
274: }
275:
276: static boolean isPackMagic(byte[] magic) {
277: return (magic[0] == (byte) 0xCA && magic[1] == (byte) 0xFE
278: && magic[2] == (byte) 0xD0 && magic[3] == (byte) 0x0D);
279: }
280:
281: static boolean isGZIPMagic(byte[] magic) {
282: return (magic[0] == (byte) 0x1F && magic[1] == (byte) 0x8B && magic[2] == (byte) 0x08);
283: // fourth byte is variable "flg" field
284: }
285:
286: private Utils() {
287: } // do not instantiate
288: }
|