| /* |
| * Copyright (c) 2003, 2005, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle in the LICENSE file that accompanied this code. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| package com.sun.java.util.jar.pack; |
| |
| import java.util.*; |
| import java.util.jar.*; |
| import java.util.zip.*; |
| import java.io.*; |
| |
| import sun.util.logging.PlatformLogger; |
| |
| class Utils { |
| static final String COM_PREFIX = "com.sun.java.util.jar.pack."; |
| static final String METAINF = "META-INF"; |
| |
| /* |
| * Outputs various diagnostic support information. |
| * If >0, print summary comments (e.g., constant pool info). |
| * If >1, print unit comments (e.g., processing of classes). |
| * If >2, print many comments (e.g., processing of members). |
| * If >3, print tons of comments (e.g., processing of references). |
| * (installer only) |
| */ |
| static final String DEBUG_VERBOSE = Utils.COM_PREFIX+"verbose"; |
| |
| /* |
| * Disables use of native code, prefers the Java-coded implementation. |
| * (installer only) |
| */ |
| static final String DEBUG_DISABLE_NATIVE = COM_PREFIX+"disable.native"; |
| |
| /* |
| * Use the default working TimeZone instead of UTC. |
| * Note: This has installer unpacker implications. |
| * see: zip.cpp which uses gmtime vs. localtime. |
| */ |
| static final String PACK_DEFAULT_TIMEZONE = COM_PREFIX+"default.timezone"; |
| |
| /* |
| * Property indicating that the unpacker should |
| * ignore the transmitted PACK_MODIFICATION_TIME, |
| * replacing it by the given value. The value can |
| * be a numeric string, representing the number of |
| * mSecs since the epoch (UTC), or the special string |
| * {@link #NOW}, meaning the current time (UTC). |
| * The default value is the special string {@link #KEEP}, |
| * which asks the unpacker to preserve all transmitted |
| * modification time information. |
| * (installer only) |
| */ |
| static final String UNPACK_MODIFICATION_TIME = COM_PREFIX+"unpack.modification.time"; |
| |
| /* |
| * Property indicating that the unpacker strip the |
| * Debug Attributes, if they are present, in the pack stream. |
| * The default value is false. |
| * (installer only) |
| */ |
| static final String UNPACK_STRIP_DEBUG = COM_PREFIX+"unpack.strip.debug"; |
| |
| /* |
| * Remove the input file after unpacking. |
| * (installer only) |
| */ |
| static final String UNPACK_REMOVE_PACKFILE = COM_PREFIX+"unpack.remove.packfile"; |
| |
| /* |
| * A possible value for MODIFICATION_TIME |
| */ |
| static final String NOW = "now"; |
| // Other debug options: |
| // com...debug.bands=false add band IDs to pack file, to verify sync |
| // com...dump.bands=false dump band contents to local disk |
| // com...no.vary.codings=false turn off coding variation heuristics |
| // com...no.big.strings=false turn off "big string" feature |
| |
| /* |
| * If this property is set to {@link #TRUE}, the packer will preserve |
| * the ordering of class files of the original jar in the output archive. |
| * The ordering is preserved only for class-files; resource files |
| * may be reordered. |
| * <p> |
| * If the packer is allowed to reorder class files, it can marginally |
| * decrease the transmitted size of the archive. |
| */ |
| static final String PACK_KEEP_CLASS_ORDER = COM_PREFIX+"keep.class.order"; |
| /* |
| * This string PACK200 is given as a zip comment on all JAR files |
| * produced by this utility. |
| */ |
| static final String PACK_ZIP_ARCHIVE_MARKER_COMMENT = "PACK200"; |
| |
| // Keep a TLS point to the current Packer or Unpacker. |
| // This makes it simpler to supply environmental options |
| // to the engine code, especially the native code. |
| static final ThreadLocal currentInstance = new ThreadLocal(); |
| |
| static PropMap currentPropMap() { |
| Object obj = currentInstance.get(); |
| if (obj instanceof PackerImpl) |
| return ((PackerImpl)obj)._props; |
| if (obj instanceof UnpackerImpl) |
| return ((UnpackerImpl)obj)._props; |
| return null; |
| } |
| |
| static final boolean nolog |
| = Boolean.getBoolean(Utils.COM_PREFIX+"nolog"); |
| |
| |
| static class Pack200Logger { |
| private final String name; |
| private PlatformLogger log; |
| Pack200Logger(String name) { |
| this.name = name; |
| } |
| |
| private synchronized PlatformLogger getLogger() { |
| if (log == null) { |
| log = PlatformLogger.getLogger(name); |
| } |
| return log; |
| } |
| |
| public void warning(String msg, Object param) { |
| int verbose = currentPropMap().getInteger(DEBUG_VERBOSE); |
| if (verbose > 0) { |
| getLogger().warning(msg, param); |
| } |
| } |
| |
| public void warning(String msg) { |
| warning(msg, null); |
| } |
| |
| public void info(String msg) { |
| int verbose = currentPropMap().getInteger(DEBUG_VERBOSE); |
| if (verbose > 0) { |
| if (nolog) { |
| System.out.println(msg); |
| } else { |
| getLogger().info(msg); |
| } |
| } |
| } |
| |
| public void fine(String msg) { |
| int verbose = currentPropMap().getInteger(DEBUG_VERBOSE); |
| if (verbose > 0) { |
| System.out.println(msg); |
| } |
| } |
| } |
| |
| static final Pack200Logger log |
| = new Pack200Logger("java.util.jar.Pack200"); |
| |
| // Returns the Max Version String of this implementation |
| static String getVersionString() { |
| return "Pack200, Vendor: Sun Microsystems, Version: " + |
| Constants.JAVA6_PACKAGE_MAJOR_VERSION + "." + |
| Constants.JAVA6_PACKAGE_MINOR_VERSION; |
| } |
| |
| static void markJarFile(JarOutputStream out) throws IOException { |
| out.setComment(PACK_ZIP_ARCHIVE_MARKER_COMMENT); |
| } |
| |
| // -0 mode helper |
| static void copyJarFile(JarInputStream in, JarOutputStream out) throws IOException { |
| if (in.getManifest() != null) { |
| ZipEntry me = new ZipEntry(JarFile.MANIFEST_NAME); |
| out.putNextEntry(me); |
| in.getManifest().write(out); |
| out.closeEntry(); |
| } |
| byte[] buffer = new byte[1 << 14]; |
| for (JarEntry je; (je = in.getNextJarEntry()) != null; ) { |
| out.putNextEntry(je); |
| for (int nr; 0 < (nr = in.read(buffer)); ) { |
| out.write(buffer, 0, nr); |
| } |
| } |
| in.close(); |
| markJarFile(out); // add PACK200 comment |
| } |
| static void copyJarFile(JarFile in, JarOutputStream out) throws IOException { |
| byte[] buffer = new byte[1 << 14]; |
| for (Enumeration e = in.entries(); e.hasMoreElements(); ) { |
| JarEntry je = (JarEntry) e.nextElement(); |
| out.putNextEntry(je); |
| InputStream ein = in.getInputStream(je); |
| for (int nr; 0 < (nr = ein.read(buffer)); ) { |
| out.write(buffer, 0, nr); |
| } |
| } |
| in.close(); |
| markJarFile(out); // add PACK200 comment |
| } |
| static void copyJarFile(JarInputStream in, OutputStream out) throws IOException { |
| // 4947205 : Peformance is slow when using pack-effort=0 |
| out = new BufferedOutputStream(out); |
| out = new NonCloser(out); // protect from JarOutputStream.close() |
| JarOutputStream jout = new JarOutputStream(out); |
| copyJarFile(in, jout); |
| jout.close(); |
| } |
| static void copyJarFile(JarFile in, OutputStream out) throws IOException { |
| |
| // 4947205 : Peformance is slow when using pack-effort=0 |
| out = new BufferedOutputStream(out); |
| out = new NonCloser(out); // protect from JarOutputStream.close() |
| JarOutputStream jout = new JarOutputStream(out); |
| copyJarFile(in, jout); |
| jout.close(); |
| } |
| // Wrapper to prevent closing of client-supplied stream. |
| static private |
| class NonCloser extends FilterOutputStream { |
| NonCloser(OutputStream out) { super(out); } |
| public void close() throws IOException { flush(); } |
| } |
| static String getJarEntryName(String name) { |
| if (name == null) return null; |
| return name.replace(File.separatorChar, '/'); |
| } |
| |
| static String zeString(ZipEntry ze) { |
| int store = (ze.getCompressedSize() > 0) ? |
| (int)( (1.0 - ((double)ze.getCompressedSize()/(double)ze.getSize()))*100 ) |
| : 0 ; |
| // Follow unzip -lv output |
| return (long)ze.getSize() + "\t" + ze.getMethod() |
| + "\t" + ze.getCompressedSize() + "\t" |
| + store + "%\t" |
| + new Date(ze.getTime()) + "\t" |
| + Long.toHexString(ze.getCrc()) + "\t" |
| + ze.getName() ; |
| } |
| |
| |
| |
| static byte[] readMagic(BufferedInputStream in) throws IOException { |
| in.mark(4); |
| byte[] magic = new byte[4]; |
| for (int i = 0; i < magic.length; i++) { |
| // read 1 byte at a time, so we always get 4 |
| if (1 != in.read(magic, i, 1)) |
| break; |
| } |
| in.reset(); |
| return magic; |
| } |
| |
| // magic number recognizers |
| static boolean isJarMagic(byte[] magic) { |
| return (magic[0] == (byte)'P' && |
| magic[1] == (byte)'K' && |
| magic[2] >= 1 && |
| magic[2] < 8 && |
| magic[3] == magic[2] + 1); |
| } |
| static boolean isPackMagic(byte[] magic) { |
| return (magic[0] == (byte)0xCA && |
| magic[1] == (byte)0xFE && |
| magic[2] == (byte)0xD0 && |
| magic[3] == (byte)0x0D); |
| } |
| static boolean isGZIPMagic(byte[] magic) { |
| return (magic[0] == (byte)0x1F && |
| magic[1] == (byte)0x8B && |
| magic[2] == (byte)0x08); |
| // fourth byte is variable "flg" field |
| } |
| |
| private Utils() { } // do not instantiate |
| } |