blob: 8edbed10c4699b0e7717b97f6f14a48a2ef31f92 [file] [log] [blame]
/*
* 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
}