/* * 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.util.logging.*; import java.io.*; 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 final Logger log = new Logger("java.util.jar.Pack200", null) { public void log(LogRecord record) { int verbose = currentPropMap().getInteger(DEBUG_VERBOSE); if (verbose > 0) { if (nolog && record.getLevel().intValue() < Level.WARNING.intValue()) { System.out.println(record.getMessage()); } else { super.log(record); } } } public void fine(String msg) { int verbose = currentPropMap().getInteger(DEBUG_VERBOSE); if (verbose > 0) { System.out.println(msg); } } }; static { LogManager.getLogManager().addLogger(log); } // 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 }