8234542: code removal of Pack200 Tools and API

Reviewed-by: alanb, mchung, erikj
This commit is contained in:
Henry Jen 2019-12-10 00:36:30 +00:00
parent c198b4da32
commit 9ac2f8b654
107 changed files with 4 additions and 46217 deletions

View file

@ -67,7 +67,6 @@ export STRIP="@STRIP@ @STRIPFLAGS@"
export TAR="@TAR@" export TAR="@TAR@"
export TEE="@TEE@" export TEE="@TEE@"
export UNIQ="@UNIQ@" export UNIQ="@UNIQ@"
export UNPACK200="@FIXPATH@ @BOOT_JDK@/bin/unpack200"
export UNARCHIVE="@UNZIP@ -q -o" export UNARCHIVE="@UNZIP@ -q -o"
export TOPDIR="@TOPDIR@" export TOPDIR="@TOPDIR@"

View file

@ -129,7 +129,6 @@ endif
JRE_TOOL_MODULES += \ JRE_TOOL_MODULES += \
jdk.jdwp.agent \ jdk.jdwp.agent \
jdk.incubator.jpackage \ jdk.incubator.jpackage \
jdk.pack \
jdk.scripting.nashorn.shell \ jdk.scripting.nashorn.shell \
# #
@ -170,7 +169,6 @@ DOCS_MODULES += \
jdk.naming.dns \ jdk.naming.dns \
jdk.naming.rmi \ jdk.naming.rmi \
jdk.net \ jdk.net \
jdk.pack \
jdk.rmic \ jdk.rmic \
jdk.scripting.nashorn \ jdk.scripting.nashorn \
jdk.sctp \ jdk.sctp \

View file

@ -1,102 +0,0 @@
#
# Copyright (c) 2011, 2019, 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.
#
include LauncherCommon.gmk
$(eval $(call SetupBuildLauncher, pack200, \
MAIN_MODULE := java.base, \
MAIN_CLASS := com.sun.java.util.jar.pack.Driver, \
))
################################################################################
# The order of the object files on the link command line affects the size of the resulting
# binary (at least on linux) which causes the size to differ between old and new build.
# Tell the compiler not to export any functions unless declared so in
# the source code. On Windows, this is the default and cannot be changed.
# On Mac, we have always exported all symbols, probably due to oversight
# and/or misunderstanding. To emulate this, don't hide any symbols
# by default.
# On AIX/xlc we need at least xlc 13.1 for the symbol hiding (see JDK-8214063)
# Also provide an override for non-conformant libraries.
ifeq ($(TOOLCHAIN_TYPE), gcc)
CXXFLAGS_JDKEXE += -fvisibility=hidden
LDFLAGS_JDKEXE += -Wl,--exclude-libs,ALL
else ifeq ($(TOOLCHAIN_TYPE), clang)
ifeq ($(call isTargetOs, macosx), false)
CXXFLAGS_JDKEXE += -fvisibility=hidden
endif
else ifeq ($(TOOLCHAIN_TYPE), solstudio)
CXXFLAGS_JDKEXE += -xldscope=hidden
endif
UNPACKEXE_SRC := $(TOPDIR)/src/jdk.pack/share/native/common-unpack \
$(TOPDIR)/src/jdk.pack/share/native/unpack200
UNPACKEXE_CFLAGS := -I$(TOPDIR)/src/jdk.pack/share/native/common-unpack \
-I$(TOPDIR)/src/java.base/share/native/libjava \
-I$(TOPDIR)/src/java.base/$(OPENJDK_TARGET_OS_TYPE)/native/libjava
ifeq ($(USE_EXTERNAL_LIBZ), true)
UNPACKEXE_CFLAGS += -DSYSTEM_ZLIB
UNPACKEXE_LIBS := -lz
else
UNPACKEXE_CFLAGS += -I$(TOPDIR)/src/java.base/share/native/libzip/zlib
UNPACKEXE_ZIPOBJS := $(SUPPORT_OUTPUTDIR)/native/java.base/libzip/zcrc32$(OBJ_SUFFIX) \
$(SUPPORT_OUTPUTDIR)/native/java.base/libzip/deflate$(OBJ_SUFFIX) \
$(SUPPORT_OUTPUTDIR)/native/java.base/libzip/trees$(OBJ_SUFFIX) \
$(SUPPORT_OUTPUTDIR)/native/java.base/libzip/zadler32$(OBJ_SUFFIX) \
$(SUPPORT_OUTPUTDIR)/native/java.base/libzip/compress$(OBJ_SUFFIX) \
$(SUPPORT_OUTPUTDIR)/native/java.base/libzip/zutil$(OBJ_SUFFIX) \
$(SUPPORT_OUTPUTDIR)/native/java.base/libzip/inflate$(OBJ_SUFFIX) \
$(SUPPORT_OUTPUTDIR)/native/java.base/libzip/infback$(OBJ_SUFFIX) \
$(SUPPORT_OUTPUTDIR)/native/java.base/libzip/inftrees$(OBJ_SUFFIX) \
$(SUPPORT_OUTPUTDIR)/native/java.base/libzip/inffast$(OBJ_SUFFIX)
endif
$(eval $(call SetupJdkExecutable, BUILD_UNPACKEXE, \
NAME := unpack200, \
SRC := $(UNPACKEXE_SRC), \
TOOLCHAIN := TOOLCHAIN_LINK_CXX, \
OPTIMIZATION := LOW, \
CFLAGS := $(UNPACKEXE_CFLAGS) $(CXXFLAGS_JDKEXE) -DFULL, \
CFLAGS_release := -DPRODUCT, \
CFLAGS_linux := -fPIC, \
CFLAGS_solaris := -KPIC, \
CFLAGS_macosx := -fPIC, \
DISABLED_WARNINGS_clang := format-nonliteral, \
DISABLED_WARNINGS_solstudio := wunreachable, \
LDFLAGS := $(LDFLAGS_JDKEXE) $(LDFLAGS_CXX_JDK) \
$(call SET_SHARED_LIBRARY_ORIGIN), \
LIBS := $(UNPACKEXE_LIBS) $(LIBCXX), \
OBJECT_DIR := $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/unpackexe, \
MANIFEST := $(TOPDIR)/src/jdk.pack/windows/native/unpack200/unpack200_proto.exe.manifest, \
MANIFEST_VERSION := $(VERSION_NUMBER_FOUR_POSITIONS), \
EXTRA_OBJECT_FILES := $(UNPACKEXE_ZIPOBJS) \
))
TARGETS += $(BUILD_UNPACKEXE)
################################################################################

View file

@ -1,53 +0,0 @@
#
# Copyright (c) 2011, 2018, 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.
#
include LibCommon.gmk
################################################################################
$(eval $(call SetupJdkLibrary, BUILD_LIBUNPACK, \
NAME := unpack, \
EXTRA_SRC := common-unpack, \
TOOLCHAIN := TOOLCHAIN_LINK_CXX, \
OPTIMIZATION := LOW, \
CFLAGS := $(CXXFLAGS_JDKLIB) \
-DNO_ZLIB -DUNPACK_JNI -DFULL, \
CFLAGS_release := -DPRODUCT, \
EXTRA_HEADER_DIRS := $(call GetJavaHeaderDir, java.base), \
DISABLED_WARNINGS_gcc := implicit-fallthrough, \
DISABLED_WARNINGS_clang := format-nonliteral, \
DISABLED_WARNINGS_solstudio := wunreachable, \
LDFLAGS := $(LDFLAGS_JDKLIB) $(LDFLAGS_CXX_JDK) \
$(call SET_SHARED_LIBRARY_ORIGIN), \
LDFLAGS_windows := -map:$(SUPPORT_OUTPUTDIR)/native/$(MODULE)/unpack.map -debug, \
LIBS_unix := -ljvm $(LIBCXX) -ljava, \
LIBS_windows := jvm.lib $(WIN_JAVA_LIB), \
))
$(BUILD_LIBUNPACK): $(call FindLib, java.base, java)
TARGETS += $(BUILD_LIBUNPACK)
################################################################################

View file

@ -260,7 +260,6 @@ module:jdk.naming.rmi
module:jdk.net module:jdk.net
jdk.net jdk.net
jdk.nio jdk.nio
module:jdk.pack
module:jdk.rmic module:jdk.rmic
module:jdk.scripting.nashorn module:jdk.scripting.nashorn
jdk.nashorn.api.scripting jdk.nashorn.api.scripting

View file

@ -529,31 +529,6 @@ compare_zip_file() {
(cd $OTHER_UNZIPDIR && $JIMAGE extract $OTHER_ZIP) (cd $OTHER_UNZIPDIR && $JIMAGE extract $OTHER_ZIP)
fi fi
# Find all archives inside and unzip them as well to compare the contents rather than
# the archives. pie.jar.pack.gz i app3.war is corrupt, skip it.
EXCEPTIONS="pie.jar.pack.gz jdk.pack"
for pack in $($FIND $THIS_UNZIPDIR \( -name "*.pack" -o -name "*.pack.gz" \) -a \
! -name pie.jar.pack.gz -a ! -name jdk.pack); do
($UNPACK200 $pack $pack.jar)
# Filter out the unzipped archives from the diff below.
EXCEPTIONS="$EXCEPTIONS $pack $pack.jar"
done
for pack in $($FIND $OTHER_UNZIPDIR \( -name "*.pack" -o -name "*.pack.gz" \) -a \
! -name pie.jar.pack.gz -a ! -name jdk.pack); do
($UNPACK200 $pack $pack.jar)
EXCEPTIONS="$EXCEPTIONS $pack $pack.jar"
done
for zip in $($FIND $THIS_UNZIPDIR -name "*.jar" -o -name "*.zip"); do
$MKDIR $zip.unzip
(cd $zip.unzip && $UNARCHIVE $zip)
EXCEPTIONS="$EXCEPTIONS $zip"
done
for zip in $($FIND $OTHER_UNZIPDIR -name "*.jar" -o -name "*.zip"); do
$MKDIR $zip.unzip
(cd $zip.unzip && $UNARCHIVE $zip)
EXCEPTIONS="$EXCEPTIONS $zip"
done
CONTENTS_DIFF_FILE=$WORK_DIR/$ZIP_FILE.diff CONTENTS_DIFF_FILE=$WORK_DIR/$ZIP_FILE.diff
# On solaris, there is no -q option. # On solaris, there is no -q option.
if [ "$OPENJDK_TARGET_OS" = "solaris" ]; then if [ "$OPENJDK_TARGET_OS" = "solaris" ]; then

View file

@ -50,9 +50,7 @@ elif [ "$OPENJDK_TARGET_OS" = "solaris" ]; then
SORT_SYMBOLS=" SORT_SYMBOLS="
./lib/libfontmanager.so ./lib/libfontmanager.so
./lib/libjimage.so ./lib/libjimage.so
./lib/libunpack.so
./lib/server/libjvm.so ./lib/server/libjvm.so
./bin/unpack200
./hotspot/gtest/server/libjvm.so ./hotspot/gtest/server/libjvm.so
" "
KNOWN_DIS_DIFF=" KNOWN_DIS_DIFF="

View file

@ -1,298 +0,0 @@
/*
* Copyright (c) 2003, 2010, 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.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import static com.sun.java.util.jar.pack.Constants.*;
/**
* Adaptive coding.
* See the section "Adaptive Encodings" in the Pack200 spec.
* @author John Rose
*/
class AdaptiveCoding implements CodingMethod {
CodingMethod headCoding;
int headLength;
CodingMethod tailCoding;
public AdaptiveCoding(int headLength, CodingMethod headCoding, CodingMethod tailCoding) {
assert(isCodableLength(headLength));
this.headLength = headLength;
this.headCoding = headCoding;
this.tailCoding = tailCoding;
}
public void setHeadCoding(CodingMethod headCoding) {
this.headCoding = headCoding;
}
public void setHeadLength(int headLength) {
assert(isCodableLength(headLength));
this.headLength = headLength;
}
public void setTailCoding(CodingMethod tailCoding) {
this.tailCoding = tailCoding;
}
public boolean isTrivial() {
return headCoding == tailCoding;
}
// CodingMethod methods.
public void writeArrayTo(OutputStream out, int[] a, int start, int end) throws IOException {
writeArray(this, out, a, start, end);
}
// writeArrayTo must be coded iteratively, not recursively:
private static void writeArray(AdaptiveCoding run, OutputStream out, int[] a, int start, int end) throws IOException {
for (;;) {
int mid = start+run.headLength;
assert(mid <= end);
run.headCoding.writeArrayTo(out, a, start, mid);
start = mid;
if (run.tailCoding instanceof AdaptiveCoding) {
run = (AdaptiveCoding) run.tailCoding;
continue;
}
break;
}
run.tailCoding.writeArrayTo(out, a, start, end);
}
public void readArrayFrom(InputStream in, int[] a, int start, int end) throws IOException {
readArray(this, in, a, start, end);
}
private static void readArray(AdaptiveCoding run, InputStream in, int[] a, int start, int end) throws IOException {
for (;;) {
int mid = start+run.headLength;
assert(mid <= end);
run.headCoding.readArrayFrom(in, a, start, mid);
start = mid;
if (run.tailCoding instanceof AdaptiveCoding) {
run = (AdaptiveCoding) run.tailCoding;
continue;
}
break;
}
run.tailCoding.readArrayFrom(in, a, start, end);
}
public static final int KX_MIN = 0;
public static final int KX_MAX = 3;
public static final int KX_LG2BASE = 4;
public static final int KX_BASE = 16;
public static final int KB_MIN = 0x00;
public static final int KB_MAX = 0xFF;
public static final int KB_OFFSET = 1;
public static final int KB_DEFAULT = 3;
static int getKXOf(int K) {
for (int KX = KX_MIN; KX <= KX_MAX; KX++) {
if (((K - KB_OFFSET) & ~KB_MAX) == 0)
return KX;
K >>>= KX_LG2BASE;
}
return -1;
}
static int getKBOf(int K) {
int KX = getKXOf(K);
if (KX < 0) return -1;
K >>>= (KX * KX_LG2BASE);
return K-1;
}
static int decodeK(int KX, int KB) {
assert(KX_MIN <= KX && KX <= KX_MAX);
assert(KB_MIN <= KB && KB <= KB_MAX);
return (KB+KB_OFFSET) << (KX * KX_LG2BASE);
}
static int getNextK(int K) {
if (K <= 0) return 1; // 1st K value
int KX = getKXOf(K);
if (KX < 0) return Integer.MAX_VALUE;
// This is the increment we expect to apply:
int unit = 1 << (KX * KX_LG2BASE);
int mask = KB_MAX << (KX * KX_LG2BASE);
int K1 = K + unit;
K1 &= ~(unit-1); // cut off stray low-order bits
if (((K1 - unit) & ~mask) == 0) {
assert(getKXOf(K1) == KX);
return K1;
}
if (KX == KX_MAX) return Integer.MAX_VALUE;
KX += 1;
int mask2 = KB_MAX << (KX * KX_LG2BASE);
K1 |= (mask & ~mask2);
K1 += unit;
assert(getKXOf(K1) == KX);
return K1;
}
// Is K of the form ((KB:[0..255])+1) * 16^(KX:{0..3])?
public static boolean isCodableLength(int K) {
int KX = getKXOf(K);
if (KX < 0) return false;
int unit = 1 << (KX * KX_LG2BASE);
int mask = KB_MAX << (KX * KX_LG2BASE);
return ((K - unit) & ~mask) == 0;
}
public byte[] getMetaCoding(Coding dflt) {
//assert(!isTrivial()); // can happen
// See the isCodableLength restriction in CodingChooser.
ByteArrayOutputStream bytes = new ByteArrayOutputStream(10);
try {
makeMetaCoding(this, dflt, bytes);
} catch (IOException ee) {
throw new RuntimeException(ee);
}
return bytes.toByteArray();
}
private static void makeMetaCoding(AdaptiveCoding run, Coding dflt,
ByteArrayOutputStream bytes)
throws IOException {
for (;;) {
CodingMethod headCoding = run.headCoding;
int headLength = run.headLength;
CodingMethod tailCoding = run.tailCoding;
int K = headLength;
assert(isCodableLength(K));
int ADef = (headCoding == dflt)?1:0;
int BDef = (tailCoding == dflt)?1:0;
if (ADef+BDef > 1) BDef = 0; // arbitrary choice
int ABDef = 1*ADef + 2*BDef;
assert(ABDef < 3);
int KX = getKXOf(K);
int KB = getKBOf(K);
assert(decodeK(KX, KB) == K);
int KBFlag = (KB != KB_DEFAULT)?1:0;
bytes.write(_meta_run + KX + 4*KBFlag + 8*ABDef);
if (KBFlag != 0) bytes.write(KB);
if (ADef == 0) bytes.write(headCoding.getMetaCoding(dflt));
if (tailCoding instanceof AdaptiveCoding) {
run = (AdaptiveCoding) tailCoding;
continue; // tail call, to avoid deep stack recursion
}
if (BDef == 0) bytes.write(tailCoding.getMetaCoding(dflt));
break;
}
}
public static int parseMetaCoding(byte[] bytes, int pos, Coding dflt, CodingMethod res[]) {
int op = bytes[pos++] & 0xFF;
if (op < _meta_run || op >= _meta_pop) return pos-1; // backup
AdaptiveCoding prevc = null;
for (boolean keepGoing = true; keepGoing; ) {
keepGoing = false;
assert(op >= _meta_run);
op -= _meta_run;
int KX = op % 4;
int KBFlag = (op / 4) % 2;
int ABDef = (op / 8);
assert(ABDef < 3);
int ADef = (ABDef & 1);
int BDef = (ABDef & 2);
CodingMethod[] ACode = {dflt}, BCode = {dflt};
int KB = KB_DEFAULT;
if (KBFlag != 0)
KB = bytes[pos++] & 0xFF;
if (ADef == 0) {
pos = BandStructure.parseMetaCoding(bytes, pos, dflt, ACode);
}
if (BDef == 0 &&
((op = bytes[pos] & 0xFF) >= _meta_run) && op < _meta_pop) {
pos++;
keepGoing = true;
} else if (BDef == 0) {
pos = BandStructure.parseMetaCoding(bytes, pos, dflt, BCode);
}
AdaptiveCoding newc = new AdaptiveCoding(decodeK(KX, KB),
ACode[0], BCode[0]);
if (prevc == null) {
res[0] = newc;
} else {
prevc.tailCoding = newc;
}
prevc = newc;
}
return pos;
}
private String keyString(CodingMethod m) {
if (m instanceof Coding)
return ((Coding)m).keyString();
return m.toString();
}
public String toString() {
StringBuilder res = new StringBuilder(20);
AdaptiveCoding run = this;
res.append("run(");
for (;;) {
res.append(run.headLength).append("*");
res.append(keyString(run.headCoding));
if (run.tailCoding instanceof AdaptiveCoding) {
run = (AdaptiveCoding) run.tailCoding;
res.append(" ");
continue;
}
break;
}
res.append(" **").append(keyString(run.tailCoding));
res.append(")");
return res.toString();
}
/*
public static void main(String av[]) {
int[][] samples = {
{1,2,3,4,5},
{254,255,256,256+1*16,256+2*16},
{0xfd,0xfe,0xff,0x100,0x110,0x120,0x130},
{0xfd0,0xfe0,0xff0,0x1000,0x1100,0x1200,0x1300},
{0xfd00,0xfe00,0xff00,0x10000,0x11000,0x12000,0x13000},
{0xfd000,0xfe000,0xff000,0x100000}
};
for (int i = 0; i < samples.length; i++) {
for (int j = 0; j < samples[i].length; j++) {
int K = samples[i][j];
int KX = getKXOf(K);
int KB = getKBOf(K);
System.out.println("K="+Integer.toHexString(K)+
" KX="+KX+" KB="+KB);
assert(isCodableLength(K));
assert(K == decodeK(KX, KB));
if (j == 0) continue;
int K1 = samples[i][j-1];
assert(K == getNextK(K1));
}
}
}
//*/
}

View file

@ -1,619 +0,0 @@
/*
* Copyright (c) 2001, 2019, 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 com.sun.java.util.jar.pack.ConstantPool.ClassEntry;
import com.sun.java.util.jar.pack.ConstantPool.DescriptorEntry;
import com.sun.java.util.jar.pack.ConstantPool.Entry;
import com.sun.java.util.jar.pack.ConstantPool.SignatureEntry;
import com.sun.java.util.jar.pack.ConstantPool.MemberEntry;
import com.sun.java.util.jar.pack.ConstantPool.MethodHandleEntry;
import com.sun.java.util.jar.pack.ConstantPool.BootstrapMethodEntry;
import com.sun.java.util.jar.pack.ConstantPool.Utf8Entry;
import com.sun.java.util.jar.pack.Package.Class;
import com.sun.java.util.jar.pack.Package.InnerClass;
import java.io.DataInputStream;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Map;
import static com.sun.java.util.jar.pack.Constants.*;
/**
* Reader for a class file that is being incorporated into a package.
* @author John Rose
*/
class ClassReader {
int verbose;
Package pkg;
Class cls;
long inPos;
long constantPoolLimit = -1;
DataInputStream in;
Map<Attribute.Layout, Attribute> attrDefs;
Map<Attribute.Layout, String> attrCommands;
String unknownAttrCommand = "error";;
ClassReader(Class cls, InputStream in) throws IOException {
this.pkg = cls.getPackage();
this.cls = cls;
this.verbose = pkg.verbose;
this.in = new DataInputStream(new FilterInputStream(in) {
public int read(byte b[], int off, int len) throws IOException {
int nr = super.read(b, off, len);
if (nr >= 0) inPos += nr;
return nr;
}
public int read() throws IOException {
int ch = super.read();
if (ch >= 0) inPos += 1;
return ch;
}
public long skip(long n) throws IOException {
long ns = super.skip(n);
if (ns >= 0) inPos += ns;
return ns;
}
});
}
public void setAttrDefs(Map<Attribute.Layout, Attribute> attrDefs) {
this.attrDefs = attrDefs;
}
public void setAttrCommands(Map<Attribute.Layout, String> attrCommands) {
this.attrCommands = attrCommands;
}
private void skip(int n, String what) throws IOException {
Utils.log.warning("skipping "+n+" bytes of "+what);
long skipped = 0;
while (skipped < n) {
long j = in.skip(n - skipped);
assert(j > 0);
skipped += j;
}
assert(skipped == n);
}
private int readUnsignedShort() throws IOException {
return in.readUnsignedShort();
}
private int readInt() throws IOException {
return in.readInt();
}
/** Read a 2-byte int, and return the <em>global</em> CP entry for it. */
private Entry readRef() throws IOException {
int i = in.readUnsignedShort();
return i == 0 ? null : cls.cpMap[i];
}
private Entry readRef(byte tag) throws IOException {
Entry e = readRef();
assert(!(e instanceof UnresolvedEntry));
checkTag(e, tag);
return e;
}
/** Throw a ClassFormatException if the entry does not match the expected tag type. */
private Entry checkTag(Entry e, byte tag) throws ClassFormatException {
if (e == null || !e.tagMatches(tag)) {
String where = (inPos == constantPoolLimit
? " in constant pool"
: " at pos: " + inPos);
String got = (e == null
? "null CP index"
: "type=" + ConstantPool.tagName(e.tag));
throw new ClassFormatException("Bad constant, expected type=" +
ConstantPool.tagName(tag) +
" got "+ got + ", in File: " + cls.file.nameString + where);
}
return e;
}
private Entry checkTag(Entry e, byte tag, boolean nullOK) throws ClassFormatException {
return nullOK && e == null ? null : checkTag(e, tag);
}
private Entry readRefOrNull(byte tag) throws IOException {
Entry e = readRef();
checkTag(e, tag, true);
return e;
}
private Utf8Entry readUtf8Ref() throws IOException {
return (Utf8Entry) readRef(CONSTANT_Utf8);
}
private ClassEntry readClassRef() throws IOException {
return (ClassEntry) readRef(CONSTANT_Class);
}
private ClassEntry readClassRefOrNull() throws IOException {
return (ClassEntry) readRefOrNull(CONSTANT_Class);
}
private SignatureEntry readSignatureRef() throws IOException {
// The class file stores a Utf8, but we want a Signature.
Entry e = readRef(CONSTANT_Signature);
return (e != null && e.getTag() == CONSTANT_Utf8)
? ConstantPool.getSignatureEntry(e.stringValue())
: (SignatureEntry) e;
}
void read() throws IOException {
boolean ok = false;
try {
readMagicNumbers();
readConstantPool();
readHeader();
readMembers(false); // fields
readMembers(true); // methods
readAttributes(ATTR_CONTEXT_CLASS, cls);
fixUnresolvedEntries();
cls.finishReading();
assert(0 >= in.read(new byte[1]));
ok = true;
} finally {
if (!ok) {
if (verbose > 0) Utils.log.warning("Erroneous data at input offset "+inPos+" of "+cls.file);
}
}
}
void readMagicNumbers() throws IOException {
cls.magic = in.readInt();
if (cls.magic != JAVA_MAGIC)
throw new Attribute.FormatException
("Bad magic number in class file "
+Integer.toHexString(cls.magic),
ATTR_CONTEXT_CLASS, "magic-number", "pass");
int minver = (short) readUnsignedShort();
int majver = (short) readUnsignedShort();
cls.version = Package.Version.of(majver, minver);
//System.out.println("ClassFile.version="+cls.majver+"."+cls.minver);
String bad = checkVersion(cls.version);
if (bad != null) {
throw new Attribute.FormatException
("classfile version too "+bad+": "
+cls.version+" in "+cls.file,
ATTR_CONTEXT_CLASS, "version", "pass");
}
}
private String checkVersion(Package.Version ver) {
int majver = ver.major;
int minver = ver.minor;
if (majver < pkg.minClassVersion.major ||
(majver == pkg.minClassVersion.major &&
minver < pkg.minClassVersion.minor)) {
return "small";
}
if (majver > pkg.maxClassVersion.major ||
(majver == pkg.maxClassVersion.major &&
minver > pkg.maxClassVersion.minor)) {
return "large";
}
return null; // OK
}
void readConstantPool() throws IOException {
int length = in.readUnsignedShort();
//System.err.println("reading CP, length="+length);
int[] fixups = new int[length*4];
int fptr = 0;
Entry[] cpMap = new Entry[length];
cpMap[0] = null;
for (int i = 1; i < length; i++) {
//System.err.println("reading CP elt, i="+i);
int tag = in.readByte();
switch (tag) {
case CONSTANT_Utf8:
cpMap[i] = ConstantPool.getUtf8Entry(in.readUTF());
break;
case CONSTANT_Integer:
{
cpMap[i] = ConstantPool.getLiteralEntry(in.readInt());
}
break;
case CONSTANT_Float:
{
cpMap[i] = ConstantPool.getLiteralEntry(in.readFloat());
}
break;
case CONSTANT_Long:
{
cpMap[i] = ConstantPool.getLiteralEntry(in.readLong());
cpMap[++i] = null;
}
break;
case CONSTANT_Double:
{
cpMap[i] = ConstantPool.getLiteralEntry(in.readDouble());
cpMap[++i] = null;
}
break;
// just read the refs; do not attempt to resolve while reading
case CONSTANT_Class:
case CONSTANT_String:
case CONSTANT_MethodType:
fixups[fptr++] = i;
fixups[fptr++] = tag;
fixups[fptr++] = in.readUnsignedShort();
fixups[fptr++] = -1; // empty ref2
break;
case CONSTANT_Fieldref:
case CONSTANT_Methodref:
case CONSTANT_InterfaceMethodref:
case CONSTANT_NameandType:
fixups[fptr++] = i;
fixups[fptr++] = tag;
fixups[fptr++] = in.readUnsignedShort();
fixups[fptr++] = in.readUnsignedShort();
break;
case CONSTANT_InvokeDynamic:
fixups[fptr++] = i;
fixups[fptr++] = tag;
fixups[fptr++] = -1 ^ in.readUnsignedShort(); // not a ref
fixups[fptr++] = in.readUnsignedShort();
break;
case CONSTANT_MethodHandle:
fixups[fptr++] = i;
fixups[fptr++] = tag;
fixups[fptr++] = -1 ^ in.readUnsignedByte();
fixups[fptr++] = in.readUnsignedShort();
break;
default:
throw new ClassFormatException("Bad constant pool tag " +
tag + " in File: " + cls.file.nameString +
" at pos: " + inPos);
}
}
constantPoolLimit = inPos;
// Fix up refs, which might be out of order.
while (fptr > 0) {
if (verbose > 3)
Utils.log.fine("CP fixups ["+fptr/4+"]");
int flimit = fptr;
fptr = 0;
for (int fi = 0; fi < flimit; ) {
int cpi = fixups[fi++];
int tag = fixups[fi++];
int ref = fixups[fi++];
int ref2 = fixups[fi++];
if (verbose > 3)
Utils.log.fine(" cp["+cpi+"] = "+ConstantPool.tagName(tag)+"{"+ref+","+ref2+"}");
if (ref >= 0 && cpMap[ref] == null || ref2 >= 0 && cpMap[ref2] == null) {
// Defer.
fixups[fptr++] = cpi;
fixups[fptr++] = tag;
fixups[fptr++] = ref;
fixups[fptr++] = ref2;
continue;
}
switch (tag) {
case CONSTANT_Class:
cpMap[cpi] = ConstantPool.getClassEntry(cpMap[ref].stringValue());
break;
case CONSTANT_String:
cpMap[cpi] = ConstantPool.getStringEntry(cpMap[ref].stringValue());
break;
case CONSTANT_Fieldref:
case CONSTANT_Methodref:
case CONSTANT_InterfaceMethodref:
ClassEntry mclass = (ClassEntry) checkTag(cpMap[ref], CONSTANT_Class);
DescriptorEntry mdescr = (DescriptorEntry) checkTag(cpMap[ref2], CONSTANT_NameandType);
cpMap[cpi] = ConstantPool.getMemberEntry((byte)tag, mclass, mdescr);
break;
case CONSTANT_NameandType:
Utf8Entry mname = (Utf8Entry) checkTag(cpMap[ref], CONSTANT_Utf8);
Utf8Entry mtype = (Utf8Entry) checkTag(cpMap[ref2], CONSTANT_Signature);
cpMap[cpi] = ConstantPool.getDescriptorEntry(mname, mtype);
break;
case CONSTANT_MethodType:
cpMap[cpi] = ConstantPool.getMethodTypeEntry((Utf8Entry) checkTag(cpMap[ref], CONSTANT_Signature));
break;
case CONSTANT_MethodHandle:
byte refKind = (byte)(-1 ^ ref);
MemberEntry memRef = (MemberEntry) checkTag(cpMap[ref2], CONSTANT_AnyMember);
cpMap[cpi] = ConstantPool.getMethodHandleEntry(refKind, memRef);
break;
case CONSTANT_InvokeDynamic:
DescriptorEntry idescr = (DescriptorEntry) checkTag(cpMap[ref2], CONSTANT_NameandType);
cpMap[cpi] = new UnresolvedEntry((byte)tag, (-1 ^ ref), idescr);
// Note that ref must be resolved later, using the BootstrapMethods attribute.
break;
default:
assert(false);
}
}
assert(fptr < flimit); // Must make progress.
}
cls.cpMap = cpMap;
}
private /*non-static*/
class UnresolvedEntry extends Entry {
final Object[] refsOrIndexes;
UnresolvedEntry(byte tag, Object... refsOrIndexes) {
super(tag);
this.refsOrIndexes = refsOrIndexes;
ClassReader.this.haveUnresolvedEntry = true;
}
Entry resolve() {
Class cls = ClassReader.this.cls;
Entry res;
switch (tag) {
case CONSTANT_InvokeDynamic:
BootstrapMethodEntry iboots = cls.bootstrapMethods.get((Integer) refsOrIndexes[0]);
DescriptorEntry idescr = (DescriptorEntry) refsOrIndexes[1];
res = ConstantPool.getInvokeDynamicEntry(iboots, idescr);
break;
default:
throw new AssertionError();
}
return res;
}
private void unresolved() { throw new RuntimeException("unresolved entry has no string"); }
public int compareTo(Object x) { unresolved(); return 0; }
public boolean equals(Object x) { unresolved(); return false; }
protected int computeValueHash() { unresolved(); return 0; }
public String stringValue() { unresolved(); return toString(); }
public String toString() { return "(unresolved "+ConstantPool.tagName(tag)+")"; }
}
boolean haveUnresolvedEntry;
private void fixUnresolvedEntries() {
if (!haveUnresolvedEntry) return;
Entry[] cpMap = cls.getCPMap();
for (int i = 0; i < cpMap.length; i++) {
Entry e = cpMap[i];
if (e instanceof UnresolvedEntry) {
cpMap[i] = e = ((UnresolvedEntry)e).resolve();
assert(!(e instanceof UnresolvedEntry));
}
}
haveUnresolvedEntry = false;
}
void readHeader() throws IOException {
cls.flags = readUnsignedShort();
cls.thisClass = readClassRef();
cls.superClass = readClassRefOrNull();
int ni = readUnsignedShort();
cls.interfaces = new ClassEntry[ni];
for (int i = 0; i < ni; i++) {
cls.interfaces[i] = readClassRef();
}
}
void readMembers(boolean doMethods) throws IOException {
int nm = readUnsignedShort();
for (int i = 0; i < nm; i++) {
readMember(doMethods);
}
}
void readMember(boolean doMethod) throws IOException {
int mflags = readUnsignedShort();
Utf8Entry mname = readUtf8Ref();
SignatureEntry mtype = readSignatureRef();
DescriptorEntry descr = ConstantPool.getDescriptorEntry(mname, mtype);
Class.Member m;
if (!doMethod)
m = cls.new Field(mflags, descr);
else
m = cls.new Method(mflags, descr);
readAttributes(!doMethod ? ATTR_CONTEXT_FIELD : ATTR_CONTEXT_METHOD,
m);
}
void readAttributes(int ctype, Attribute.Holder h) throws IOException {
int na = readUnsignedShort();
if (na == 0) return; // nothing to do here
if (verbose > 3)
Utils.log.fine("readAttributes "+h+" ["+na+"]");
for (int i = 0; i < na; i++) {
String name = readUtf8Ref().stringValue();
int length = readInt();
// See if there is a special command that applies.
if (attrCommands != null) {
Attribute.Layout lkey = Attribute.keyForLookup(ctype, name);
String cmd = attrCommands.get(lkey);
if (cmd != null) {
switch (cmd) {
case "pass":
String message1 = "passing attribute bitwise in " + h;
throw new Attribute.FormatException(message1, ctype, name, cmd);
case "error":
String message2 = "attribute not allowed in " + h;
throw new Attribute.FormatException(message2, ctype, name, cmd);
case "strip":
skip(length, name + " attribute in " + h);
continue;
}
}
}
// Find canonical instance of the requested attribute.
Attribute a = Attribute.lookup(Package.attrDefs, ctype, name);
if (verbose > 4 && a != null)
Utils.log.fine("pkg_attribute_lookup "+name+" = "+a);
if (a == null) {
a = Attribute.lookup(this.attrDefs, ctype, name);
if (verbose > 4 && a != null)
Utils.log.fine("this "+name+" = "+a);
}
if (a == null) {
a = Attribute.lookup(null, ctype, name);
if (verbose > 4 && a != null)
Utils.log.fine("null_attribute_lookup "+name+" = "+a);
}
if (a == null && length == 0) {
// Any zero-length attr is "known"...
// We can assume an empty attr. has an empty layout.
// Handles markers like Enum, Bridge, Synthetic, Deprecated.
a = Attribute.find(ctype, name, "");
}
boolean isStackMap = (ctype == ATTR_CONTEXT_CODE
&& (name.equals("StackMap") ||
name.equals("StackMapX")));
if (isStackMap) {
// Known attribute but with a corner case format, "pass" it.
Code code = (Code) h;
final int TOO_BIG = 0x10000;
if (code.max_stack >= TOO_BIG ||
code.max_locals >= TOO_BIG ||
code.getLength() >= TOO_BIG ||
name.endsWith("X")) {
// No, we don't really know what to do with this one.
// Do not compress the rare and strange "u4" and "X" cases.
a = null;
}
}
if (a == null) {
if (isStackMap) {
// Known attribute but w/o a format; pass it.
String message = "unsupported StackMap variant in "+h;
throw new Attribute.FormatException(message, ctype, name,
"pass");
} else if ("strip".equals(unknownAttrCommand)) {
// Skip the unknown attribute.
skip(length, "unknown "+name+" attribute in "+h);
continue;
} else {
String message = " is unknown attribute in class " + h;
throw new Attribute.FormatException(message, ctype, name,
unknownAttrCommand);
}
}
long pos0 = inPos; // in case we want to check it
if (a.layout() == Package.attrCodeEmpty) {
// These are hardwired.
Class.Method m = (Class.Method) h;
m.code = new Code(m);
try {
readCode(m.code);
} catch (Instruction.FormatException iie) {
String message = iie.getMessage() + " in " + h;
throw new ClassReader.ClassFormatException(message, iie);
}
assert(length == inPos - pos0);
// Keep empty attribute a...
} else if (a.layout() == Package.attrBootstrapMethodsEmpty) {
assert(h == cls);
readBootstrapMethods(cls);
assert(length == inPos - pos0);
// Delete the attribute; it is logically part of the constant pool.
continue;
} else if (a.layout() == Package.attrInnerClassesEmpty) {
// These are hardwired also.
assert(h == cls);
readInnerClasses(cls);
assert(length == inPos - pos0);
// Keep empty attribute a...
} else if (length > 0) {
byte[] bytes = new byte[length];
in.readFully(bytes);
a = a.addContent(bytes);
}
if (a.size() == 0 && !a.layout().isEmpty()) {
throw new ClassFormatException(name +
": attribute length cannot be zero, in " + h);
}
h.addAttribute(a);
if (verbose > 2)
Utils.log.fine("read "+a);
}
}
void readCode(Code code) throws IOException {
code.max_stack = readUnsignedShort();
code.max_locals = readUnsignedShort();
code.bytes = new byte[readInt()];
in.readFully(code.bytes);
Entry[] cpMap = cls.getCPMap();
Instruction.opcodeChecker(code.bytes, cpMap, this.cls.version);
int nh = readUnsignedShort();
code.setHandlerCount(nh);
for (int i = 0; i < nh; i++) {
code.handler_start[i] = readUnsignedShort();
code.handler_end[i] = readUnsignedShort();
code.handler_catch[i] = readUnsignedShort();
code.handler_class[i] = readClassRefOrNull();
}
readAttributes(ATTR_CONTEXT_CODE, code);
}
void readBootstrapMethods(Class cls) throws IOException {
BootstrapMethodEntry[] bsms = new BootstrapMethodEntry[readUnsignedShort()];
for (int i = 0; i < bsms.length; i++) {
MethodHandleEntry bsmRef = (MethodHandleEntry) readRef(CONSTANT_MethodHandle);
Entry[] argRefs = new Entry[readUnsignedShort()];
for (int j = 0; j < argRefs.length; j++) {
argRefs[j] = readRef(CONSTANT_LoadableValue);
}
bsms[i] = ConstantPool.getBootstrapMethodEntry(bsmRef, argRefs);
}
cls.setBootstrapMethods(Arrays.asList(bsms));
}
void readInnerClasses(Class cls) throws IOException {
int nc = readUnsignedShort();
ArrayList<InnerClass> ics = new ArrayList<>(nc);
for (int i = 0; i < nc; i++) {
InnerClass ic =
new InnerClass(readClassRef(),
readClassRefOrNull(),
(Utf8Entry)readRefOrNull(CONSTANT_Utf8),
readUnsignedShort());
ics.add(ic);
}
cls.innerClasses = ics; // set directly; do not use setInnerClasses.
// (Later, ics may be transferred to the pkg.)
}
static class ClassFormatException extends IOException {
@java.io.Serial
private static final long serialVersionUID = -3564121733989501833L;
public ClassFormatException(String message) {
super(message);
}
public ClassFormatException(String message, Throwable cause) {
super(message, cause);
}
}
}

View file

@ -1,317 +0,0 @@
/*
* Copyright (c) 2001, 2012, 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 com.sun.java.util.jar.pack.ConstantPool.Entry;
import com.sun.java.util.jar.pack.ConstantPool.Index;
import com.sun.java.util.jar.pack.ConstantPool.NumberEntry;
import com.sun.java.util.jar.pack.ConstantPool.MethodHandleEntry;
import com.sun.java.util.jar.pack.ConstantPool.BootstrapMethodEntry;
import com.sun.java.util.jar.pack.Package.Class;
import com.sun.java.util.jar.pack.Package.InnerClass;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.List;
import static com.sun.java.util.jar.pack.Constants.*;
/**
* Writer for a class file that is incorporated into a package.
* @author John Rose
*/
class ClassWriter {
int verbose;
Package pkg;
Class cls;
DataOutputStream out;
Index cpIndex;
Index bsmIndex;
ClassWriter(Class cls, OutputStream out) throws IOException {
this.pkg = cls.getPackage();
this.cls = cls;
this.verbose = pkg.verbose;
this.out = new DataOutputStream(new BufferedOutputStream(out));
this.cpIndex = ConstantPool.makeIndex(cls.toString(), cls.getCPMap());
this.cpIndex.flattenSigs = true;
if (cls.hasBootstrapMethods()) {
this.bsmIndex = ConstantPool.makeIndex(cpIndex.debugName+".BootstrapMethods",
cls.getBootstrapMethodMap());
}
if (verbose > 1)
Utils.log.fine("local CP="+(verbose > 2 ? cpIndex.dumpString() : cpIndex.toString()));
}
private void writeShort(int x) throws IOException {
out.writeShort(x);
}
private void writeInt(int x) throws IOException {
out.writeInt(x);
}
/** Write a 2-byte int representing a CP entry, using the local cpIndex. */
private void writeRef(Entry e) throws IOException {
writeRef(e, cpIndex);
}
/** Write a 2-byte int representing a CP entry, using the given cpIndex. */
private void writeRef(Entry e, Index cpIndex) throws IOException {
int i = (e == null) ? 0 : cpIndex.indexOf(e);
writeShort(i);
}
void write() throws IOException {
boolean ok = false;
try {
if (verbose > 1) Utils.log.fine("...writing "+cls);
writeMagicNumbers();
writeConstantPool();
writeHeader();
writeMembers(false); // fields
writeMembers(true); // methods
writeAttributes(ATTR_CONTEXT_CLASS, cls);
/* Closing here will cause all the underlying
streams to close, Causing the jar stream
to close prematurely, instead we just flush.
out.close();
*/
out.flush();
ok = true;
} finally {
if (!ok) {
Utils.log.warning("Error on output of "+cls);
}
}
}
void writeMagicNumbers() throws IOException {
writeInt(cls.magic);
writeShort(cls.version.minor);
writeShort(cls.version.major);
}
void writeConstantPool() throws IOException {
Entry[] cpMap = cls.cpMap;
writeShort(cpMap.length);
for (int i = 0; i < cpMap.length; i++) {
Entry e = cpMap[i];
assert((e == null) == (i == 0 || cpMap[i-1] != null && cpMap[i-1].isDoubleWord()));
if (e == null) continue;
byte tag = e.getTag();
if (verbose > 2) Utils.log.fine(" CP["+i+"] = "+e);
out.write(tag);
switch (tag) {
case CONSTANT_Signature:
throw new AssertionError("CP should have Signatures remapped to Utf8");
case CONSTANT_Utf8:
out.writeUTF(e.stringValue());
break;
case CONSTANT_Integer:
out.writeInt(((NumberEntry)e).numberValue().intValue());
break;
case CONSTANT_Float:
float fval = ((NumberEntry)e).numberValue().floatValue();
out.writeInt(Float.floatToRawIntBits(fval));
break;
case CONSTANT_Long:
out.writeLong(((NumberEntry)e).numberValue().longValue());
break;
case CONSTANT_Double:
double dval = ((NumberEntry)e).numberValue().doubleValue();
out.writeLong(Double.doubleToRawLongBits(dval));
break;
case CONSTANT_Class:
case CONSTANT_String:
case CONSTANT_MethodType:
writeRef(e.getRef(0));
break;
case CONSTANT_MethodHandle:
MethodHandleEntry mhe = (MethodHandleEntry) e;
out.writeByte(mhe.refKind);
writeRef(mhe.getRef(0));
break;
case CONSTANT_Fieldref:
case CONSTANT_Methodref:
case CONSTANT_InterfaceMethodref:
case CONSTANT_NameandType:
writeRef(e.getRef(0));
writeRef(e.getRef(1));
break;
case CONSTANT_InvokeDynamic:
writeRef(e.getRef(0), bsmIndex);
writeRef(e.getRef(1));
break;
case CONSTANT_BootstrapMethod:
throw new AssertionError("CP should have BootstrapMethods moved to side-table");
default:
throw new IOException("Bad constant pool tag "+tag);
}
}
}
void writeHeader() throws IOException {
writeShort(cls.flags);
writeRef(cls.thisClass);
writeRef(cls.superClass);
writeShort(cls.interfaces.length);
for (int i = 0; i < cls.interfaces.length; i++) {
writeRef(cls.interfaces[i]);
}
}
void writeMembers(boolean doMethods) throws IOException {
List<? extends Class.Member> mems;
if (!doMethods)
mems = cls.getFields();
else
mems = cls.getMethods();
writeShort(mems.size());
for (Class.Member m : mems) {
writeMember(m, doMethods);
}
}
void writeMember(Class.Member m, boolean doMethod) throws IOException {
if (verbose > 2) Utils.log.fine("writeMember "+m);
writeShort(m.flags);
writeRef(m.getDescriptor().nameRef);
writeRef(m.getDescriptor().typeRef);
writeAttributes(!doMethod ? ATTR_CONTEXT_FIELD : ATTR_CONTEXT_METHOD,
m);
}
private void reorderBSMandICS(Attribute.Holder h) {
Attribute bsmAttr = h.getAttribute(Package.attrBootstrapMethodsEmpty);
if (bsmAttr == null) return;
Attribute icsAttr = h.getAttribute(Package.attrInnerClassesEmpty);
if (icsAttr == null) return;
int bsmidx = h.attributes.indexOf(bsmAttr);
int icsidx = h.attributes.indexOf(icsAttr);
if (bsmidx > icsidx) {
h.attributes.remove(bsmAttr);
h.attributes.add(icsidx, bsmAttr);
}
return;
}
// handy buffer for collecting attrs
ByteArrayOutputStream buf = new ByteArrayOutputStream();
DataOutputStream bufOut = new DataOutputStream(buf);
void writeAttributes(int ctype, Attribute.Holder h) throws IOException {
if (h.attributes == null) {
writeShort(0); // attribute size
return;
}
// there may be cases if an InnerClass attribute is explicit, then the
// ordering could be wrong, fix the ordering before we write it out.
if (h instanceof Package.Class)
reorderBSMandICS(h);
writeShort(h.attributes.size());
for (Attribute a : h.attributes) {
a.finishRefs(cpIndex);
writeRef(a.getNameRef());
if (a.layout() == Package.attrCodeEmpty ||
a.layout() == Package.attrBootstrapMethodsEmpty ||
a.layout() == Package.attrInnerClassesEmpty) {
// These are hardwired.
DataOutputStream savedOut = out;
assert(out != bufOut);
buf.reset();
out = bufOut;
if ("Code".equals(a.name())) {
Class.Method m = (Class.Method) h;
writeCode(m.code);
} else if ("BootstrapMethods".equals(a.name())) {
assert(h == cls);
writeBootstrapMethods(cls);
} else if ("InnerClasses".equals(a.name())) {
assert(h == cls);
writeInnerClasses(cls);
} else {
throw new AssertionError();
}
out = savedOut;
if (verbose > 2)
Utils.log.fine("Attribute "+a.name()+" ["+buf.size()+"]");
writeInt(buf.size());
buf.writeTo(out);
} else {
if (verbose > 2)
Utils.log.fine("Attribute "+a.name()+" ["+a.size()+"]");
writeInt(a.size());
out.write(a.bytes());
}
}
}
void writeCode(Code code) throws IOException {
code.finishRefs(cpIndex);
writeShort(code.max_stack);
writeShort(code.max_locals);
writeInt(code.bytes.length);
out.write(code.bytes);
int nh = code.getHandlerCount();
writeShort(nh);
for (int i = 0; i < nh; i++) {
writeShort(code.handler_start[i]);
writeShort(code.handler_end[i]);
writeShort(code.handler_catch[i]);
writeRef(code.handler_class[i]);
}
writeAttributes(ATTR_CONTEXT_CODE, code);
}
void writeBootstrapMethods(Class cls) throws IOException {
List<BootstrapMethodEntry> bsms = cls.getBootstrapMethods();
writeShort(bsms.size());
for (BootstrapMethodEntry e : bsms) {
writeRef(e.bsmRef);
writeShort(e.argRefs.length);
for (Entry argRef : e.argRefs) {
writeRef(argRef);
}
}
}
void writeInnerClasses(Class cls) throws IOException {
List<InnerClass> ics = cls.getInnerClasses();
writeShort(ics.size());
for (InnerClass ic : ics) {
writeRef(ic.thisClass);
writeRef(ic.outerClass);
writeRef(ic.name);
writeShort(ic.flags);
}
}
}

View file

@ -1,398 +0,0 @@
/*
* Copyright (c) 2001, 2013, 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 com.sun.java.util.jar.pack.Package.Class;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.Collection;
import static com.sun.java.util.jar.pack.Constants.*;
/**
* Represents a chunk of bytecodes.
* @author John Rose
*/
class Code extends Attribute.Holder {
Class.Method m;
public Code(Class.Method m) {
this.m = m;
}
public Class.Method getMethod() {
return m;
}
public Class thisClass() {
return m.thisClass();
}
public Package getPackage() {
return m.thisClass().getPackage();
}
public ConstantPool.Entry[] getCPMap() {
return m.getCPMap();
}
private static final ConstantPool.Entry[] noRefs = ConstantPool.noRefs;
// The following fields are used directly by the ClassReader, etc.
int max_stack;
int max_locals;
ConstantPool.Entry handler_class[] = noRefs;
int handler_start[] = noInts;
int handler_end[] = noInts;
int handler_catch[] = noInts;
byte[] bytes;
Fixups fixups; // reference relocations, if any are required
Object insnMap; // array of instruction boundaries
int getLength() { return bytes.length; }
int getMaxStack() {
return max_stack;
}
void setMaxStack(int ms) {
max_stack = ms;
}
int getMaxNALocals() {
int argsize = m.getArgumentSize();
return max_locals - argsize;
}
void setMaxNALocals(int ml) {
int argsize = m.getArgumentSize();
max_locals = argsize + ml;
}
int getHandlerCount() {
assert(handler_class.length == handler_start.length);
assert(handler_class.length == handler_end.length);
assert(handler_class.length == handler_catch.length);
return handler_class.length;
}
void setHandlerCount(int h) {
if (h > 0) {
handler_class = new ConstantPool.Entry[h];
handler_start = new int[h];
handler_end = new int[h];
handler_catch = new int[h];
// caller must fill these in ASAP
}
}
void setBytes(byte[] bytes) {
this.bytes = bytes;
if (fixups != null)
fixups.setBytes(bytes);
}
void setInstructionMap(int[] insnMap, int mapLen) {
//int[] oldMap = null;
//assert((oldMap = getInstructionMap()) != null);
this.insnMap = allocateInstructionMap(insnMap, mapLen);
//assert(Arrays.equals(oldMap, getInstructionMap()));
}
void setInstructionMap(int[] insnMap) {
setInstructionMap(insnMap, insnMap.length);
}
int[] getInstructionMap() {
return expandInstructionMap(getInsnMap());
}
void addFixups(Collection<Fixups.Fixup> moreFixups) {
if (fixups == null) {
fixups = new Fixups(bytes);
}
assert(fixups.getBytes() == bytes);
fixups.addAll(moreFixups);
}
public void trimToSize() {
if (fixups != null) {
fixups.trimToSize();
if (fixups.size() == 0)
fixups = null;
}
super.trimToSize();
}
protected void visitRefs(int mode, Collection<ConstantPool.Entry> refs) {
int verbose = getPackage().verbose;
if (verbose > 2)
System.out.println("Reference scan "+this);
refs.addAll(Arrays.asList(handler_class));
if (fixups != null) {
fixups.visitRefs(refs);
} else {
// References (to a local cpMap) are embedded in the bytes.
ConstantPool.Entry[] cpMap = getCPMap();
for (Instruction i = instructionAt(0); i != null; i = i.next()) {
if (verbose > 4)
System.out.println(i);
int cpref = i.getCPIndex();
if (cpref >= 0) {
refs.add(cpMap[cpref]);
}
}
}
// Handle attribute list:
super.visitRefs(mode, refs);
}
// Since bytecodes are the single largest contributor to
// package size, it's worth a little bit of trouble
// to reduce the per-bytecode memory footprint.
// In the current scheme, half of the bulk of these arrays
// due to bytes, and half to shorts. (Ints are insignificant.)
// Given an average of 1.8 bytes per instruction, this means
// instruction boundary arrays are about a 75% overhead--tolerable.
// (By using bytes, we get 33% savings over just shorts and ints.
// Using both bytes and shorts gives 66% savings over just ints.)
static final boolean shrinkMaps = true;
private Object allocateInstructionMap(int[] insnMap, int mapLen) {
int PClimit = getLength();
if (shrinkMaps && PClimit <= Byte.MAX_VALUE - Byte.MIN_VALUE) {
byte[] map = new byte[mapLen+1];
for (int i = 0; i < mapLen; i++) {
map[i] = (byte)(insnMap[i] + Byte.MIN_VALUE);
}
map[mapLen] = (byte)(PClimit + Byte.MIN_VALUE);
return map;
} else if (shrinkMaps && PClimit < Short.MAX_VALUE - Short.MIN_VALUE) {
short[] map = new short[mapLen+1];
for (int i = 0; i < mapLen; i++) {
map[i] = (short)(insnMap[i] + Short.MIN_VALUE);
}
map[mapLen] = (short)(PClimit + Short.MIN_VALUE);
return map;
} else {
int[] map = Arrays.copyOf(insnMap, mapLen + 1);
map[mapLen] = PClimit;
return map;
}
}
private int[] expandInstructionMap(Object map0) {
int[] imap;
if (map0 instanceof byte[]) {
byte[] map = (byte[]) map0;
imap = new int[map.length-1];
for (int i = 0; i < imap.length; i++) {
imap[i] = map[i] - Byte.MIN_VALUE;
}
} else if (map0 instanceof short[]) {
short[] map = (short[]) map0;
imap = new int[map.length-1];
for (int i = 0; i < imap.length; i++) {
imap[i] = map[i] - Byte.MIN_VALUE;
}
} else {
int[] map = (int[]) map0;
imap = Arrays.copyOfRange(map, 0, map.length - 1);
}
return imap;
}
Object getInsnMap() {
// Build a map of instruction boundaries.
if (insnMap != null) {
return insnMap;
}
int[] map = new int[getLength()];
int fillp = 0;
for (Instruction i = instructionAt(0); i != null; i = i.next()) {
map[fillp++] = i.getPC();
}
// Make it byte[], short[], or int[] according to the max BCI.
insnMap = allocateInstructionMap(map, fillp);
//assert(assertBCICodingsOK());
return insnMap;
}
/** Encode the given BCI as an instruction boundary number.
* For completeness, irregular (non-boundary) BCIs are
* encoded compactly immediately after the boundary numbers.
* This encoding is the identity mapping outside 0..length,
* and it is 1-1 everywhere. All by itself this technique
* improved zipped rt.jar compression by 2.6%.
*/
public int encodeBCI(int bci) {
if (bci <= 0 || bci > getLength()) return bci;
Object map0 = getInsnMap();
int i, len;
if (shrinkMaps && map0 instanceof byte[]) {
byte[] map = (byte[]) map0;
len = map.length;
i = Arrays.binarySearch(map, (byte)(bci + Byte.MIN_VALUE));
} else if (shrinkMaps && map0 instanceof short[]) {
short[] map = (short[]) map0;
len = map.length;
i = Arrays.binarySearch(map, (short)(bci + Short.MIN_VALUE));
} else {
int[] map = (int[]) map0;
len = map.length;
i = Arrays.binarySearch(map, bci);
}
assert(i != -1);
assert(i != 0);
assert(i != len);
assert(i != -len-1);
return (i >= 0) ? i : len + bci - (-i-1);
}
public int decodeBCI(int bciCode) {
if (bciCode <= 0 || bciCode > getLength()) return bciCode;
Object map0 = getInsnMap();
int i, len;
// len == map.length
// If bciCode < len, result is map[bciCode], the common and fast case.
// Otherwise, let map[i] be the smallest map[*] larger than bci.
// Then, required by the return statement of encodeBCI:
// bciCode == len + bci - i
// Thus:
// bci-i == bciCode-len
// map[i]-adj-i == bciCode-len ; adj in (0..map[i]-map[i-1])
// We can solve this by searching for adjacent entries
// map[i-1], map[i] such that:
// map[i-1]-(i-1) <= bciCode-len < map[i]-i
// This can be approximated by searching map[i] for bciCode and then
// linear searching backward. Given the right i, we then have:
// bci == bciCode-len + i
// This linear search is at its worst case for indexes in the beginning
// of a large method, but it's not clear that this is a problem in
// practice, since BCIs are usually on instruction boundaries.
if (shrinkMaps && map0 instanceof byte[]) {
byte[] map = (byte[]) map0;
len = map.length;
if (bciCode < len)
return map[bciCode] - Byte.MIN_VALUE;
i = Arrays.binarySearch(map, (byte)(bciCode + Byte.MIN_VALUE));
if (i < 0) i = -i-1;
int key = bciCode-len + Byte.MIN_VALUE;
for (;; i--) {
if (map[i-1]-(i-1) <= key) break;
}
} else if (shrinkMaps && map0 instanceof short[]) {
short[] map = (short[]) map0;
len = map.length;
if (bciCode < len)
return map[bciCode] - Short.MIN_VALUE;
i = Arrays.binarySearch(map, (short)(bciCode + Short.MIN_VALUE));
if (i < 0) i = -i-1;
int key = bciCode-len + Short.MIN_VALUE;
for (;; i--) {
if (map[i-1]-(i-1) <= key) break;
}
} else {
int[] map = (int[]) map0;
len = map.length;
if (bciCode < len)
return map[bciCode];
i = Arrays.binarySearch(map, bciCode);
if (i < 0) i = -i-1;
int key = bciCode-len;
for (;; i--) {
if (map[i-1]-(i-1) <= key) break;
}
}
return bciCode-len + i;
}
public void finishRefs(ConstantPool.Index ix) {
if (fixups != null) {
fixups.finishRefs(ix);
fixups = null;
}
// Code attributes are finished in ClassWriter.writeAttributes.
}
Instruction instructionAt(int pc) {
return Instruction.at(bytes, pc);
}
static boolean flagsRequireCode(int flags) {
// A method's flags force it to have a Code attribute,
// if the flags are neither native nor abstract.
return (flags & (Modifier.NATIVE | Modifier.ABSTRACT)) == 0;
}
public String toString() {
return m+".Code";
}
/// Fetching values from my own array.
public int getInt(int pc) { return Instruction.getInt(bytes, pc); }
public int getShort(int pc) { return Instruction.getShort(bytes, pc); }
public int getByte(int pc) { return Instruction.getByte(bytes, pc); }
void setInt(int pc, int x) { Instruction.setInt(bytes, pc, x); }
void setShort(int pc, int x) { Instruction.setShort(bytes, pc, x); }
void setByte(int pc, int x) { Instruction.setByte(bytes, pc, x); }
/* TEST CODE ONLY
private boolean assertBCICodingsOK() {
boolean ok = true;
int len = java.lang.reflect.Array.getLength(insnMap);
int base = 0;
if (insnMap.getClass().getComponentType() == Byte.TYPE)
base = Byte.MIN_VALUE;
if (insnMap.getClass().getComponentType() == Short.TYPE)
base = Short.MIN_VALUE;
for (int i = -1, imax = getLength()+1; i <= imax; i++) {
int bci = i;
int enc = Math.min(-999, bci-1);
int dec = enc;
try {
enc = encodeBCI(bci);
dec = decodeBCI(enc);
} catch (RuntimeException ee) {
ee.printStackTrace();
}
if (dec == bci) {
//System.out.println("BCI="+bci+(enc<len?"":" ")+" enc="+enc);
continue;
}
if (ok) {
for (int q = 0; q <= 1; q++) {
StringBuffer sb = new StringBuffer();
sb.append("bci "+(q==0?"map":"del")+"["+len+"] = {");
for (int j = 0; j < len; j++) {
int mapi = ((Number)java.lang.reflect.Array.get(insnMap, j)).intValue() - base;
mapi -= j*q;
sb.append(" "+mapi);
}
sb.append(" }");
System.out.println("*** "+sb);
}
}
System.out.println("*** BCI="+bci+" enc="+enc+" dec="+dec);
ok = false;
}
return ok;
}
//*/
}

View file

@ -1,906 +0,0 @@
/*
* Copyright (c) 2001, 2011, 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.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;
import static com.sun.java.util.jar.pack.Constants.*;
/**
* Define the conversions between sequences of small integers and raw bytes.
* This is a schema of encodings which incorporates varying lengths,
* varying degrees of length variability, and varying amounts of signed-ness.
* @author John Rose
*/
class Coding implements Comparable<Coding>, CodingMethod, Histogram.BitMetric {
/*
Coding schema for single integers, parameterized by (B,H,S):
Let B in [1,5], H in [1,256], S in [0,3].
(S limit is arbitrary. B follows the 32-bit limit. H is byte size.)
A given (B,H,S) code varies in length from 1 to B bytes.
The 256 values a byte may take on are divided into L=(256-H) and H
values, with all the H values larger than the L values.
(That is, the L values are [0,L) and the H are [L,256).)
The last byte is always either the B-th byte, a byte with "L value"
(<L), or both. There is no other byte that satisfies these conditions.
All bytes before the last always have "H values" (>=L).
Therefore, if L==0, the code always has the full length of B bytes.
The coding then becomes a classic B-byte little-endian unsigned integer.
(Also, if L==128, the high bit of each byte acts signals the presence
of a following byte, up to the maximum length.)
In the unsigned case (S==0), the coding is compact and monotonic
in the ordering of byte sequences defined by appending zero bytes
to pad them to a common length B, reversing them, and ordering them
lexicographically. (This agrees with "little-endian" byte order.)
Therefore, the unsigned value of a byte sequence may be defined as:
<pre>
U(b0) == b0
in [0..L)
or [0..256) if B==1 (**)
U(b0,b1) == b0 + b1*H
in [L..L*(1+H))
or [L..L*(1+H) + H^2) if B==2
U(b0,b1,b2) == b0 + b1*H + b2*H^2
in [L*(1+H)..L*(1+H+H^2))
or [L*(1+H)..L*(1+H+H^2) + H^3) if B==3
U(b[i]: i<n) == Sum[i<n]( b[i] * H^i )
up to L*Sum[i<n]( H^i )
or to L*Sum[i<n]( H^i ) + H^n if n==B
</pre>
(**) If B==1, the values H,L play no role in the coding.
As a convention, we require that any (1,H,S) code must always
encode values less than H. Thus, a simple unsigned byte is coded
specifically by the code (1,256,0).
(Properly speaking, the unsigned case should be parameterized as
S==Infinity. If the schema were regular, the case S==0 would really
denote a numbering in which all coded values are negative.)
If S>0, the unsigned value of a byte sequence is regarded as a binary
integer. If any of the S low-order bits are zero, the corresponding
signed value will be non-negative. If all of the S low-order bits
(S>0) are one, the corresponding signed value will be negative.
The non-negative signed values are compact and monotonically increasing
(from 0) in the ordering of the corresponding unsigned values.
The negative signed values are compact and monotonically decreasing
(from -1) in the ordering of the corresponding unsigned values.
In essence, the low-order S bits function as a collective sign bit
for negative signed numbers, and as a low-order base-(2^S-1) digit
for non-negative signed numbers.
Therefore, the signed value corresponding to an unsigned value is:
<pre>
Sgn(x) == x if S==0
Sgn(x) == (x / 2^S)*(2^S-1) + (x % 2^S), if S>0, (x % 2^S) < 2^S-1
Sgn(x) == -(x / 2^S)-1, if S>0, (x % 2^S) == 2^S-1
</pre>
Finally, the value of a byte sequence, given the coding parameters
(B,H,S), is defined as:
<pre>
V(b[i]: i<n) == Sgn(U(b[i]: i<n))
</pre>
The extremal positive and negative signed value for a given range
of unsigned values may be found by sign-encoding the largest unsigned
value which is not 2^S-1 mod 2^S, and that which is, respectively.
Because B,H,S are variable, this is not a single coding but a schema
of codings. For optimal compression, it is necessary to adaptively
select specific codings to the data being compressed.
For example, if a sequence of values happens never to be negative,
S==0 is the best choice. If the values are equally balanced between
negative and positive, S==1. If negative values are rare, then S>1
is more appropriate.
A (B,H,S) encoding is called a "subrange" if it does not encode
the largest 32-bit value, and if the number R of values it does
encode can be expressed as a positive 32-bit value. (Note that
B=1 implies R<=256, B=2 implies R<=65536, etc.)
A delta version of a given (B,H,S) coding encodes an array of integers
by writing their successive differences in the (B,H,S) coding.
The original integers themselves may be recovered by making a
running accumulation of sum of the differences as they are read.
As a special case, if a (B,H,S) encoding is a subrange, its delta
version will only encode arrays of numbers in the coding's unsigned
range, [0..R-1]. The coding of deltas is still in the normal signed
range, if S!=0. During delta encoding, all subtraction results are
reduced to the signed range, by adding multiples of R. Likewise,
. during encoding, all addition results are reduced to the unsigned range.
This special case for subranges allows the benefits of wraparound
when encoding correlated sequences of very small positive numbers.
*/
// Code-specific limits:
private static int saturate32(long x) {
if (x > Integer.MAX_VALUE) return Integer.MAX_VALUE;
if (x < Integer.MIN_VALUE) return Integer.MIN_VALUE;
return (int)x;
}
private static long codeRangeLong(int B, int H) {
return codeRangeLong(B, H, B);
}
private static long codeRangeLong(int B, int H, int nMax) {
// Code range for a all (B,H) codes of length <=nMax (<=B).
// n < B: L*Sum[i<n]( H^i )
// n == B: L*Sum[i<B]( H^i ) + H^B
assert(nMax >= 0 && nMax <= B);
assert(B >= 1 && B <= 5);
assert(H >= 1 && H <= 256);
if (nMax == 0) return 0; // no codes of zero length
if (B == 1) return H; // special case; see (**) above
int L = 256-H;
long sum = 0;
long H_i = 1;
for (int n = 1; n <= nMax; n++) {
sum += H_i;
H_i *= H;
}
sum *= L;
if (nMax == B)
sum += H_i;
return sum;
}
/** Largest int representable by (B,H,S) in up to nMax bytes. */
public static int codeMax(int B, int H, int S, int nMax) {
//assert(S >= 0 && S <= S_MAX);
long range = codeRangeLong(B, H, nMax);
if (range == 0)
return -1; // degenerate max value for empty set of codes
if (S == 0 || range >= (long)1<<32)
return saturate32(range-1);
long maxPos = range-1;
while (isNegativeCode(maxPos, S)) {
--maxPos;
}
if (maxPos < 0) return -1; // No positive codings at all.
int smax = decodeSign32(maxPos, S);
// check for 32-bit wraparound:
if (smax < 0)
return Integer.MAX_VALUE;
return smax;
}
/** Smallest int representable by (B,H,S) in up to nMax bytes.
Returns Integer.MIN_VALUE if 32-bit wraparound covers
the entire negative range.
*/
public static int codeMin(int B, int H, int S, int nMax) {
//assert(S >= 0 && S <= S_MAX);
long range = codeRangeLong(B, H, nMax);
if (range >= (long)1<<32 && nMax == B) {
// Can code negative values via 32-bit wraparound.
return Integer.MIN_VALUE;
}
if (S == 0) {
return 0;
}
long maxNeg = range-1;
while (!isNegativeCode(maxNeg, S))
--maxNeg;
if (maxNeg < 0) return 0; // No negative codings at all.
return decodeSign32(maxNeg, S);
}
// Some of the arithmetic below is on unsigned 32-bit integers.
// These must be represented in Java as longs in the range [0..2^32-1].
// The conversion to a signed int is just the Java cast (int), but
// the conversion to an unsigned int is the following little method:
private static long toUnsigned32(int sx) {
return ((long)sx << 32) >>> 32;
}
// Sign encoding:
private static boolean isNegativeCode(long ux, int S) {
assert(S > 0);
assert(ux >= -1); // can be out of 32-bit range; who cares
int Smask = (1<<S)-1;
return (((int)ux+1) & Smask) == 0;
}
private static boolean hasNegativeCode(int sx, int S) {
assert(S > 0);
// If S>=2 very low negatives are coded by 32-bit-wrapped positives.
// The lowest negative representable by a negative coding is
// ~(umax32 >> S), and the next lower number is coded by wrapping
// the highest positive:
// CodePos(umax32-1) -> (umax32-1)-((umax32-1)>>S)
// which simplifies to ~(umax32 >> S)-1.
return (0 > sx) && (sx >= ~(-1>>>S));
}
private static int decodeSign32(long ux, int S) {
assert(ux == toUnsigned32((int)ux)) // must be unsigned 32-bit number
: (Long.toHexString(ux));
if (S == 0) {
return (int) ux; // cast to signed int
}
int sx;
if (isNegativeCode(ux, S)) {
// Sgn(x) == -(x / 2^S)-1
sx = ~((int)ux >>> S);
} else {
// Sgn(x) == (x / 2^S)*(2^S-1) + (x % 2^S)
sx = (int)ux - ((int)ux >>> S);
}
// Assert special case of S==1:
assert(!(S == 1) || sx == (((int)ux >>> 1) ^ -((int)ux & 1)));
return sx;
}
private static long encodeSign32(int sx, int S) {
if (S == 0) {
return toUnsigned32(sx); // unsigned 32-bit int
}
int Smask = (1<<S)-1;
long ux;
if (!hasNegativeCode(sx, S)) {
// InvSgn(sx) = (sx / (2^S-1))*2^S + (sx % (2^S-1))
ux = sx + (toUnsigned32(sx) / Smask);
} else {
// InvSgn(sx) = (-sx-1)*2^S + (2^S-1)
ux = (-sx << S) - 1;
}
ux = toUnsigned32((int)ux);
assert(sx == decodeSign32(ux, S))
: (Long.toHexString(ux)+" -> "+
Integer.toHexString(sx)+" != "+
Integer.toHexString(decodeSign32(ux, S)));
return ux;
}
// Top-level coding of single integers:
public static void writeInt(byte[] out, int[] outpos, int sx, int B, int H, int S) {
long ux = encodeSign32(sx, S);
assert(ux == toUnsigned32((int)ux));
assert(ux < codeRangeLong(B, H))
: Long.toHexString(ux);
int L = 256-H;
long sum = ux;
int pos = outpos[0];
for (int i = 0; i < B-1; i++) {
if (sum < L)
break;
sum -= L;
int b_i = (int)( L + (sum % H) );
sum /= H;
out[pos++] = (byte)b_i;
}
out[pos++] = (byte)sum;
// Report number of bytes written by updating outpos[0]:
outpos[0] = pos;
// Check right away for mis-coding.
//assert(sx == readInt(out, new int[1], B, H, S));
}
public static int readInt(byte[] in, int[] inpos, int B, int H, int S) {
// U(b[i]: i<n) == Sum[i<n]( b[i] * H^i )
int L = 256-H;
long sum = 0;
long H_i = 1;
int pos = inpos[0];
for (int i = 0; i < B; i++) {
int b_i = in[pos++] & 0xFF;
sum += b_i*H_i;
H_i *= H;
if (b_i < L) break;
}
//assert(sum >= 0 && sum < codeRangeLong(B, H));
// Report number of bytes read by updating inpos[0]:
inpos[0] = pos;
return decodeSign32(sum, S);
}
// The Stream version doesn't fetch a byte unless it is needed for coding.
public static int readIntFrom(InputStream in, int B, int H, int S) throws IOException {
// U(b[i]: i<n) == Sum[i<n]( b[i] * H^i )
int L = 256-H;
long sum = 0;
long H_i = 1;
for (int i = 0; i < B; i++) {
int b_i = in.read();
if (b_i < 0) throw new RuntimeException("unexpected EOF");
sum += b_i*H_i;
H_i *= H;
if (b_i < L) break;
}
assert(sum >= 0 && sum < codeRangeLong(B, H));
return decodeSign32(sum, S);
}
public static final int B_MAX = 5; /* B: [1,5] */
public static final int H_MAX = 256; /* H: [1,256] */
public static final int S_MAX = 2; /* S: [0,2] */
// END OF STATICS.
private final int B; /*1..5*/ // # bytes (1..5)
private final int H; /*1..256*/ // # codes requiring a higher byte
private final int L; /*0..255*/ // # codes requiring a higher byte
private final int S; /*0..3*/ // # low-order bits representing sign
private final int del; /*0..2*/ // type of delta encoding (0 == none)
private final int min; // smallest representable value
private final int max; // largest representable value
private final int umin; // smallest representable uns. value
private final int umax; // largest representable uns. value
private final int[] byteMin; // smallest repr. value, given # bytes
private final int[] byteMax; // largest repr. value, given # bytes
private Coding(int B, int H, int S) {
this(B, H, S, 0);
}
private Coding(int B, int H, int S, int del) {
this.B = B;
this.H = H;
this.L = 256-H;
this.S = S;
this.del = del;
this.min = codeMin(B, H, S, B);
this.max = codeMax(B, H, S, B);
this.umin = codeMin(B, H, 0, B);
this.umax = codeMax(B, H, 0, B);
this.byteMin = new int[B];
this.byteMax = new int[B];
for (int nMax = 1; nMax <= B; nMax++) {
byteMin[nMax-1] = codeMin(B, H, S, nMax);
byteMax[nMax-1] = codeMax(B, H, S, nMax);
}
}
public boolean equals(Object x) {
if (!(x instanceof Coding)) return false;
Coding that = (Coding) x;
if (this.B != that.B) return false;
if (this.H != that.H) return false;
if (this.S != that.S) return false;
if (this.del != that.del) return false;
return true;
}
public int hashCode() {
return (del<<14)+(S<<11)+(B<<8)+(H<<0);
}
private static Map<Coding, Coding> codeMap;
private static synchronized Coding of(int B, int H, int S, int del) {
if (codeMap == null) codeMap = new HashMap<>();
Coding x0 = new Coding(B, H, S, del);
Coding x1 = codeMap.get(x0);
if (x1 == null) codeMap.put(x0, x1 = x0);
return x1;
}
public static Coding of(int B, int H) {
return of(B, H, 0, 0);
}
public static Coding of(int B, int H, int S) {
return of(B, H, S, 0);
}
public boolean canRepresentValue(int x) {
if (isSubrange())
return canRepresentUnsigned(x);
else
return canRepresentSigned(x);
}
/** Can this coding represent a single value, possibly a delta?
* This ignores the D property. That is, for delta codings,
* this tests whether a delta value of 'x' can be coded.
* For signed delta codings which produce unsigned end values,
* use canRepresentUnsigned.
*/
public boolean canRepresentSigned(int x) {
return (x >= min && x <= max);
}
/** Can this coding, apart from its S property,
* represent a single value? (Negative values
* can only be represented via 32-bit overflow,
* so this returns true for negative values
* if isFullRange is true.)
*/
public boolean canRepresentUnsigned(int x) {
return (x >= umin && x <= umax);
}
// object-oriented code/decode
public int readFrom(byte[] in, int[] inpos) {
return readInt(in, inpos, B, H, S);
}
public void writeTo(byte[] out, int[] outpos, int x) {
writeInt(out, outpos, x, B, H, S);
}
// Stream versions
public int readFrom(InputStream in) throws IOException {
return readIntFrom(in, B, H, S);
}
public void writeTo(OutputStream out, int x) throws IOException {
byte[] buf = new byte[B];
int[] pos = new int[1];
writeInt(buf, pos, x, B, H, S);
out.write(buf, 0, pos[0]);
}
// Stream/array versions
public void readArrayFrom(InputStream in, int[] a, int start, int end) throws IOException {
// %%% use byte[] buffer
for (int i = start; i < end; i++)
a[i] = readFrom(in);
for (int dstep = 0; dstep < del; dstep++) {
long state = 0;
for (int i = start; i < end; i++) {
state += a[i];
// Reduce array values to the required range.
if (isSubrange()) {
state = reduceToUnsignedRange(state);
}
a[i] = (int) state;
}
}
}
public void writeArrayTo(OutputStream out, int[] a, int start, int end) throws IOException {
if (end <= start) return;
for (int dstep = 0; dstep < del; dstep++) {
int[] deltas;
if (!isSubrange())
deltas = makeDeltas(a, start, end, 0, 0);
else
deltas = makeDeltas(a, start, end, min, max);
a = deltas;
start = 0;
end = deltas.length;
}
// The following code is a buffered version of this loop:
// for (int i = start; i < end; i++)
// writeTo(out, a[i]);
byte[] buf = new byte[1<<8];
final int bufmax = buf.length-B;
int[] pos = { 0 };
for (int i = start; i < end; ) {
while (pos[0] <= bufmax) {
writeTo(buf, pos, a[i++]);
if (i >= end) break;
}
out.write(buf, 0, pos[0]);
pos[0] = 0;
}
}
/** Tell if the range of this coding (number of distinct
* representable values) can be expressed in 32 bits.
*/
boolean isSubrange() {
return max < Integer.MAX_VALUE
&& ((long)max - (long)min + 1) <= Integer.MAX_VALUE;
}
/** Tell if this coding can represent all 32-bit values.
* Note: Some codings, such as unsigned ones, can be neither
* subranges nor full-range codings.
*/
boolean isFullRange() {
return max == Integer.MAX_VALUE && min == Integer.MIN_VALUE;
}
/** Return the number of values this coding (a subrange) can represent. */
int getRange() {
assert(isSubrange());
return (max - min) + 1; // range includes both min & max
}
Coding setB(int B) { return Coding.of(B, H, S, del); }
Coding setH(int H) { return Coding.of(B, H, S, del); }
Coding setS(int S) { return Coding.of(B, H, S, del); }
Coding setL(int L) { return setH(256-L); }
Coding setD(int del) { return Coding.of(B, H, S, del); }
Coding getDeltaCoding() { return setD(del+1); }
/** Return a coding suitable for representing summed, modulo-reduced values. */
Coding getValueCoding() {
if (isDelta())
return Coding.of(B, H, 0, del-1);
else
return this;
}
/** Reduce the given value to be within this coding's unsigned range,
* by adding or subtracting a multiple of (max-min+1).
*/
int reduceToUnsignedRange(long value) {
if (value == (int)value && canRepresentUnsigned((int)value))
// already in unsigned range
return (int)value;
int range = getRange();
assert(range > 0);
value %= range;
if (value < 0) value += range;
assert(canRepresentUnsigned((int)value));
return (int)value;
}
int reduceToSignedRange(int value) {
if (canRepresentSigned(value))
// already in signed range
return value;
return reduceToSignedRange(value, min, max);
}
static int reduceToSignedRange(int value, int min, int max) {
int range = (max-min+1);
assert(range > 0);
int value0 = value;
value -= min;
if (value < 0 && value0 >= 0) {
// 32-bit overflow, but the next '%=' op needs to be unsigned
value -= range;
assert(value >= 0);
}
value %= range;
if (value < 0) value += range;
value += min;
assert(min <= value && value <= max);
return value;
}
/** Does this coding support at least one negative value?
Includes codings that can do so via 32-bit wraparound.
*/
boolean isSigned() {
return min < 0;
}
/** Does this coding code arrays by making successive differences? */
boolean isDelta() {
return del != 0;
}
public int B() { return B; }
public int H() { return H; }
public int L() { return L; }
public int S() { return S; }
public int del() { return del; }
public int min() { return min; }
public int max() { return max; }
public int umin() { return umin; }
public int umax() { return umax; }
public int byteMin(int b) { return byteMin[b-1]; }
public int byteMax(int b) { return byteMax[b-1]; }
public int compareTo(Coding that) {
int dkey = this.del - that.del;
if (dkey == 0)
dkey = this.B - that.B;
if (dkey == 0)
dkey = this.H - that.H;
if (dkey == 0)
dkey = this.S - that.S;
return dkey;
}
/** Heuristic measure of the difference between two codings. */
public int distanceFrom(Coding that) {
int diffdel = this.del - that.del;
if (diffdel < 0) diffdel = -diffdel;
int diffS = this.S - that.S;
if (diffS < 0) diffS = -diffS;
int diffB = this.B - that.B;
if (diffB < 0) diffB = -diffB;
int diffHL;
if (this.H == that.H) {
diffHL = 0;
} else {
// Distance in log space of H (<=128) and L (<128).
int thisHL = this.getHL();
int thatHL = that.getHL();
// Double the accuracy of the log:
thisHL *= thisHL;
thatHL *= thatHL;
if (thisHL > thatHL)
diffHL = ceil_lg2(1+(thisHL-1)/thatHL);
else
diffHL = ceil_lg2(1+(thatHL-1)/thisHL);
}
int norm = 5*(diffdel + diffS + diffB) + diffHL;
assert(norm != 0 || this.compareTo(that) == 0);
return norm;
}
private int getHL() {
// Follow H in log space by the multiplicative inverse of L.
if (H <= 128) return H;
if (L >= 1) return 128*128/L;
return 128*256;
}
/** ceiling(log[2](x)): {1->0, 2->1, 3->2, 4->2, ...} */
static int ceil_lg2(int x) {
assert(x-1 >= 0); // x in range (int.MIN_VALUE -> 32)
x -= 1;
int lg = 0;
while (x != 0) {
lg++;
x >>= 1;
}
return lg;
}
private static final byte[] byteBitWidths = new byte[0x100];
static {
for (int b = 0; b < byteBitWidths.length; b++) {
byteBitWidths[b] = (byte) ceil_lg2(b + 1);
}
for (int i = 10; i >= 0; i = (i << 1) - (i >> 3)) {
assert(bitWidth(i) == ceil_lg2(i + 1));
}
}
/** Number of significant bits in i, not counting sign bits.
* For positive i, it is ceil_lg2(i + 1).
*/
static int bitWidth(int i) {
if (i < 0) i = ~i; // change sign
int w = 0;
int lo = i;
if (lo < byteBitWidths.length)
return byteBitWidths[lo];
int hi;
hi = (lo >>> 16);
if (hi != 0) {
lo = hi;
w += 16;
}
hi = (lo >>> 8);
if (hi != 0) {
lo = hi;
w += 8;
}
w += byteBitWidths[lo];
//assert(w == ceil_lg2(i + 1));
return w;
}
/** Create an array of successive differences.
* If min==max, accept any and all 32-bit overflow.
* Otherwise, avoid 32-bit overflow, and reduce all differences
* to a value in the given range, by adding or subtracting
* multiples of the range cardinality (max-min+1).
* Also, the values are assumed to be in the range [0..(max-min)].
*/
static int[] makeDeltas(int[] values, int start, int end,
int min, int max) {
assert(max >= min);
int count = end-start;
int[] deltas = new int[count];
int state = 0;
if (min == max) {
for (int i = 0; i < count; i++) {
int value = values[start+i];
deltas[i] = value - state;
state = value;
}
} else {
for (int i = 0; i < count; i++) {
int value = values[start+i];
assert(value >= 0 && value+min <= max);
int delta = value - state;
assert(delta == (long)value - (long)state); // no overflow
state = value;
// Reduce delta values to the required range.
delta = reduceToSignedRange(delta, min, max);
deltas[i] = delta;
}
}
return deltas;
}
boolean canRepresent(int minValue, int maxValue) {
assert(minValue <= maxValue);
if (del > 0) {
if (isSubrange()) {
// We will force the values to reduce to the right subrange.
return canRepresentUnsigned(maxValue)
&& canRepresentUnsigned(minValue);
} else {
// Huge range; delta values must assume full 32-bit range.
return isFullRange();
}
}
else
// final values must be representable
return canRepresentSigned(maxValue)
&& canRepresentSigned(minValue);
}
boolean canRepresent(int[] values, int start, int end) {
int len = end-start;
if (len == 0) return true;
if (isFullRange()) return true;
// Calculate max, min:
int lmax = values[start];
int lmin = lmax;
for (int i = 1; i < len; i++) {
int value = values[start+i];
if (lmax < value) lmax = value;
if (lmin > value) lmin = value;
}
return canRepresent(lmin, lmax);
}
public double getBitLength(int value) { // implements BitMetric
return (double) getLength(value) * 8;
}
/** How many bytes are in the coding of this value?
* Returns Integer.MAX_VALUE if the value has no coding.
* The coding must not be a delta coding, since there is no
* definite size for a single value apart from its context.
*/
public int getLength(int value) {
if (isDelta() && isSubrange()) {
if (!canRepresentUnsigned(value))
return Integer.MAX_VALUE;
value = reduceToSignedRange(value);
}
if (value >= 0) {
for (int n = 0; n < B; n++) {
if (value <= byteMax[n]) return n+1;
}
} else {
for (int n = 0; n < B; n++) {
if (value >= byteMin[n]) return n+1;
}
}
return Integer.MAX_VALUE;
}
public int getLength(int[] values, int start, int end) {
int len = end-start;
if (B == 1) return len;
if (L == 0) return len * B;
if (isDelta()) {
int[] deltas;
if (!isSubrange())
deltas = makeDeltas(values, start, end, 0, 0);
else
deltas = makeDeltas(values, start, end, min, max);
//return Coding.of(B, H, S).getLength(deltas, 0, len);
values = deltas;
start = 0;
}
int sum = len; // at least 1 byte per
// add extra bytes for extra-long values
for (int n = 1; n <= B; n++) {
// what is the coding interval [min..max] for n bytes?
int lmax = byteMax[n-1];
int lmin = byteMin[n-1];
int longer = 0; // count of guys longer than n bytes
for (int i = 0; i < len; i++) {
int value = values[start+i];
if (value >= 0) {
if (value > lmax) longer++;
} else {
if (value < lmin) longer++;
}
}
if (longer == 0) break; // no more passes needed
if (n == B) return Integer.MAX_VALUE; // cannot represent!
sum += longer;
}
return sum;
}
public byte[] getMetaCoding(Coding dflt) {
if (dflt == this) return new byte[]{ (byte) _meta_default };
int canonicalIndex = BandStructure.indexOf(this);
if (canonicalIndex > 0)
return new byte[]{ (byte) canonicalIndex };
return new byte[]{
(byte)_meta_arb,
(byte)(del + 2*S + 8*(B-1)),
(byte)(H-1)
};
}
public static int parseMetaCoding(byte[] bytes, int pos, Coding dflt, CodingMethod res[]) {
int op = bytes[pos++] & 0xFF;
if (_meta_canon_min <= op && op <= _meta_canon_max) {
Coding c = BandStructure.codingForIndex(op);
assert(c != null);
res[0] = c;
return pos;
}
if (op == _meta_arb) {
int dsb = bytes[pos++] & 0xFF;
int H_1 = bytes[pos++] & 0xFF;
int del = dsb % 2;
int S = (dsb / 2) % 4;
int B = (dsb / 8)+1;
int H = H_1+1;
if (!((1 <= B && B <= B_MAX) &&
(0 <= S && S <= S_MAX) &&
(1 <= H && H <= H_MAX) &&
(0 <= del && del <= 1))
|| (B == 1 && H != 256)
|| (B == 5 && H == 256)) {
throw new RuntimeException("Bad arb. coding: ("+B+","+H+","+S+","+del);
}
res[0] = Coding.of(B, H, S, del);
return pos;
}
return pos-1; // backup
}
public String keyString() {
return "("+B+","+H+","+S+","+del+")";
}
public String toString() {
String str = "Coding"+keyString();
// If -ea, print out more informative strings!
//assert((str = stringForDebug()) != null);
return str;
}
static boolean verboseStringForDebug = false;
String stringForDebug() {
String minS = (min == Integer.MIN_VALUE ? "min" : ""+min);
String maxS = (max == Integer.MAX_VALUE ? "max" : ""+max);
String str = keyString()+" L="+L+" r=["+minS+","+maxS+"]";
if (isSubrange())
str += " subrange";
else if (!isFullRange())
str += " MIDRANGE";
if (verboseStringForDebug) {
str += " {";
int prev_range = 0;
for (int n = 1; n <= B; n++) {
int range_n = saturate32((long)byteMax[n-1] - byteMin[n-1] + 1);
assert(range_n == saturate32(codeRangeLong(B, H, n)));
range_n -= prev_range;
prev_range = range_n;
String rngS = (range_n == Integer.MAX_VALUE ? "max" : ""+range_n);
str += " #"+n+"="+rngS;
}
str += " }";
}
return str;
}
}

View file

@ -1,43 +0,0 @@
/*
* Copyright (c) 2003, 2010, 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.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/**
* Interface for encoding and decoding int arrays using bytewise codes.
* @author John Rose
*/
interface CodingMethod {
// Read and write an array of ints from/to a stream.
public void readArrayFrom(InputStream in, int[] a, int start, int end) throws IOException;
public void writeArrayTo(OutputStream out, int[] a, int start, int end) throws IOException;
// how to express me in a band header?
public byte[] getMetaCoding(Coding dflt);
}

View file

@ -1,515 +0,0 @@
/*
* Copyright (c) 2001, 2019, 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.Arrays;
import java.util.List;
/**
* Shared constants
* @author John Rose
*/
class Constants {
private Constants(){}
public static final int JAVA_MAGIC = 0xCAFEBABE;
/*
Java Class Version numbers history
1.0 to 1.3.X 45,3
1.4 to 1.4.X 46,0
1.5 to 1.5.X 49,0
1.6 to 1.6.X 50,0
1.7 to 1.7.X 51,0
1.8 to 1.8.X 52,0
1.9 to 1.9.X 53,0
1.10 to 1.10.X 54,0
1.11 to 1.11.X 55,0
1.12 to 1.12.X 56,0
1.13 to 1.13.X 57,0
1.14 to 1.14.X 58,0
*/
public static final Package.Version JAVA_MIN_CLASS_VERSION =
Package.Version.of(45, 03);
public static final Package.Version JAVA5_MAX_CLASS_VERSION =
Package.Version.of(49, 00);
public static final Package.Version JAVA6_MAX_CLASS_VERSION =
Package.Version.of(50, 00);
public static final Package.Version JAVA7_MAX_CLASS_VERSION =
Package.Version.of(51, 00);
public static final Package.Version JAVA8_MAX_CLASS_VERSION =
Package.Version.of(52, 00);
public static final Package.Version JAVA9_MAX_CLASS_VERSION =
Package.Version.of(53, 00);
public static final Package.Version JAVA10_MAX_CLASS_VERSION =
Package.Version.of(54, 00);
public static final Package.Version JAVA11_MAX_CLASS_VERSION =
Package.Version.of(55, 00);
public static final Package.Version JAVA12_MAX_CLASS_VERSION =
Package.Version.of(56, 00);
public static final Package.Version JAVA13_MAX_CLASS_VERSION =
Package.Version.of(57, 00);
public static final Package.Version JAVA14_MAX_CLASS_VERSION =
Package.Version.of(58, 00);
public static final int JAVA_PACKAGE_MAGIC = 0xCAFED00D;
public static final Package.Version JAVA5_PACKAGE_VERSION =
Package.Version.of(150, 7);
public static final Package.Version JAVA6_PACKAGE_VERSION =
Package.Version.of(160, 1);
public static final Package.Version JAVA7_PACKAGE_VERSION =
Package.Version.of(170, 1);
public static final Package.Version JAVA8_PACKAGE_VERSION =
Package.Version.of(171, 0);
// upper limit, should point to the latest class version
public static final Package.Version JAVA_MAX_CLASS_VERSION =
JAVA13_MAX_CLASS_VERSION;
// upper limit should point to the latest package version, for version info!.
public static final Package.Version MAX_PACKAGE_VERSION =
JAVA7_PACKAGE_VERSION;
public static final int CONSTANT_POOL_INDEX_LIMIT = 0x10000;
public static final int CONSTANT_POOL_NARROW_LIMIT = 0x00100;
public static final String JAVA_SIGNATURE_CHARS = "BSCIJFDZLV([";
public static final byte CONSTANT_Utf8 = 1;
public static final byte CONSTANT_unused2 = 2; // unused, was Unicode
public static final byte CONSTANT_Integer = 3;
public static final byte CONSTANT_Float = 4;
public static final byte CONSTANT_Long = 5;
public static final byte CONSTANT_Double = 6;
public static final byte CONSTANT_Class = 7;
public static final byte CONSTANT_String = 8;
public static final byte CONSTANT_Fieldref = 9;
public static final byte CONSTANT_Methodref = 10;
public static final byte CONSTANT_InterfaceMethodref = 11;
public static final byte CONSTANT_NameandType = 12;
public static final byte CONSTANT_unused13 = 13;
public static final byte CONSTANT_unused14 = 14;
public static final byte CONSTANT_MethodHandle = 15;
public static final byte CONSTANT_MethodType = 16;
public static final byte CONSTANT_unused17 = 17; // unused
public static final byte CONSTANT_InvokeDynamic = 18;
// pseudo-constants:
public static final byte CONSTANT_None = 0;
public static final byte CONSTANT_Signature = CONSTANT_unused13;
public static final byte CONSTANT_BootstrapMethod = CONSTANT_unused17; // used only in InvokeDynamic constants
public static final byte CONSTANT_Limit = 19;
public static final byte CONSTANT_All = 50; // combined global map
public static final byte CONSTANT_LoadableValue = 51; // used for 'KL' and qldc operands
public static final byte CONSTANT_AnyMember = 52; // union of refs to field or (interface) method
public static final byte CONSTANT_FieldSpecific = 53; // used only for 'KQ' ConstantValue attrs
public static final byte CONSTANT_GroupFirst = CONSTANT_All;
public static final byte CONSTANT_GroupLimit = CONSTANT_FieldSpecific+1;
// CONSTANT_MethodHandle reference kinds
public static final byte REF_getField = 1;
public static final byte REF_getStatic = 2;
public static final byte REF_putField = 3;
public static final byte REF_putStatic = 4;
public static final byte REF_invokeVirtual = 5;
public static final byte REF_invokeStatic = 6;
public static final byte REF_invokeSpecial = 7;
public static final byte REF_newInvokeSpecial = 8;
public static final byte REF_invokeInterface = 9;
// pseudo-access bits
public static final int ACC_IC_LONG_FORM = (1<<16); //for ic_flags
// attribute "context types"
public static final int ATTR_CONTEXT_CLASS = 0;
public static final int ATTR_CONTEXT_FIELD = 1;
public static final int ATTR_CONTEXT_METHOD = 2;
public static final int ATTR_CONTEXT_CODE = 3;
public static final int ATTR_CONTEXT_LIMIT = 4;
public static final String[] ATTR_CONTEXT_NAME
= { "class", "field", "method", "code" };
// predefined attr bits
public static final int
X_ATTR_OVERFLOW = 16,
CLASS_ATTR_SourceFile = 17,
METHOD_ATTR_Code = 17,
FIELD_ATTR_ConstantValue = 17,
CLASS_ATTR_EnclosingMethod = 18,
METHOD_ATTR_Exceptions = 18,
X_ATTR_Signature = 19,
X_ATTR_Deprecated = 20,
X_ATTR_RuntimeVisibleAnnotations = 21,
X_ATTR_RuntimeInvisibleAnnotations = 22,
METHOD_ATTR_RuntimeVisibleParameterAnnotations = 23,
CLASS_ATTR_InnerClasses = 23,
METHOD_ATTR_RuntimeInvisibleParameterAnnotations = 24,
CLASS_ATTR_ClassFile_version = 24,
METHOD_ATTR_AnnotationDefault = 25,
METHOD_ATTR_MethodParameters = 26, // JDK8
X_ATTR_RuntimeVisibleTypeAnnotations = 27, // JDK8
X_ATTR_RuntimeInvisibleTypeAnnotations = 28, // JDK8
CODE_ATTR_StackMapTable = 0, // new in Java 6
CODE_ATTR_LineNumberTable = 1,
CODE_ATTR_LocalVariableTable = 2,
CODE_ATTR_LocalVariableTypeTable = 3;
// File option bits, from LSB in ascending bit position.
public static final int FO_DEFLATE_HINT = 1<<0;
public static final int FO_IS_CLASS_STUB = 1<<1;
// Archive option bits, from LSB in ascending bit position:
public static final int AO_HAVE_SPECIAL_FORMATS = 1<<0;
public static final int AO_HAVE_CP_NUMBERS = 1<<1;
public static final int AO_HAVE_ALL_CODE_FLAGS = 1<<2;
public static final int AO_HAVE_CP_EXTRAS = 1<<3;
public static final int AO_HAVE_FILE_HEADERS = 1<<4;
public static final int AO_DEFLATE_HINT = 1<<5;
public static final int AO_HAVE_FILE_MODTIME = 1<<6;
public static final int AO_HAVE_FILE_OPTIONS = 1<<7;
public static final int AO_HAVE_FILE_SIZE_HI = 1<<8;
public static final int AO_HAVE_CLASS_FLAGS_HI = 1<<9;
public static final int AO_HAVE_FIELD_FLAGS_HI = 1<<10;
public static final int AO_HAVE_METHOD_FLAGS_HI = 1<<11;
public static final int AO_HAVE_CODE_FLAGS_HI = 1<<12;
public static final int AO_UNUSED_MBZ = (-1)<<13; // option bits reserved for future use
public static final int LG_AO_HAVE_XXX_FLAGS_HI = 9;
// visitRefs modes:
static final int VRM_CLASSIC = 0;
static final int VRM_PACKAGE = 1;
public static final int NO_MODTIME = 0; // null modtime value
// some comstantly empty containers
public static final int[] noInts = {};
public static final byte[] noBytes = {};
public static final Object[] noValues = {};
public static final String[] noStrings = {};
public static final List<Object> emptyList = Arrays.asList(noValues);
// meta-coding
public static final int
_meta_default = 0,
_meta_canon_min = 1,
_meta_canon_max = 115,
_meta_arb = 116,
_meta_run = 117,
_meta_pop = 141,
_meta_limit = 189;
// bytecodes
public static final int
_nop = 0, // 0x00
_aconst_null = 1, // 0x01
_iconst_m1 = 2, // 0x02
_iconst_0 = 3, // 0x03
_iconst_1 = 4, // 0x04
_iconst_2 = 5, // 0x05
_iconst_3 = 6, // 0x06
_iconst_4 = 7, // 0x07
_iconst_5 = 8, // 0x08
_lconst_0 = 9, // 0x09
_lconst_1 = 10, // 0x0a
_fconst_0 = 11, // 0x0b
_fconst_1 = 12, // 0x0c
_fconst_2 = 13, // 0x0d
_dconst_0 = 14, // 0x0e
_dconst_1 = 15, // 0x0f
_bipush = 16, // 0x10
_sipush = 17, // 0x11
_ldc = 18, // 0x12
_ldc_w = 19, // 0x13
_ldc2_w = 20, // 0x14
_iload = 21, // 0x15
_lload = 22, // 0x16
_fload = 23, // 0x17
_dload = 24, // 0x18
_aload = 25, // 0x19
_iload_0 = 26, // 0x1a
_iload_1 = 27, // 0x1b
_iload_2 = 28, // 0x1c
_iload_3 = 29, // 0x1d
_lload_0 = 30, // 0x1e
_lload_1 = 31, // 0x1f
_lload_2 = 32, // 0x20
_lload_3 = 33, // 0x21
_fload_0 = 34, // 0x22
_fload_1 = 35, // 0x23
_fload_2 = 36, // 0x24
_fload_3 = 37, // 0x25
_dload_0 = 38, // 0x26
_dload_1 = 39, // 0x27
_dload_2 = 40, // 0x28
_dload_3 = 41, // 0x29
_aload_0 = 42, // 0x2a
_aload_1 = 43, // 0x2b
_aload_2 = 44, // 0x2c
_aload_3 = 45, // 0x2d
_iaload = 46, // 0x2e
_laload = 47, // 0x2f
_faload = 48, // 0x30
_daload = 49, // 0x31
_aaload = 50, // 0x32
_baload = 51, // 0x33
_caload = 52, // 0x34
_saload = 53, // 0x35
_istore = 54, // 0x36
_lstore = 55, // 0x37
_fstore = 56, // 0x38
_dstore = 57, // 0x39
_astore = 58, // 0x3a
_istore_0 = 59, // 0x3b
_istore_1 = 60, // 0x3c
_istore_2 = 61, // 0x3d
_istore_3 = 62, // 0x3e
_lstore_0 = 63, // 0x3f
_lstore_1 = 64, // 0x40
_lstore_2 = 65, // 0x41
_lstore_3 = 66, // 0x42
_fstore_0 = 67, // 0x43
_fstore_1 = 68, // 0x44
_fstore_2 = 69, // 0x45
_fstore_3 = 70, // 0x46
_dstore_0 = 71, // 0x47
_dstore_1 = 72, // 0x48
_dstore_2 = 73, // 0x49
_dstore_3 = 74, // 0x4a
_astore_0 = 75, // 0x4b
_astore_1 = 76, // 0x4c
_astore_2 = 77, // 0x4d
_astore_3 = 78, // 0x4e
_iastore = 79, // 0x4f
_lastore = 80, // 0x50
_fastore = 81, // 0x51
_dastore = 82, // 0x52
_aastore = 83, // 0x53
_bastore = 84, // 0x54
_castore = 85, // 0x55
_sastore = 86, // 0x56
_pop = 87, // 0x57
_pop2 = 88, // 0x58
_dup = 89, // 0x59
_dup_x1 = 90, // 0x5a
_dup_x2 = 91, // 0x5b
_dup2 = 92, // 0x5c
_dup2_x1 = 93, // 0x5d
_dup2_x2 = 94, // 0x5e
_swap = 95, // 0x5f
_iadd = 96, // 0x60
_ladd = 97, // 0x61
_fadd = 98, // 0x62
_dadd = 99, // 0x63
_isub = 100, // 0x64
_lsub = 101, // 0x65
_fsub = 102, // 0x66
_dsub = 103, // 0x67
_imul = 104, // 0x68
_lmul = 105, // 0x69
_fmul = 106, // 0x6a
_dmul = 107, // 0x6b
_idiv = 108, // 0x6c
_ldiv = 109, // 0x6d
_fdiv = 110, // 0x6e
_ddiv = 111, // 0x6f
_irem = 112, // 0x70
_lrem = 113, // 0x71
_frem = 114, // 0x72
_drem = 115, // 0x73
_ineg = 116, // 0x74
_lneg = 117, // 0x75
_fneg = 118, // 0x76
_dneg = 119, // 0x77
_ishl = 120, // 0x78
_lshl = 121, // 0x79
_ishr = 122, // 0x7a
_lshr = 123, // 0x7b
_iushr = 124, // 0x7c
_lushr = 125, // 0x7d
_iand = 126, // 0x7e
_land = 127, // 0x7f
_ior = 128, // 0x80
_lor = 129, // 0x81
_ixor = 130, // 0x82
_lxor = 131, // 0x83
_iinc = 132, // 0x84
_i2l = 133, // 0x85
_i2f = 134, // 0x86
_i2d = 135, // 0x87
_l2i = 136, // 0x88
_l2f = 137, // 0x89
_l2d = 138, // 0x8a
_f2i = 139, // 0x8b
_f2l = 140, // 0x8c
_f2d = 141, // 0x8d
_d2i = 142, // 0x8e
_d2l = 143, // 0x8f
_d2f = 144, // 0x90
_i2b = 145, // 0x91
_i2c = 146, // 0x92
_i2s = 147, // 0x93
_lcmp = 148, // 0x94
_fcmpl = 149, // 0x95
_fcmpg = 150, // 0x96
_dcmpl = 151, // 0x97
_dcmpg = 152, // 0x98
_ifeq = 153, // 0x99
_ifne = 154, // 0x9a
_iflt = 155, // 0x9b
_ifge = 156, // 0x9c
_ifgt = 157, // 0x9d
_ifle = 158, // 0x9e
_if_icmpeq = 159, // 0x9f
_if_icmpne = 160, // 0xa0
_if_icmplt = 161, // 0xa1
_if_icmpge = 162, // 0xa2
_if_icmpgt = 163, // 0xa3
_if_icmple = 164, // 0xa4
_if_acmpeq = 165, // 0xa5
_if_acmpne = 166, // 0xa6
_goto = 167, // 0xa7
_jsr = 168, // 0xa8
_ret = 169, // 0xa9
_tableswitch = 170, // 0xaa
_lookupswitch = 171, // 0xab
_ireturn = 172, // 0xac
_lreturn = 173, // 0xad
_freturn = 174, // 0xae
_dreturn = 175, // 0xaf
_areturn = 176, // 0xb0
_return = 177, // 0xb1
_getstatic = 178, // 0xb2
_putstatic = 179, // 0xb3
_getfield = 180, // 0xb4
_putfield = 181, // 0xb5
_invokevirtual = 182, // 0xb6
_invokespecial = 183, // 0xb7
_invokestatic = 184, // 0xb8
_invokeinterface = 185, // 0xb9
_invokedynamic = 186, // 0xba
_new = 187, // 0xbb
_newarray = 188, // 0xbc
_anewarray = 189, // 0xbd
_arraylength = 190, // 0xbe
_athrow = 191, // 0xbf
_checkcast = 192, // 0xc0
_instanceof = 193, // 0xc1
_monitorenter = 194, // 0xc2
_monitorexit = 195, // 0xc3
_wide = 196, // 0xc4
_multianewarray = 197, // 0xc5
_ifnull = 198, // 0xc6
_ifnonnull = 199, // 0xc7
_goto_w = 200, // 0xc8
_jsr_w = 201, // 0xc9
_bytecode_limit = 202; // 0xca
// End marker, used to terminate bytecode sequences:
public static final int _end_marker = 255;
// Escapes:
public static final int _byte_escape = 254;
public static final int _ref_escape = 253;
// Self-relative pseudo-opcodes for better compression.
// A "linker op" is a bytecode which links to a class member.
// (But in what follows, "invokeinterface" ops are excluded.)
//
// A "self linker op" is a variant bytecode which works only
// with the current class or its super. Because the number of
// possible targets is small, it admits a more compact encoding.
// Self linker ops are allowed to absorb a previous "aload_0" op.
// There are (7 * 4) self linker ops (super or not, aload_0 or not).
//
// For simplicity, we define the full symmetric set of variants.
// However, some of them are relatively useless.
// Self linker ops are enabled by Pack.selfCallVariants (true).
public static final int _first_linker_op = _getstatic;
public static final int _last_linker_op = _invokestatic;
public static final int _num_linker_ops = (_last_linker_op - _first_linker_op) + 1;
public static final int _self_linker_op = _bytecode_limit;
public static final int _self_linker_aload_flag = 1*_num_linker_ops;
public static final int _self_linker_super_flag = 2*_num_linker_ops;
public static final int _self_linker_limit = _self_linker_op + 4*_num_linker_ops;
// An "invoke init" op is a variant of invokespecial which works
// only with the method name "<init>". There are variants which
// link to the current class, the super class, or the class of the
// immediately previous "newinstance" op. There are 3 of these ops.
// They all take method signature references as operands.
// Invoke init ops are enabled by Pack.initCallVariants (true).
public static final int _invokeinit_op = _self_linker_limit;
public static final int _invokeinit_self_option = 0;
public static final int _invokeinit_super_option = 1;
public static final int _invokeinit_new_option = 2;
public static final int _invokeinit_limit = _invokeinit_op+3;
public static final int _pseudo_instruction_limit = _invokeinit_limit;
// linker variant limit == 202+(7*4)+3 == 233
// Ldc variants support strongly typed references to constants.
// This lets us index constant pool entries completely according to tag,
// which is a great simplification.
// Ldc variants gain us only 0.007% improvement in compression ratio,
// but they simplify the file format greatly.
public static final int _xldc_op = _invokeinit_limit;
public static final int _sldc = _ldc; // previously named _aldc
public static final int _cldc = _xldc_op+0;
public static final int _ildc = _xldc_op+1;
public static final int _fldc = _xldc_op+2;
public static final int _sldc_w = _ldc_w; // previously named _aldc_w
public static final int _cldc_w = _xldc_op+3;
public static final int _ildc_w = _xldc_op+4;
public static final int _fldc_w = _xldc_op+5;
public static final int _lldc2_w = _ldc2_w;
public static final int _dldc2_w = _xldc_op+6;
// anything other than primitive, string, or class must be handled with qldc:
public static final int _qldc = _xldc_op+7;
public static final int _qldc_w = _xldc_op+8;
public static final int _xldc_limit = _xldc_op+9;
// handling of InterfaceMethodRef
public static final int _invoke_int_op = _xldc_limit;
public static final int _invokespecial_int = _invoke_int_op+0;
public static final int _invokestatic_int = _invoke_int_op+1;
public static final int _invoke_int_limit = _invoke_int_op+2;
}

View file

@ -1,750 +0,0 @@
/*
* Copyright (c) 2003, 2019, 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 sun.nio.cs.UTF_8;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.text.MessageFormat;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Properties;
import java.util.ResourceBundle;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.jar.JarFile;
import java.util.jar.JarOutputStream;
import java.util.jar.Pack200;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
/** Command line interface for Pack200.
*/
@SuppressWarnings({"removal"})
class Driver {
private static final ResourceBundle RESOURCE =
ResourceBundle.getBundle("com.sun.java.util.jar.pack.DriverResource");
private static boolean suppressDeprecateMsg = false;
public static void main(String[] ava) throws IOException {
List<String> av = new ArrayList<>(Arrays.asList(ava));
boolean doPack = true;
boolean doUnpack = false;
boolean doRepack = false;
boolean doZip = true;
suppressDeprecateMsg = av.remove("-XDsuppress-tool-removal-message");
String logFile = null;
String verboseProp = Utils.DEBUG_VERBOSE;
{
// Non-standard, undocumented "--unpack" switch enables unpack mode.
String arg0 = av.isEmpty() ? "" : av.get(0);
switch (arg0) {
case "--pack":
av.remove(0);
break;
case "--unpack":
av.remove(0);
doPack = false;
doUnpack = true;
break;
}
}
if (!suppressDeprecateMsg) {
printDeprecateWarning(doPack, System.out);
}
// Collect engine properties here:
Map<String,String> engProps = new HashMap<>();
engProps.put(verboseProp, System.getProperty(verboseProp));
String optionMap;
String[] propTable;
if (doPack) {
optionMap = PACK200_OPTION_MAP;
propTable = PACK200_PROPERTY_TO_OPTION;
} else {
optionMap = UNPACK200_OPTION_MAP;
propTable = UNPACK200_PROPERTY_TO_OPTION;
}
// Collect argument properties here:
Map<String,String> avProps = new HashMap<>();
try {
for (;;) {
String state = parseCommandOptions(av, optionMap, avProps);
// Translate command line options to Pack200 properties:
eachOpt:
for (Iterator<String> opti = avProps.keySet().iterator();
opti.hasNext(); ) {
String opt = opti.next();
String prop = null;
for (int i = 0; i < propTable.length; i += 2) {
if (opt.equals(propTable[1+i])) {
prop = propTable[0+i];
break;
}
}
if (prop != null) {
String val = avProps.get(opt);
opti.remove(); // remove opt from avProps
if (!prop.endsWith(".")) {
// Normal string or boolean.
if (!(opt.equals("--verbose")
|| opt.endsWith("="))) {
// Normal boolean; convert to T/F.
boolean flag = (val != null);
if (opt.startsWith("--no-"))
flag = !flag;
val = flag? "true": "false";
}
engProps.put(prop, val);
} else if (prop.contains(".attribute.")) {
for (String val1 : val.split("\0")) {
String[] val2 = val1.split("=", 2);
engProps.put(prop+val2[0], val2[1]);
}
} else {
// Collection property: pack.pass.file.cli.NNN
int idx = 1;
for (String val1 : val.split("\0")) {
String prop1;
do {
prop1 = prop+"cli."+(idx++);
} while (engProps.containsKey(prop1));
engProps.put(prop1, val1);
}
}
}
}
// See if there is any other action to take.
if ("--config-file=".equals(state)) {
String propFile = av.remove(0);
Properties fileProps = new Properties();
try (InputStream propIn = new FileInputStream(propFile)) {
fileProps.load(propIn);
}
if (engProps.get(verboseProp) != null)
fileProps.list(System.out);
for (Map.Entry<Object,Object> me : fileProps.entrySet()) {
engProps.put((String) me.getKey(), (String) me.getValue());
}
} else if ("--version".equals(state)) {
System.out.println(MessageFormat.format(RESOURCE.getString(DriverResource.VERSION),
Driver.class.getName(), "1.31, 07/05/05"));
return;
} else if ("--help".equals(state)) {
printUsage(doPack, true, System.out);
System.exit(0);
return;
} else {
break;
}
}
} catch (IllegalArgumentException ee) {
System.err.println(MessageFormat.format(RESOURCE.getString(DriverResource.BAD_ARGUMENT), ee));
printUsage(doPack, false, System.err);
System.exit(2);
return;
}
// Deal with remaining non-engine properties:
for (String opt : avProps.keySet()) {
String val = avProps.get(opt);
switch (opt) {
case "--repack":
doRepack = true;
break;
case "--no-gzip":
doZip = (val == null);
break;
case "--log-file=":
logFile = val;
break;
default:
throw new InternalError(MessageFormat.format(
RESOURCE.getString(DriverResource.BAD_OPTION),
opt, avProps.get(opt)));
}
}
if (logFile != null && !logFile.isEmpty()) {
if (logFile.equals("-")) {
System.setErr(System.out);
} else {
OutputStream log = new FileOutputStream(logFile);
//log = new BufferedOutputStream(out);
System.setErr(new PrintStream(log));
}
}
boolean verbose = (engProps.get(verboseProp) != null);
String packfile = "";
if (!av.isEmpty())
packfile = av.remove(0);
String jarfile = "";
if (!av.isEmpty())
jarfile = av.remove(0);
String newfile = ""; // output JAR file if --repack
String bakfile = ""; // temporary backup of input JAR
String tmpfile = ""; // temporary file to be deleted
if (doRepack) {
// The first argument is the target JAR file.
// (Note: *.pac is nonstandard, but may be necessary
// if a host OS truncates file extensions.)
if (packfile.toLowerCase().endsWith(".pack") ||
packfile.toLowerCase().endsWith(".pac") ||
packfile.toLowerCase().endsWith(".gz")) {
System.err.println(MessageFormat.format(
RESOURCE.getString(DriverResource.BAD_REPACK_OUTPUT),
packfile));
printUsage(doPack, false, System.err);
System.exit(2);
}
newfile = packfile;
// The optional second argument is the source JAR file.
if (jarfile.isEmpty()) {
// If only one file is given, it is the only JAR.
// It serves as both input and output.
jarfile = newfile;
}
tmpfile = createTempFile(newfile, ".pack").getPath();
packfile = tmpfile;
doZip = false; // no need to zip the temporary file
}
if (!av.isEmpty()
// Accept jarfiles ending with .jar or .zip.
// Accept jarfile of "-" (stdout), but only if unpacking.
|| !(jarfile.toLowerCase().endsWith(".jar")
|| jarfile.toLowerCase().endsWith(".zip")
|| (jarfile.equals("-") && !doPack))) {
printUsage(doPack, false, System.err);
System.exit(2);
return;
}
if (doRepack)
doPack = doUnpack = true;
else if (doPack)
doUnpack = false;
Pack200.Packer jpack = Pack200.newPacker();
Pack200.Unpacker junpack = Pack200.newUnpacker();
jpack.properties().putAll(engProps);
junpack.properties().putAll(engProps);
if (doRepack && newfile.equals(jarfile)) {
String zipc = getZipComment(jarfile);
if (verbose && !zipc.isEmpty())
System.out.println(MessageFormat.format(RESOURCE.getString(DriverResource.DETECTED_ZIP_COMMENT), zipc));
if (zipc.indexOf(Utils.PACK_ZIP_ARCHIVE_MARKER_COMMENT) >= 0) {
System.out.println(MessageFormat.format(RESOURCE.getString(DriverResource.SKIP_FOR_REPACKED), jarfile));
doPack = false;
doUnpack = false;
doRepack = false;
}
}
try {
if (doPack) {
// Mode = Pack.
JarFile in = new JarFile(new File(jarfile));
OutputStream out;
// Packfile must be -, *.gz, *.pack, or *.pac.
if (packfile.equals("-")) {
out = System.out;
// Send warnings, etc., to stderr instead of stdout.
System.setOut(System.err);
} else if (doZip) {
if (!packfile.endsWith(".gz")) {
System.err.println(MessageFormat.format(RESOURCE.getString(DriverResource.WRITE_PACK_FILE), packfile));
printUsage(doPack, false, System.err);
System.exit(2);
}
out = new FileOutputStream(packfile);
out = new BufferedOutputStream(out);
out = new GZIPOutputStream(out);
} else {
if (!packfile.toLowerCase().endsWith(".pack") &&
!packfile.toLowerCase().endsWith(".pac")) {
System.err.println(MessageFormat.format(RESOURCE.getString(DriverResource.WRITE_PACKGZ_FILE),packfile));
printUsage(doPack, false, System.err);
System.exit(2);
}
out = new FileOutputStream(packfile);
out = new BufferedOutputStream(out);
}
jpack.pack(in, out);
//in.close(); // p200 closes in but not out
out.close();
}
if (doRepack && newfile.equals(jarfile)) {
// If the source and destination are the same,
// we will move the input JAR aside while regenerating it.
// This allows us to restore it if something goes wrong.
File bakf = createTempFile(jarfile, ".bak");
// On Windows target must be deleted see 4017593
bakf.delete();
boolean okBackup = new File(jarfile).renameTo(bakf);
if (!okBackup) {
throw new Error(MessageFormat.format(RESOURCE.getString(DriverResource.SKIP_FOR_MOVE_FAILED),bakfile));
} else {
// Open jarfile recovery bracket.
bakfile = bakf.getPath();
}
}
if (doUnpack) {
// Mode = Unpack.
InputStream in;
if (packfile.equals("-"))
in = System.in;
else
in = new FileInputStream(new File(packfile));
BufferedInputStream inBuf = new BufferedInputStream(in);
in = inBuf;
if (Utils.isGZIPMagic(Utils.readMagic(inBuf))) {
in = new GZIPInputStream(in);
}
String outfile = newfile.isEmpty()? jarfile: newfile;
OutputStream fileOut;
if (outfile.equals("-"))
fileOut = System.out;
else
fileOut = new FileOutputStream(outfile);
fileOut = new BufferedOutputStream(fileOut);
try (JarOutputStream out = new JarOutputStream(fileOut)) {
junpack.unpack(in, out);
// p200 closes in but not out
}
// At this point, we have a good jarfile (or newfile, if -r)
}
if (!bakfile.isEmpty()) {
// On success, abort jarfile recovery bracket.
new File(bakfile).delete();
bakfile = "";
}
} finally {
// Close jarfile recovery bracket.
if (!bakfile.isEmpty()) {
File jarFile = new File(jarfile);
jarFile.delete(); // Win32 requires this, see above
new File(bakfile).renameTo(jarFile);
}
// In all cases, delete temporary *.pack.
if (!tmpfile.isEmpty())
new File(tmpfile).delete();
}
}
private static
File createTempFile(String basefile, String suffix) throws IOException {
File base = new File(basefile);
String prefix = base.getName();
if (prefix.length() < 3) prefix += "tmp";
File where = (base.getParentFile() == null && suffix.equals(".bak"))
? new File(".").getAbsoluteFile()
: base.getParentFile();
Path tmpfile = (where == null)
? Files.createTempFile(prefix, suffix)
: Files.createTempFile(where.toPath(), prefix, suffix);
return tmpfile.toFile();
}
private static
void printDeprecateWarning(boolean doPack, PrintStream out) {
String prog = doPack ? "pack200" : "unpack200";
out.println(MessageFormat.format(RESOURCE.getString(DriverResource.DEPRECATED), prog));
}
private static
void printUsage(boolean doPack, boolean full, PrintStream out) {
String prog = doPack ? "pack200" : "unpack200";
String[] packUsage = (String[])RESOURCE.getObject(DriverResource.PACK_HELP);
String[] unpackUsage = (String[])RESOURCE.getObject(DriverResource.UNPACK_HELP);
String[] usage = doPack? packUsage: unpackUsage;
for (int i = 0; i < usage.length; i++) {
out.println(usage[i]);
if (!full) {
out.println(MessageFormat.format(RESOURCE.getString(DriverResource.MORE_INFO), prog));
break;
}
}
// Print a warning at the end
// The full help page is long, the beginning warning could be out of sight
if (full && !suppressDeprecateMsg) {
printDeprecateWarning(doPack, out);
}
}
private static
String getZipComment(String jarfile) throws IOException {
byte[] tail = new byte[1000];
long filelen = new File(jarfile).length();
if (filelen <= 0) return "";
long skiplen = Math.max(0, filelen - tail.length);
try (InputStream in = new FileInputStream(new File(jarfile))) {
in.skip(skiplen);
in.read(tail);
for (int i = tail.length-4; i >= 0; i--) {
if (tail[i+0] == 'P' && tail[i+1] == 'K' &&
tail[i+2] == 5 && tail[i+3] == 6) {
// Skip sig4, disks4, entries4, clen4, coff4, cmt2
i += 4+4+4+4+4+2;
if (i < tail.length)
return new String(tail, i, tail.length-i, UTF_8.INSTANCE);
return "";
}
}
return "";
}
}
private static final String PACK200_OPTION_MAP =
(""
+"--repack $ \n -r +>- @--repack $ \n"
+"--no-gzip $ \n -g +>- @--no-gzip $ \n"
+"--strip-debug $ \n -G +>- @--strip-debug $ \n"
+"--no-keep-file-order $ \n -O +>- @--no-keep-file-order $ \n"
+"--segment-limit= *> = \n -S +> @--segment-limit= = \n"
+"--effort= *> = \n -E +> @--effort= = \n"
+"--deflate-hint= *> = \n -H +> @--deflate-hint= = \n"
+"--modification-time= *> = \n -m +> @--modification-time= = \n"
+"--pass-file= *> &\0 \n -P +> @--pass-file= &\0 \n"
+"--unknown-attribute= *> = \n -U +> @--unknown-attribute= = \n"
+"--class-attribute= *> &\0 \n -C +> @--class-attribute= &\0 \n"
+"--field-attribute= *> &\0 \n -F +> @--field-attribute= &\0 \n"
+"--method-attribute= *> &\0 \n -M +> @--method-attribute= &\0 \n"
+"--code-attribute= *> &\0 \n -D +> @--code-attribute= &\0 \n"
+"--config-file= *> . \n -f +> @--config-file= . \n"
// Negative options as required by CLIP:
+"--no-strip-debug !--strip-debug \n"
+"--gzip !--no-gzip \n"
+"--keep-file-order !--no-keep-file-order \n"
// Non-Standard Options
+"--verbose $ \n -v +>- @--verbose $ \n"
+"--quiet !--verbose \n -q +>- !--verbose \n"
+"--log-file= *> = \n -l +> @--log-file= = \n"
//+"--java-option= *> = \n -J +> @--java-option= = \n"
+"--version . \n -V +> @--version . \n"
+"--help . \n -? +> @--help . \n -h +> @--help . \n"
// Termination:
+"-- . \n" // end option sequence here
+"- +? >- . \n" // report error if -XXX present; else use stdout
);
// Note: Collection options use "\0" as a delimiter between arguments.
// For Java version of unpacker (used for testing only):
private static final String UNPACK200_OPTION_MAP =
(""
+"--deflate-hint= *> = \n -H +> @--deflate-hint= = \n"
+"--verbose $ \n -v +>- @--verbose $ \n"
+"--quiet !--verbose \n -q +>- !--verbose \n"
+"--remove-pack-file $ \n -r +>- @--remove-pack-file $ \n"
+"--log-file= *> = \n -l +> @--log-file= = \n"
+"--config-file= *> . \n -f +> @--config-file= . \n"
// Termination:
+"-- . \n" // end option sequence here
+"- +? >- . \n" // report error if -XXX present; else use stdin
+"--version . \n -V +> @--version . \n"
+"--help . \n -? +> @--help . \n -h +> @--help . \n"
);
private static final String[] PACK200_PROPERTY_TO_OPTION = {
Pack200.Packer.SEGMENT_LIMIT, "--segment-limit=",
Pack200.Packer.KEEP_FILE_ORDER, "--no-keep-file-order",
Pack200.Packer.EFFORT, "--effort=",
Pack200.Packer.DEFLATE_HINT, "--deflate-hint=",
Pack200.Packer.MODIFICATION_TIME, "--modification-time=",
Pack200.Packer.PASS_FILE_PFX, "--pass-file=",
Pack200.Packer.UNKNOWN_ATTRIBUTE, "--unknown-attribute=",
Pack200.Packer.CLASS_ATTRIBUTE_PFX, "--class-attribute=",
Pack200.Packer.FIELD_ATTRIBUTE_PFX, "--field-attribute=",
Pack200.Packer.METHOD_ATTRIBUTE_PFX, "--method-attribute=",
Pack200.Packer.CODE_ATTRIBUTE_PFX, "--code-attribute=",
//Pack200.Packer.PROGRESS, "--progress=",
Utils.DEBUG_VERBOSE, "--verbose",
Utils.COM_PREFIX+"strip.debug", "--strip-debug",
};
private static final String[] UNPACK200_PROPERTY_TO_OPTION = {
Pack200.Unpacker.DEFLATE_HINT, "--deflate-hint=",
//Pack200.Unpacker.PROGRESS, "--progress=",
Utils.DEBUG_VERBOSE, "--verbose",
Utils.UNPACK_REMOVE_PACKFILE, "--remove-pack-file",
};
/*-*
* Remove a set of command-line options from args,
* storing them in the map in a canonicalized form.
* <p>
* The options string is a newline-separated series of
* option processing specifiers.
*/
private static
String parseCommandOptions(List<String> args,
String options,
Map<String,String> properties) {
//System.out.println(args+" // "+properties);
String resultString = null;
// Convert options string into optLines dictionary.
TreeMap<String,String[]> optmap = new TreeMap<>();
loadOptmap:
for (String optline : options.split("\n")) {
String[] words = optline.split("\\p{Space}+");
if (words.length == 0) continue loadOptmap;
String opt = words[0];
words[0] = ""; // initial word is not a spec
if (opt.isEmpty() && words.length >= 1) {
opt = words[1]; // initial "word" is empty due to leading ' '
words[1] = "";
}
if (opt.length() == 0) continue loadOptmap;
String[] prevWords = optmap.put(opt, words);
if (prevWords != null)
throw new RuntimeException(MessageFormat.format(RESOURCE.getString(DriverResource.DUPLICATE_OPTION), optline.trim()));
}
// State machine for parsing a command line.
ListIterator<String> argp = args.listIterator();
ListIterator<String> pbp = new ArrayList<String>().listIterator();
doArgs:
for (;;) {
// One trip through this loop per argument.
// Multiple trips per option only if several options per argument.
String arg;
if (pbp.hasPrevious()) {
arg = pbp.previous();
pbp.remove();
} else if (argp.hasNext()) {
arg = argp.next();
} else {
// No more arguments at all.
break doArgs;
}
tryOpt:
for (int optlen = arg.length(); ; optlen--) {
// One time through this loop for each matching arg prefix.
String opt;
// Match some prefix of the argument to a key in optmap.
findOpt:
for (;;) {
opt = arg.substring(0, optlen);
if (optmap.containsKey(opt)) break findOpt;
if (optlen == 0) break tryOpt;
// Decide on a smaller prefix to search for.
SortedMap<String,String[]> pfxmap = optmap.headMap(opt);
// pfxmap.lastKey is no shorter than any prefix in optmap.
int len = pfxmap.isEmpty() ? 0 : pfxmap.lastKey().length();
optlen = Math.min(len, optlen - 1);
opt = arg.substring(0, optlen);
// (Note: We could cut opt down to its common prefix with
// pfxmap.lastKey, but that wouldn't save many cycles.)
}
opt = opt.intern();
assert(arg.startsWith(opt));
assert(opt.length() == optlen);
String val = arg.substring(optlen); // arg == opt+val
// Execute the option processing specs for this opt.
// If no actions are taken, then look for a shorter prefix.
boolean didAction = false;
boolean isError = false;
int pbpMark = pbp.nextIndex(); // in case of backtracking
String[] specs = optmap.get(opt);
eachSpec:
for (String spec : specs) {
if (spec.length() == 0) continue eachSpec;
if (spec.startsWith("#")) break eachSpec;
int sidx = 0;
char specop = spec.charAt(sidx++);
// Deal with '+'/'*' prefixes (spec conditions).
boolean ok;
switch (specop) {
case '+':
// + means we want an non-empty val suffix.
ok = !val.isEmpty();
specop = spec.charAt(sidx++);
break;
case '*':
// * means we accept empty or non-empty
ok = true;
specop = spec.charAt(sidx++);
break;
default:
// No condition prefix means we require an exact
// match, as indicated by an empty val suffix.
ok = (val.length() == 0);
break;
}
if (!ok) continue eachSpec;
String specarg = spec.substring(sidx);
switch (specop) {
case '.': // terminate the option sequence
resultString = specarg.isEmpty() ? opt : specarg.intern();
break doArgs;
case '?': // abort the option sequence
resultString = specarg.isEmpty() ? arg : specarg.intern();
isError = true;
break eachSpec;
case '@': // change the effective opt name
opt = specarg.intern();
break;
case '>': // shift remaining arg val to next arg
pbp.add(specarg + val); // push a new argument
val = "";
break;
case '!': // negation option
String negopt = specarg.isEmpty() ? opt : specarg.intern();
properties.remove(negopt);
properties.put(negopt, null); // leave placeholder
didAction = true;
break;
case '$': // normal "boolean" option
String boolval;
if (!specarg.isEmpty()) {
// If there is a given spec token, store it.
boolval = specarg;
} else {
String old = properties.get(opt);
if (old == null || old.length() == 0) {
boolval = "1";
} else {
// Increment any previous value as a numeral.
boolval = ""+(1+Integer.parseInt(old));
}
}
properties.put(opt, boolval);
didAction = true;
break;
case '=': // "string" option
case '&': // "collection" option
// Read an option.
boolean append = (specop == '&');
String strval;
if (pbp.hasPrevious()) {
strval = pbp.previous();
pbp.remove();
} else if (argp.hasNext()) {
strval = argp.next();
} else {
resultString = arg + " ?";
isError = true;
break eachSpec;
}
if (append) {
String old = properties.get(opt);
if (old != null) {
// Append new val to old with embedded delim.
String delim = specarg;
if (delim.length() == 0) delim = " ";
strval = old + specarg + strval;
}
}
properties.put(opt, strval);
didAction = true;
break;
default:
throw new RuntimeException(MessageFormat.format(RESOURCE.getString(DriverResource.BAD_SPEC),opt, spec));
}
}
// Done processing specs.
if (didAction && !isError) {
continue doArgs;
}
// The specs should have done something, but did not.
while (pbp.nextIndex() > pbpMark) {
// Remove anything pushed during these specs.
pbp.previous();
pbp.remove();
}
if (isError) {
throw new IllegalArgumentException(resultString);
}
if (optlen == 0) {
// We cannot try a shorter matching option.
break tryOpt;
}
}
// If we come here, there was no matching option.
// So, push back the argument, and return to caller.
pbp.add(arg);
break doArgs;
}
// Report number of arguments consumed.
args.subList(0, argp.nextIndex()).clear();
// Report any unconsumed partial argument.
while (pbp.hasPrevious()) {
args.add(0, pbp.previous());
}
//System.out.println(args+" // "+properties+" -> "+resultString);
return resultString;
}
}

View file

@ -1,136 +0,0 @@
/*
* Copyright (c) 2005, 2018, 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.ListResourceBundle;
public class DriverResource extends ListResourceBundle {
public static final String VERSION = "VERSION";
public static final String BAD_ARGUMENT = "BAD_ARGUMENT";
public static final String BAD_OPTION = "BAD_OPTION";
public static final String BAD_REPACK_OUTPUT = "BAD_REPACK_OUTPUT";
public static final String DETECTED_ZIP_COMMENT = "DETECTED_ZIP_COMMENT";
public static final String SKIP_FOR_REPACKED = "SKIP_FOR_REPACKED";
public static final String WRITE_PACK_FILE = "WRITE_PACK_FILE";
public static final String WRITE_PACKGZ_FILE = "WRITE_PACKGZ_FILE";
public static final String SKIP_FOR_MOVE_FAILED = "SKIP_FOR_MOVE_FAILED";
public static final String PACK_HELP = "PACK_HELP";
public static final String UNPACK_HELP = "UNPACK_HELP";
public static final String MORE_INFO = "MORE_INFO";
public static final String DUPLICATE_OPTION = "DUPLICATE_OPTION";
public static final String BAD_SPEC = "BAD_SPEC";
public static final String DEPRECATED = "DEPRECATED";
/*
* The following are the output of 'pack200' and 'unpack200' commands.
* Do not translate command arguments and words with a prefix of '-' or '--'.
*/
private static final Object[][] resource = {
{VERSION, "{0} version {1}"}, // parameter 0:class name;parameter 1: version value
{BAD_ARGUMENT, "Bad argument: {0}"},
{BAD_OPTION, "Bad option: {0}={1}"}, // parameter 0:option name;parameter 1:option value
{BAD_REPACK_OUTPUT, "Bad --repack output: {0}"}, // parameter 0:filename
{DETECTED_ZIP_COMMENT, "Detected ZIP comment: {0}"}, // parameter 0:comment
{SKIP_FOR_REPACKED, "Skipping because already repacked: {0}"}, // parameter 0:filename
{WRITE_PACK_FILE, "To write a *.pack file, specify --no-gzip: {0}"}, // parameter 0:filename
{WRITE_PACKGZ_FILE, "To write a *.pack.gz file, specify --gzip: {0}"}, // parameter 0:filename
{SKIP_FOR_MOVE_FAILED, "Skipping unpack because move failed: {0}"}, // parameter 0:filename
{PACK_HELP, new String[] {
"Usage: pack200 [-opt... | --option=value]... x.pack[.gz] y.jar",
"",
"Packing Options",
" -r, --repack repack or normalize a jar, suitable for ",
" signing with jarsigner",
" -g, --no-gzip output a plain pack file, suitable to be",
" compressed with a file compression utility",
" --gzip (default) post compress the pack output",
" with gzip",
" -G, --strip-debug remove debugging attributes (SourceFile,",
" LineNumberTable, LocalVariableTable",
" and LocalVariableTypeTable) while packing",
" -O, --no-keep-file-order do not transmit file ordering information",
" --keep-file-order (default) preserve input file ordering",
" -S{N}, --segment-limit={N} limit segment sizes (default unlimited)",
" -E{N}, --effort={N} packing effort (default N=5)",
" -H{h}, --deflate-hint={h} transmit deflate hint: true, false,",
" or keep (default)",
" -m{V}, --modification-time={V} transmit modtimes: latest or keep (default)",
" -P{F}, --pass-file={F} transmit the given input element(s) unchanged",
" -U{a}, --unknown-attribute={a} unknown attribute action: error, strip,",
" or pass (default)",
" -C{N}={L}, --class-attribute={N}={L} (user-defined attribute)",
" -F{N}={L}, --field-attribute={N}={L} (user-defined attribute)",
" -M{N}={L}, --method-attribute={N}={L} (user-defined attribute)",
" -D{N}={L}, --code-attribute={N}={L} (user-defined attribute)",
" -f{F}, --config-file={F} read file F for Pack200.Packer properties",
" -v, --verbose increase program verbosity",
" -q, --quiet set verbosity to lowest level",
" -l{F}, --log-file={F} output to the given log file, ",
" or '-' for System.out",
" -?, -h, --help print this help message",
" -V, --version print program version",
" -J{X} pass option X to underlying Java VM",
"",
"Notes:",
" The -P, -C, -F, -M, and -D options accumulate.",
" Example attribute definition: -C SourceFile=RUH .",
" Config. file properties are defined by the Pack200 API.",
" For meaning of -S, -E, -H-, -m, -U values, see Pack200 API.",
" Layout definitions (like RUH) are defined by JSR 200.",
"",
"Repacking mode updates the JAR file with a pack/unpack cycle:",
" pack200 [-r|--repack] [-opt | --option=value]... [repackedy.jar] y.jar\n",
"",
"Exit Status:",
" 0 if successful, >0 if an error occurred"
}
},
{UNPACK_HELP, new String[] {
"Usage: unpack200 [-opt... | --option=value]... x.pack[.gz] y.jar\n",
"",
"Unpacking Options",
" -H{h}, --deflate-hint={h} override transmitted deflate hint:",
" true, false, or keep (default)",
" -r, --remove-pack-file remove input file after unpacking",
" -v, --verbose increase program verbosity",
" -q, --quiet set verbosity to lowest level",
" -l{F}, --log-file={F} output to the given log file, or",
" '-' for System.out",
" -?, -h, --help print this help message",
" -V, --version print program version",
" -J{X} pass option X to underlying Java VM"
}
},
{MORE_INFO, "(For more information, run {0} --help .)"}, // parameter 0:command name
{DUPLICATE_OPTION, "duplicate option: {0}"}, // parameter 0:option
{BAD_SPEC, "bad spec for {0}: {1}"}, // parameter 0:option;parameter 1:specifier
{DEPRECATED, "\nWarning: The {0} tool is deprecated, and is planned for removal in a future JDK release.\n"} // parameter 0:command name
};
protected Object[][] getContents() {
return resource;
}
}

View file

@ -1,136 +0,0 @@
/*
* Copyright (c) 2005, 2018, 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.ListResourceBundle;
public class DriverResource_ja extends ListResourceBundle {
public static final String VERSION = "VERSION";
public static final String BAD_ARGUMENT = "BAD_ARGUMENT";
public static final String BAD_OPTION = "BAD_OPTION";
public static final String BAD_REPACK_OUTPUT = "BAD_REPACK_OUTPUT";
public static final String DETECTED_ZIP_COMMENT = "DETECTED_ZIP_COMMENT";
public static final String SKIP_FOR_REPACKED = "SKIP_FOR_REPACKED";
public static final String WRITE_PACK_FILE = "WRITE_PACK_FILE";
public static final String WRITE_PACKGZ_FILE = "WRITE_PACKGZ_FILE";
public static final String SKIP_FOR_MOVE_FAILED = "SKIP_FOR_MOVE_FAILED";
public static final String PACK_HELP = "PACK_HELP";
public static final String UNPACK_HELP = "UNPACK_HELP";
public static final String MORE_INFO = "MORE_INFO";
public static final String DUPLICATE_OPTION = "DUPLICATE_OPTION";
public static final String BAD_SPEC = "BAD_SPEC";
public static final String DEPRECATED = "DEPRECATED";
/*
* The following are the output of 'pack200' and 'unpack200' commands.
* Do not translate command arguments and words with a prefix of '-' or '--'.
*/
private static final Object[][] resource = {
{VERSION, "{0}\u30D0\u30FC\u30B8\u30E7\u30F3{1}"}, // parameter 0:class name;parameter 1: version value
{BAD_ARGUMENT, "\u7121\u52B9\u306A\u5F15\u6570: {0}"},
{BAD_OPTION, "\u7121\u52B9\u306A\u30AA\u30D7\u30B7\u30E7\u30F3: {0}={1}"}, // parameter 0:option name;parameter 1:option value
{BAD_REPACK_OUTPUT, "\u7121\u52B9\u306A--repack\u51FA\u529B: {0}"}, // parameter 0:filename
{DETECTED_ZIP_COMMENT, "\u691C\u51FA\u3055\u308C\u305FZIP\u30B3\u30E1\u30F3\u30C8: {0}"}, // parameter 0:comment
{SKIP_FOR_REPACKED, "\u3059\u3067\u306B\u518D\u5727\u7E2E\u3055\u308C\u3066\u3044\u308B\u305F\u3081\u30B9\u30AD\u30C3\u30D7\u3057\u3066\u3044\u307E\u3059: {0}"}, // parameter 0:filename
{WRITE_PACK_FILE, "*.pack\u30D5\u30A1\u30A4\u30EB\u3092\u66F8\u304D\u8FBC\u3080\u306B\u306F\u3001--no-gzip\u3092\u6307\u5B9A\u3057\u307E\u3059: {0}"}, // parameter 0:filename
{WRITE_PACKGZ_FILE, "*.pack.gz\u30D5\u30A1\u30A4\u30EB\u3092\u66F8\u304D\u8FBC\u3080\u306B\u306F\u3001--gzip\u3092\u6307\u5B9A\u3057\u307E\u3059: {0}"}, // parameter 0:filename
{SKIP_FOR_MOVE_FAILED, "\u79FB\u52D5\u304C\u5931\u6557\u3057\u305F\u305F\u3081\u89E3\u51CD\u3092\u30B9\u30AD\u30C3\u30D7\u3057\u3066\u3044\u307E\u3059: {0}"}, // parameter 0:filename
{PACK_HELP, new String[] {
"\u4F7F\u7528\u65B9\u6CD5: pack200 [-opt... | --option=value]... x.pack[.gz] y.jar",
"",
"\u5727\u7E2E\u30AA\u30D7\u30B7\u30E7\u30F3",
" -r\u3001--repack jar\u3092\u518D\u5727\u7E2E\u307E\u305F\u306F\u6B63\u898F\u5316\u3059\u308B\u30AA\u30D7\u30B7\u30E7\u30F3\u3067\u3001",
" jarsigner\u306B\u3088\u308B\u7F72\u540D\u306B\u9069\u3057\u307E\u3059",
" -g\u3001--no-gzip \u30D7\u30EC\u30FC\u30F3\u306Apack\u30D5\u30A1\u30A4\u30EB\u3092\u51FA\u529B\u3059\u308B\u30AA\u30D7\u30B7\u30E7\u30F3\u3067\u3001",
" \u30D5\u30A1\u30A4\u30EB\u5727\u7E2E\u30E6\u30FC\u30C6\u30A3\u30EA\u30C6\u30A3\u306B\u3088\u308B\u5727\u7E2E\u306B\u9069\u3057\u307E\u3059",
" --gzip (\u30C7\u30D5\u30A9\u30EB\u30C8) pack\u51FA\u529B\u3092\u5F8C\u51E6\u7406\u3067\u5727\u7E2E\u3057\u307E\u3059",
" (gzip\u3092\u4F7F\u7528)",
" -G\u3001--strip-debug \u5727\u7E2E\u4E2D\u306B\u30C7\u30D0\u30C3\u30B0\u5C5E\u6027(SourceFile\u3001",
" LineNumberTable\u3001LocalVariableTable",
" \u3001LocalVariableTypeTable)\u3092\u524A\u9664\u3057\u307E\u3059",
" -O\u3001--no-keep-file-order \u30D5\u30A1\u30A4\u30EB\u306E\u9806\u5E8F\u4ED8\u3051\u60C5\u5831\u3092\u8EE2\u9001\u3057\u307E\u305B\u3093",
" --keep-file-order (\u30C7\u30D5\u30A9\u30EB\u30C8)\u5165\u529B\u30D5\u30A1\u30A4\u30EB\u306E\u9806\u5E8F\u4ED8\u3051\u3092\u4FDD\u6301\u3057\u307E\u3059",
" -S{N}\u3001--segment-limit={N} \u30BB\u30B0\u30E1\u30F3\u30C8\u30FB\u30B5\u30A4\u30BA\u3092\u5236\u9650\u3057\u307E\u3059(\u30C7\u30D5\u30A9\u30EB\u30C8\u306F\u7121\u5236\u9650)",
" -E{N}\u3001--effort={N} \u5727\u7E2E\u306E\u8A66\u884C(\u30C7\u30D5\u30A9\u30EB\u30C8N=5)",
" -H{h}\u3001--deflate-hint={h} \u30C7\u30D5\u30EC\u30FC\u30C8\u30FB\u30D2\u30F3\u30C8\u3092\u8EE2\u9001\u3057\u307E\u3059: true\u3001false",
" \u307E\u305F\u306Fkeep(\u30C7\u30D5\u30A9\u30EB\u30C8)",
" -m{V}\u3001--modification-time={V} \u5909\u66F4\u6642\u9593\u3092\u8EE2\u9001\u3057\u307E\u3059: latest\u307E\u305F\u306Fkeep(\u30C7\u30D5\u30A9\u30EB\u30C8)",
" -P{F}\u3001--pass-file={F} \u6307\u5B9A\u3055\u308C\u305F\u5165\u529B\u8981\u7D20\u3092\u305D\u306E\u307E\u307E\u8EE2\u9001\u3057\u307E\u3059",
" -U{a}\u3001--unknown-attribute={a} \u4E0D\u660E\u306E\u5C5E\u6027\u30A2\u30AF\u30B7\u30E7\u30F3: error\u3001strip",
" \u307E\u305F\u306Fpass(\u30C7\u30D5\u30A9\u30EB\u30C8)",
" -C{N}={L}\u3001--class-attribute={N}={L} (\u30E6\u30FC\u30B6\u30FC\u5B9A\u7FA9\u5C5E\u6027)",
" -F{N}={L}\u3001--field-attribute={N}={L} (\u30E6\u30FC\u30B6\u30FC\u5B9A\u7FA9\u5C5E\u6027)",
" -M{N}={L}\u3001--method-attribute={N}={L} (\u30E6\u30FC\u30B6\u30FC\u5B9A\u7FA9\u5C5E\u6027)",
" -D{N}={L}\u3001--code-attribute={N}={L} (\u30E6\u30FC\u30B6\u30FC\u5B9A\u7FA9\u5C5E\u6027)",
" -f{F}\u3001--config-file={F} Pack200.Packer\u30D7\u30ED\u30D1\u30C6\u30A3\u306B\u30D5\u30A1\u30A4\u30EBF\u3092\u8AAD\u307F\u8FBC\u307F\u307E\u3059",
" -v\u3001--verbose \u30D7\u30ED\u30B0\u30E9\u30E0\u306E\u5197\u9577\u6027\u3092\u9AD8\u3081\u307E\u3059",
" -q\u3001--quiet \u5197\u9577\u6027\u3092\u6700\u4F4E\u30EC\u30D9\u30EB\u306B\u8A2D\u5B9A\u3057\u307E\u3059",
" -l{F}\u3001--log-file={F} \u6307\u5B9A\u306E\u30ED\u30B0\u30FB\u30D5\u30A1\u30A4\u30EB\u307E\u305F\u306FSystem.out ",
" ('-'\u306E\u5834\u5408)\u306B\u51FA\u529B\u3057\u307E\u3059",
" -?\u3001-h\u3001--help \u3053\u306E\u30D8\u30EB\u30D7\u30FB\u30E1\u30C3\u30BB\u30FC\u30B8\u3092\u51FA\u529B\u3057\u307E\u3059",
" -V\u3001--version \u30D7\u30ED\u30B0\u30E9\u30E0\u306E\u30D0\u30FC\u30B8\u30E7\u30F3\u3092\u51FA\u529B\u3057\u307E\u3059",
" -J{X} \u30AA\u30D7\u30B7\u30E7\u30F3X\u3092\u57FA\u790E\u3068\u306A\u308BJava VM\u306B\u6E21\u3057\u307E\u3059",
"",
"\u6CE8:",
" -P\u3001-C\u3001-F\u3001-M\u304A\u3088\u3073-D\u30AA\u30D7\u30B7\u30E7\u30F3\u306F\u7D2F\u7A4D\u3055\u308C\u307E\u3059\u3002",
" \u5C5E\u6027\u5B9A\u7FA9\u306E\u4F8B: -C SourceFile=RUH .",
" Config.\u30D5\u30A1\u30A4\u30EB\u30FB\u30D7\u30ED\u30D1\u30C6\u30A3\u306F\u3001Pack200 API\u306B\u3088\u3063\u3066\u5B9A\u7FA9\u3055\u308C\u307E\u3059\u3002",
" -S\u3001-E\u3001-H\u3001-m\u3001-U\u306E\u5024\u306E\u610F\u5473\u306F\u3001Pack200 API\u3092\u53C2\u7167\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
" \u30EC\u30A4\u30A2\u30A6\u30C8\u5B9A\u7FA9(RUH\u306A\u3069)\u306FJSR 200\u306B\u3088\u3063\u3066\u5B9A\u7FA9\u3055\u308C\u307E\u3059\u3002",
"",
"\u518D\u5727\u7E2E\u30E2\u30FC\u30C9\u3067\u306F\u3001JAR\u30D5\u30A1\u30A4\u30EB\u304C\u5727\u7E2E/\u89E3\u51CD\u30B5\u30A4\u30AF\u30EB\u3067\u66F4\u65B0\u3055\u308C\u307E\u3059:",
" pack200 [-r|--repack] [-opt | --option=value]... [repackedy.jar] y.jar\n",
"",
"\u7D42\u4E86\u30B9\u30C6\u30FC\u30BF\u30B9:",
" 0 (\u6210\u529F\u3057\u305F\u5834\u5408)\u3001>0 (\u30A8\u30E9\u30FC\u304C\u767A\u751F\u3057\u305F\u5834\u5408)"
}
},
{UNPACK_HELP, new String[] {
"\u4F7F\u7528\u65B9\u6CD5: unpack200 [-opt... | --option=value]... x.pack[.gz] y.jar\n",
"",
"\u89E3\u51CD\u30AA\u30D7\u30B7\u30E7\u30F3",
" -H{h}\u3001--deflate-hint={h} \u8EE2\u9001\u3055\u308C\u305F\u30C7\u30D5\u30EC\u30FC\u30C8\u30FB\u30D2\u30F3\u30C8\u3092\u30AA\u30FC\u30D0\u30FC\u30E9\u30A4\u30C9\u3057\u307E\u3059:",
" true\u3001false\u307E\u305F\u306Fkeep(\u30C7\u30D5\u30A9\u30EB\u30C8)",
" -r\u3001--remove-pack-file \u89E3\u51CD\u5F8C\u306B\u5165\u529B\u30D5\u30A1\u30A4\u30EB\u3092\u524A\u9664\u3057\u307E\u3059",
" -v\u3001--verbose \u30D7\u30ED\u30B0\u30E9\u30E0\u306E\u5197\u9577\u6027\u3092\u9AD8\u3081\u307E\u3059",
" -q\u3001--quiet \u5197\u9577\u6027\u3092\u6700\u4F4E\u30EC\u30D9\u30EB\u306B\u8A2D\u5B9A\u3057\u307E\u3059",
" -l{F}\u3001--log-file={F} \u6307\u5B9A\u306E\u30ED\u30B0\u30FB\u30D5\u30A1\u30A4\u30EB\u307E\u305F\u306F",
" System.out ('-'\u306E\u5834\u5408)\u306B\u51FA\u529B\u3057\u307E\u3059",
" -?\u3001-h\u3001--help \u3053\u306E\u30D8\u30EB\u30D7\u30FB\u30E1\u30C3\u30BB\u30FC\u30B8\u3092\u51FA\u529B\u3057\u307E\u3059",
" -V\u3001--version \u30D7\u30ED\u30B0\u30E9\u30E0\u306E\u30D0\u30FC\u30B8\u30E7\u30F3\u3092\u51FA\u529B\u3057\u307E\u3059",
" -J{X} \u30AA\u30D7\u30B7\u30E7\u30F3X\u3092\u57FA\u790E\u3068\u306A\u308BJava VM\u306B\u6E21\u3057\u307E\u3059"
}
},
{MORE_INFO, "(\u8A73\u7D30\u306F\u3001{0} --help\u3092\u5B9F\u884C\u3057\u3066\u304F\u3060\u3055\u3044\u3002)"}, // parameter 0:command name
{DUPLICATE_OPTION, "\u91CD\u8907\u30AA\u30D7\u30B7\u30E7\u30F3: {0}"}, // parameter 0:option
{BAD_SPEC, "{0}\u306E\u7121\u52B9\u306A\u4ED5\u69D8: {1}"}, // parameter 0:option;parameter 1:specifier
{DEPRECATED, "\n\u8B66\u544A: {0}\u30C4\u30FC\u30EB\u306F\u975E\u63A8\u5968\u3067\u3042\u308A\u3001\u4ECA\u5F8C\u306EJDK\u30EA\u30EA\u30FC\u30B9\u3067\u524A\u9664\u3055\u308C\u308B\u4E88\u5B9A\u3067\u3059\u3002\n"} // parameter 0:command name
};
protected Object[][] getContents() {
return resource;
}
}

View file

@ -1,136 +0,0 @@
/*
* Copyright (c) 2005, 2018, 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.ListResourceBundle;
public class DriverResource_zh_CN extends ListResourceBundle {
public static final String VERSION = "VERSION";
public static final String BAD_ARGUMENT = "BAD_ARGUMENT";
public static final String BAD_OPTION = "BAD_OPTION";
public static final String BAD_REPACK_OUTPUT = "BAD_REPACK_OUTPUT";
public static final String DETECTED_ZIP_COMMENT = "DETECTED_ZIP_COMMENT";
public static final String SKIP_FOR_REPACKED = "SKIP_FOR_REPACKED";
public static final String WRITE_PACK_FILE = "WRITE_PACK_FILE";
public static final String WRITE_PACKGZ_FILE = "WRITE_PACKGZ_FILE";
public static final String SKIP_FOR_MOVE_FAILED = "SKIP_FOR_MOVE_FAILED";
public static final String PACK_HELP = "PACK_HELP";
public static final String UNPACK_HELP = "UNPACK_HELP";
public static final String MORE_INFO = "MORE_INFO";
public static final String DUPLICATE_OPTION = "DUPLICATE_OPTION";
public static final String BAD_SPEC = "BAD_SPEC";
public static final String DEPRECATED = "DEPRECATED";
/*
* The following are the output of 'pack200' and 'unpack200' commands.
* Do not translate command arguments and words with a prefix of '-' or '--'.
*/
private static final Object[][] resource = {
{VERSION, "{0}\u7248\u672C {1}"}, // parameter 0:class name;parameter 1: version value
{BAD_ARGUMENT, "\u9519\u8BEF\u53C2\u6570: {0}"},
{BAD_OPTION, "\u9519\u8BEF\u9009\u9879: {0}={1}"}, // parameter 0:option name;parameter 1:option value
{BAD_REPACK_OUTPUT, "--repack \u8F93\u51FA\u9519\u8BEF: {0}"}, // parameter 0:filename
{DETECTED_ZIP_COMMENT, "\u68C0\u6D4B\u5230 ZIP \u6CE8\u91CA: {0}"}, // parameter 0:comment
{SKIP_FOR_REPACKED, "\u7531\u4E8E\u5DF2\u91CD\u65B0\u6253\u5305\u800C\u8DF3\u8FC7: {0}"}, // parameter 0:filename
{WRITE_PACK_FILE, "\u8981\u5199\u5165 *.pack \u6587\u4EF6, \u8BF7\u6307\u5B9A --no-gzip: {0}"}, // parameter 0:filename
{WRITE_PACKGZ_FILE, "\u8981\u5199\u5165 *.pack.gz \u6587\u4EF6, \u8BF7\u6307\u5B9A --gzip: {0}"}, // parameter 0:filename
{SKIP_FOR_MOVE_FAILED, "\u7531\u4E8E\u79FB\u52A8\u5931\u8D25\u800C\u8DF3\u8FC7\u89E3\u5305: {0}"}, // parameter 0:filename
{PACK_HELP, new String[] {
"\u7528\u6CD5: pack200 [-opt... | --option=value]... x.pack[.gz] y.jar",
"",
"\u6253\u5305\u9009\u9879",
" -r, --repack \u518D\u6B21\u6253\u5305\u6216\u89C4\u8303\u5316 jar, \u9002\u5408\u4E8E ",
" \u4F7F\u7528 jarsigner \u8FDB\u884C\u7B7E\u540D",
" -g, --no-gzip \u8F93\u51FA\u65E0\u683C\u5F0F\u7684\u5305\u6587\u4EF6, \u9002\u5408\u4E8E",
" \u4F7F\u7528\u6587\u4EF6\u538B\u7F29\u5B9E\u7528\u7A0B\u5E8F\u8FDB\u884C\u538B\u7F29",
" --gzip (\u9ED8\u8BA4\u503C) \u4F7F\u7528 gzip \u5BF9\u5305\u8F93\u51FA\u8FDB\u884C",
" \u538B\u7F29\u540E\u5904\u7406",
" -G, --strip-debug \u6253\u5305\u65F6\u5220\u9664\u8C03\u8BD5\u5C5E\u6027 (SourceFile,",
" LineNumberTable, LocalVariableTable",
" \u548C LocalVariableTypeTable)",
" -O, --no-keep-file-order \u4E0D\u4F20\u8F93\u6587\u4EF6\u6392\u5E8F\u4FE1\u606F",
" --keep-file-order (\u9ED8\u8BA4\u503C) \u4FDD\u7559\u8F93\u5165\u6587\u4EF6\u6392\u5E8F",
" -S{N}, --segment-limit={N} \u9650\u5236\u6BB5\u5927\u5C0F (\u9ED8\u8BA4\u4E3A\u65E0\u9650\u5236)",
" -E{N}, --effort={N} \u6253\u5305\u6548\u679C (\u9ED8\u8BA4\u503C N=5)",
" -H{h}, --deflate-hint={h} \u4F20\u8F93\u538B\u7F29\u63D0\u793A: true, false",
" \u6216 keep (\u9ED8\u8BA4\u503C)",
" -m{V}, --modification-time={V} \u4F20\u8F93 modtimes: latest \u6216 keep (\u9ED8\u8BA4\u503C)",
" -P{F}, --pass-file={F} \u4F20\u8F93\u672A\u66F4\u6539\u7684\u7ED9\u5B9A\u8F93\u5165\u5143\u7D20",
" -U{a}, --unknown-attribute={a} \u672A\u77E5\u5C5E\u6027\u64CD\u4F5C: error, strip",
" \u6216 pass (\u9ED8\u8BA4\u503C)",
" -C{N}={L}, --class-attribute={N}={L} (\u7528\u6237\u5B9A\u4E49\u7684\u5C5E\u6027)",
" -F{N}={L}, --field-attribute={N}={L} (\u7528\u6237\u5B9A\u4E49\u7684\u5C5E\u6027)",
" -M{N}={L}, --method-attribute={N}={L} (\u7528\u6237\u5B9A\u4E49\u7684\u5C5E\u6027)",
" -D{N}={L}, --code-attribute={N}={L} (\u7528\u6237\u5B9A\u4E49\u7684\u5C5E\u6027)",
" -f{F}, --config-file={F} \u8BFB\u53D6\u6587\u4EF6 F \u7684 Pack200.Packer \u5C5E\u6027",
" -v, --verbose \u63D0\u9AD8\u7A0B\u5E8F\u8BE6\u7EC6\u7A0B\u5EA6",
" -q, --quiet \u5C06\u8BE6\u7EC6\u7A0B\u5EA6\u8BBE\u7F6E\u4E3A\u6700\u4F4E\u7EA7\u522B",
" -l{F}, --log-file={F} \u8F93\u51FA\u5230\u7ED9\u5B9A\u65E5\u5FD7\u6587\u4EF6, ",
" \u6216\u5BF9\u4E8E System.out \u6307\u5B9A '-'",
" -?, -h, --help \u8F93\u51FA\u6B64\u5E2E\u52A9\u6D88\u606F",
" -V, --version \u8F93\u51FA\u7A0B\u5E8F\u7248\u672C",
" -J{X} \u5C06\u9009\u9879 X \u4F20\u9012\u7ED9\u57FA\u7840 Java VM",
"",
"\u6CE8:",
" -P, -C, -F, -M \u548C -D \u9009\u9879\u7D2F\u8BA1\u3002",
" \u793A\u4F8B\u5C5E\u6027\u5B9A\u4E49: -C SourceFile=RUH\u3002",
" Config. \u6587\u4EF6\u5C5E\u6027\u7531 Pack200 API \u5B9A\u4E49\u3002",
" \u6709\u5173 -S, -E, -H-, -m, -U \u503C\u7684\u542B\u4E49, \u8BF7\u53C2\u9605 Pack200 API\u3002",
" \u5E03\u5C40\u5B9A\u4E49 (\u4F8B\u5982 RUH) \u7531 JSR 200 \u5B9A\u4E49\u3002",
"",
"\u91CD\u65B0\u6253\u5305\u6A21\u5F0F\u901A\u8FC7\u6253\u5305/\u89E3\u5305\u5468\u671F\u66F4\u65B0 JAR \u6587\u4EF6:",
" pack200 [-r|--repack] [-opt | --option=value]... [repackedy.jar] y.jar\n",
"",
"\u9000\u51FA\u72B6\u6001:",
" \u5982\u679C\u6210\u529F\u5219\u4E3A 0; \u5982\u679C\u51FA\u73B0\u9519\u8BEF, \u5219\u4E3A\u5927\u4E8E 0 \u7684\u503C"
}
},
{UNPACK_HELP, new String[] {
"\u7528\u6CD5: unpack200 [-opt... | --option=value]... x.pack[.gz] y.jar\n",
"",
"\u89E3\u5305\u9009\u9879",
" -H{h}, --deflate-hint={h} \u8986\u76D6\u5DF2\u4F20\u8F93\u7684\u538B\u7F29\u63D0\u793A:",
" true, false \u6216 keep (\u9ED8\u8BA4\u503C)",
" -r, --remove-pack-file \u89E3\u5305\u4E4B\u540E\u5220\u9664\u8F93\u5165\u6587\u4EF6",
" -v, --verbose \u63D0\u9AD8\u7A0B\u5E8F\u8BE6\u7EC6\u7A0B\u5EA6",
" -q, --quiet \u5C06\u8BE6\u7EC6\u7A0B\u5EA6\u8BBE\u7F6E\u4E3A\u6700\u4F4E\u7EA7\u522B",
" -l{F}, --log-file={F} \u8F93\u51FA\u5230\u7ED9\u5B9A\u65E5\u5FD7\u6587\u4EF6, \u6216",
" \u5BF9\u4E8E System.out \u6307\u5B9A '-'",
" -?, -h, --help \u8F93\u51FA\u6B64\u5E2E\u52A9\u6D88\u606F",
" -V, --version \u8F93\u51FA\u7A0B\u5E8F\u7248\u672C",
" -J{X} \u5C06\u9009\u9879 X \u4F20\u9012\u7ED9\u57FA\u7840 Java VM"
}
},
{MORE_INFO, "(\u6709\u5173\u8BE6\u7EC6\u4FE1\u606F, \u8BF7\u8FD0\u884C {0} --help\u3002)"}, // parameter 0:command name
{DUPLICATE_OPTION, "\u91CD\u590D\u7684\u9009\u9879: {0}"}, // parameter 0:option
{BAD_SPEC, "{0}\u7684\u89C4\u8303\u9519\u8BEF: {1}"}, // parameter 0:option;parameter 1:specifier
{DEPRECATED, "\n\u8B66\u544A\uFF1A{0} \u5DE5\u5177\u5DF2\u8FC7\u65F6\uFF0C\u8BA1\u5212\u5728\u672A\u6765\u7684 JDK \u53D1\u884C\u7248\u4E2D\u5220\u9664\u3002\n"} // parameter 0:command name
};
protected Object[][] getContents() {
return resource;
}
}

View file

@ -1,174 +0,0 @@
/*
* Copyright (c) 2010, 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.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
/*
* @author ksrini
*/
/*
* This class provides an ArrayList implementation which has a fixed size,
* thus all the operations which modifies the size have been rendered
* inoperative. This essentially allows us to use generified array
* lists in lieu of arrays.
*/
final class FixedList<E> implements List<E> {
private final ArrayList<E> flist;
protected FixedList(int capacity) {
flist = new ArrayList<>(capacity);
// initialize the list to null
for (int i = 0 ; i < capacity ; i++) {
flist.add(null);
}
}
@Override
public int size() {
return flist.size();
}
@Override
public boolean isEmpty() {
return flist.isEmpty();
}
@Override
public boolean contains(Object o) {
return flist.contains(o);
}
@Override
public Iterator<E> iterator() {
return flist.iterator();
}
@Override
public Object[] toArray() {
return flist.toArray();
}
@Override
public <T> T[] toArray(T[] a) {
return flist.toArray(a);
}
@Override
public boolean add(E e) throws UnsupportedOperationException {
throw new UnsupportedOperationException("operation not permitted");
}
@Override
public boolean remove(Object o) throws UnsupportedOperationException {
throw new UnsupportedOperationException("operation not permitted");
}
@Override
public boolean containsAll(Collection<?> c) {
return flist.containsAll(c);
}
@Override
public boolean addAll(Collection<? extends E> c) throws UnsupportedOperationException {
throw new UnsupportedOperationException("operation not permitted");
}
@Override
public boolean addAll(int index, Collection<? extends E> c) throws UnsupportedOperationException {
throw new UnsupportedOperationException("operation not permitted");
}
@Override
public boolean removeAll(Collection<?> c) throws UnsupportedOperationException {
throw new UnsupportedOperationException("operation not permitted");
}
@Override
public boolean retainAll(Collection<?> c) throws UnsupportedOperationException {
throw new UnsupportedOperationException("operation not permitted");
}
@Override
public void clear() throws UnsupportedOperationException {
throw new UnsupportedOperationException("operation not permitted");
}
@Override
public E get(int index) {
return flist.get(index);
}
@Override
public E set(int index, E element) {
return flist.set(index, element);
}
@Override
public void add(int index, E element) throws UnsupportedOperationException {
throw new UnsupportedOperationException("operation not permitted");
}
@Override
public E remove(int index) throws UnsupportedOperationException {
throw new UnsupportedOperationException("operation not permitted");
}
@Override
public int indexOf(Object o) {
return flist.indexOf(o);
}
@Override
public int lastIndexOf(Object o) {
return flist.lastIndexOf(o);
}
@Override
public ListIterator<E> listIterator() {
return flist.listIterator();
}
@Override
public ListIterator<E> listIterator(int index) {
return flist.listIterator(index);
}
@Override
public List<E> subList(int fromIndex, int toIndex) {
return flist.subList(fromIndex, toIndex);
}
@Override
public String toString() {
return "FixedList{" + "plist=" + flist + '}';
}
}

View file

@ -1,570 +0,0 @@
/*
* Copyright (c) 2003, 2013, 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 com.sun.java.util.jar.pack.ConstantPool.Entry;
import java.util.AbstractCollection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.Objects;
/**
* Collection of relocatable constant pool references.
* It operates with respect to a particular byte array,
* and stores some of its state in the bytes themselves.
* <p>
* As a Collection, it can be iterated over, but it is not a List,
* since it does not natively support indexed access.
* <p>
*
* @author John Rose
*/
final class Fixups extends AbstractCollection<Fixups.Fixup> {
byte[] bytes; // the subject of the relocations
int head; // desc locating first reloc
int tail; // desc locating last reloc
int size; // number of relocations
Entry[] entries; // [0..size-1] relocations
int[] bigDescs; // descs which cannot be stored in the bytes
// A "desc" (descriptor) is a bit-encoded pair of a location
// and format. Every fixup occurs at a "desc". Until final
// patching, bytes addressed by descs may also be used to
// link this data structure together. If the bytes are missing,
// or if the "desc" is too large to encode in the bytes,
// it is kept in the bigDescs array.
Fixups(byte[] bytes) {
this.bytes = bytes;
entries = new Entry[3];
bigDescs = noBigDescs;
}
Fixups() {
// If there are no bytes, all descs are kept in bigDescs.
this((byte[])null);
}
Fixups(byte[] bytes, Collection<Fixup> fixups) {
this(bytes);
addAll(fixups);
}
Fixups(Collection<Fixup> fixups) {
this((byte[])null);
addAll(fixups);
}
private static final int MINBIGSIZE = 1;
// cleverly share empty bigDescs:
private static final int[] noBigDescs = {MINBIGSIZE};
@Override
public int size() {
return size;
}
public void trimToSize() {
if (size != entries.length) {
Entry[] oldEntries = entries;
entries = new Entry[size];
System.arraycopy(oldEntries, 0, entries, 0, size);
}
int bigSize = bigDescs[BIGSIZE];
if (bigSize == MINBIGSIZE) {
bigDescs = noBigDescs;
} else if (bigSize != bigDescs.length) {
int[] oldBigDescs = bigDescs;
bigDescs = new int[bigSize];
System.arraycopy(oldBigDescs, 0, bigDescs, 0, bigSize);
}
}
public void visitRefs(Collection<Entry> refs) {
for (int i = 0; i < size; i++) {
refs.add(entries[i]);
}
}
@Override
public void clear() {
if (bytes != null) {
// Clean the bytes:
for (Fixup fx : this) {
//System.out.println("clean "+fx);
storeIndex(fx.location(), fx.format(), 0);
}
}
size = 0;
if (bigDescs != noBigDescs)
bigDescs[BIGSIZE] = MINBIGSIZE;
// do not trim to size, however
}
public byte[] getBytes() {
return bytes;
}
public void setBytes(byte[] newBytes) {
if (bytes == newBytes) return;
ArrayList<Fixup> old = null;
assert((old = new ArrayList<>(this)) != null);
if (bytes == null || newBytes == null) {
// One or the other representations is deficient.
// Construct a checkpoint.
ArrayList<Fixup> save = new ArrayList<>(this);
clear();
bytes = newBytes;
addAll(save);
} else {
// assume newBytes is some sort of bitwise copy of the old bytes
bytes = newBytes;
}
assert(old.equals(new ArrayList<>(this)));
}
private static final int LOC_SHIFT = 1;
private static final int FMT_MASK = 0x1;
private static final byte UNUSED_BYTE = 0;
private static final byte OVERFLOW_BYTE = -1;
// fill pointer of bigDescs array is in element [0]
private static final int BIGSIZE = 0;
// Format values:
private static final int U2_FORMAT = 0;
private static final int U1_FORMAT = 1;
// Special values for the static methods.
private static final int SPECIAL_LOC = 0;
private static final int SPECIAL_FMT = U2_FORMAT;
static int fmtLen(int fmt) { return 1+(fmt-U1_FORMAT)/(U2_FORMAT-U1_FORMAT); }
static int descLoc(int desc) { return desc >>> LOC_SHIFT; }
static int descFmt(int desc) { return desc & FMT_MASK; }
static int descEnd(int desc) { return descLoc(desc) + fmtLen(descFmt(desc)); }
static int makeDesc(int loc, int fmt) {
int desc = (loc << LOC_SHIFT) | fmt;
assert(descLoc(desc) == loc);
assert(descFmt(desc) == fmt);
return desc;
}
int fetchDesc(int loc, int fmt) {
byte b1 = bytes[loc];
assert(b1 != OVERFLOW_BYTE);
int value;
if (fmt == U2_FORMAT) {
byte b2 = bytes[loc+1];
value = ((b1 & 0xFF) << 8) + (b2 & 0xFF);
} else {
value = (b1 & 0xFF);
}
// Stored loc field is difference between its own loc and next loc.
return value + (loc << LOC_SHIFT);
}
boolean storeDesc(int loc, int fmt, int desc) {
if (bytes == null)
return false;
int value = desc - (loc << LOC_SHIFT);
byte b1, b2;
switch (fmt) {
case U2_FORMAT:
assert(bytes[loc+0] == UNUSED_BYTE);
assert(bytes[loc+1] == UNUSED_BYTE);
b1 = (byte)(value >> 8);
b2 = (byte)(value >> 0);
if (value == (value & 0xFFFF) && b1 != OVERFLOW_BYTE) {
bytes[loc+0] = b1;
bytes[loc+1] = b2;
assert(fetchDesc(loc, fmt) == desc);
return true;
}
break;
case U1_FORMAT:
assert(bytes[loc] == UNUSED_BYTE);
b1 = (byte)value;
if (value == (value & 0xFF) && b1 != OVERFLOW_BYTE) {
bytes[loc] = b1;
assert(fetchDesc(loc, fmt) == desc);
return true;
}
break;
default: assert(false);
}
// Failure. Caller must allocate a bigDesc.
bytes[loc] = OVERFLOW_BYTE;
assert(fmt==U1_FORMAT || (bytes[loc+1]=(byte)bigDescs[BIGSIZE])!=999);
return false;
}
void storeIndex(int loc, int fmt, int value) {
storeIndex(bytes, loc, fmt, value);
}
static
void storeIndex(byte[] bytes, int loc, int fmt, int value) {
switch (fmt) {
case U2_FORMAT:
assert(value == (value & 0xFFFF)) : (value);
bytes[loc+0] = (byte)(value >> 8);
bytes[loc+1] = (byte)(value >> 0);
break;
case U1_FORMAT:
assert(value == (value & 0xFF)) : (value);
bytes[loc] = (byte)value;
break;
default: assert(false);
}
}
void addU1(int pc, Entry ref) {
add(pc, U1_FORMAT, ref);
}
void addU2(int pc, Entry ref) {
add(pc, U2_FORMAT, ref);
}
/** Simple and necessary tuple to present each fixup. */
public static
class Fixup implements Comparable<Fixup> {
int desc; // location and format of reloc
Entry entry; // which entry to plug into the bytes
Fixup(int desc, Entry entry) {
this.desc = desc;
this.entry = entry;
}
public Fixup(int loc, int fmt, Entry entry) {
this.desc = makeDesc(loc, fmt);
this.entry = entry;
}
public int location() { return descLoc(desc); }
public int format() { return descFmt(desc); }
public Entry entry() { return entry; }
@Override
public int compareTo(Fixup that) {
// Ordering depends only on location.
return this.location() - that.location();
}
@Override
public boolean equals(Object x) {
if (!(x instanceof Fixup)) return false;
Fixup that = (Fixup) x;
return this.desc == that.desc && this.entry == that.entry;
}
@Override
public int hashCode() {
int hash = 7;
hash = 59 * hash + this.desc;
hash = 59 * hash + Objects.hashCode(this.entry);
return hash;
}
@Override
public String toString() {
return "@"+location()+(format()==U1_FORMAT?".1":"")+"="+entry;
}
}
private
class Itr implements Iterator<Fixup> {
int index = 0; // index into entries
int bigIndex = BIGSIZE+1; // index into bigDescs
int next = head; // desc pointing to next fixup
@Override
public boolean hasNext() { return index < size; }
@Override
public void remove() { throw new UnsupportedOperationException(); }
@Override
public Fixup next() {
int thisIndex = index;
return new Fixup(nextDesc(), entries[thisIndex]);
}
int nextDesc() {
index++;
int thisDesc = next;
if (index < size) {
// Fetch next desc eagerly, in case this fixup gets finalized.
int loc = descLoc(thisDesc);
int fmt = descFmt(thisDesc);
if (bytes != null && bytes[loc] != OVERFLOW_BYTE) {
next = fetchDesc(loc, fmt);
} else {
// The unused extra byte is "asserted" to be equal to BI.
// This helps keep the overflow descs in sync.
assert(fmt==U1_FORMAT || bytes == null || bytes[loc+1]==(byte)bigIndex);
next = bigDescs[bigIndex++];
}
}
return thisDesc;
}
}
@Override
public Iterator<Fixup> iterator() {
return new Itr();
}
public void add(int location, int format, Entry entry) {
addDesc(makeDesc(location, format), entry);
}
@Override
public boolean add(Fixup f) {
addDesc(f.desc, f.entry);
return true;
}
@Override
public boolean addAll(Collection<? extends Fixup> c) {
if (c instanceof Fixups) {
// Use knowledge of Itr structure to avoid building little structs.
Fixups that = (Fixups) c;
if (that.size == 0) return false;
if (this.size == 0 && entries.length < that.size)
growEntries(that.size); // presize exactly
Entry[] thatEntries = that.entries;
for (Itr i = that.new Itr(); i.hasNext(); ) {
int ni = i.index;
addDesc(i.nextDesc(), thatEntries[ni]);
}
return true;
} else {
return super.addAll(c);
}
}
// Here is how things get added:
private void addDesc(int thisDesc, Entry entry) {
if (entries.length == size)
growEntries(size * 2);
entries[size] = entry;
if (size == 0) {
head = tail = thisDesc;
} else {
int prevDesc = tail;
// Store new desc in previous tail.
int prevLoc = descLoc(prevDesc);
int prevFmt = descFmt(prevDesc);
int prevLen = fmtLen(prevFmt);
int thisLoc = descLoc(thisDesc);
// The collection must go in ascending order, and not overlap.
if (thisLoc < prevLoc + prevLen)
badOverlap(thisLoc);
tail = thisDesc;
if (!storeDesc(prevLoc, prevFmt, thisDesc)) {
// overflow
int bigSize = bigDescs[BIGSIZE];
if (bigDescs.length == bigSize)
growBigDescs();
//System.out.println("bigDescs["+bigSize+"] = "+thisDesc);
bigDescs[bigSize++] = thisDesc;
bigDescs[BIGSIZE] = bigSize;
}
}
size += 1;
}
private void badOverlap(int thisLoc) {
throw new IllegalArgumentException("locs must be ascending and must not overlap: "+thisLoc+" >> "+this);
}
private void growEntries(int newSize) {
Entry[] oldEntries = entries;
entries = new Entry[Math.max(3, newSize)];
System.arraycopy(oldEntries, 0, entries, 0, oldEntries.length);
}
private void growBigDescs() {
int[] oldBigDescs = bigDescs;
bigDescs = new int[oldBigDescs.length * 2];
System.arraycopy(oldBigDescs, 0, bigDescs, 0, oldBigDescs.length);
}
/// Static methods that optimize the use of this class.
static Object addRefWithBytes(Object f, byte[] bytes, Entry e) {
return add(f, bytes, 0, U2_FORMAT, e);
}
static Object addRefWithLoc(Object f, int loc, Entry entry) {
return add(f, null, loc, U2_FORMAT, entry);
}
private static
Object add(Object prevFixups,
byte[] bytes, int loc, int fmt,
Entry e) {
Fixups f;
if (prevFixups == null) {
if (loc == SPECIAL_LOC && fmt == SPECIAL_FMT) {
// Special convention: If the attribute has a
// U2 relocation at position zero, store the Entry
// rather than building a Fixups structure.
return e;
}
f = new Fixups(bytes);
} else if (!(prevFixups instanceof Fixups)) {
// Recognize the special convention:
Entry firstEntry = (Entry) prevFixups;
f = new Fixups(bytes);
f.add(SPECIAL_LOC, SPECIAL_FMT, firstEntry);
} else {
f = (Fixups) prevFixups;
assert(f.bytes == bytes);
}
f.add(loc, fmt, e);
return f;
}
public static
void setBytes(Object fixups, byte[] bytes) {
if (fixups instanceof Fixups) {
Fixups f = (Fixups) fixups;
f.setBytes(bytes);
}
}
public static
Object trimToSize(Object fixups) {
if (fixups instanceof Fixups) {
Fixups f = (Fixups) fixups;
f.trimToSize();
if (f.size() == 0)
fixups = null;
}
return fixups;
}
// Iterate over all the references in this set of fixups.
public static
void visitRefs(Object fixups, Collection<Entry> refs) {
if (fixups == null) {
} else if (!(fixups instanceof Fixups)) {
// Special convention; see above.
refs.add((Entry) fixups);
} else {
Fixups f = (Fixups) fixups;
f.visitRefs(refs);
}
}
// Clear out this set of fixups by replacing each reference
// by a hardcoded coding of its reference, drawn from ix.
public static
void finishRefs(Object fixups, byte[] bytes, ConstantPool.Index ix) {
if (fixups == null)
return;
if (!(fixups instanceof Fixups)) {
// Special convention; see above.
int index = ix.indexOf((Entry) fixups);
storeIndex(bytes, SPECIAL_LOC, SPECIAL_FMT, index);
return;
}
Fixups f = (Fixups) fixups;
assert(f.bytes == bytes);
f.finishRefs(ix);
}
void finishRefs(ConstantPool.Index ix) {
if (isEmpty())
return;
for (Fixup fx : this) {
int index = ix.indexOf(fx.entry);
//System.out.println("finish "+fx+" = "+index);
// Note that the iterator has already fetched the
// bytes we are about to overwrite.
storeIndex(fx.location(), fx.format(), index);
}
// Further iterations should do nothing:
bytes = null; // do not clean them
clear();
}
/*
/// Testing.
public static void main(String[] av) {
byte[] bytes = new byte[1 << 20];
ConstantPool cp = new ConstantPool();
Fixups f = new Fixups(bytes);
boolean isU1 = false;
int span = 3;
int nextLoc = 0;
int[] locs = new int[100];
final int[] indexes = new int[100];
int iptr = 1;
for (int loc = 0; loc < bytes.length; loc++) {
if (loc == nextLoc && loc+1 < bytes.length) {
int fmt = (isU1 ? U1_FORMAT : U2_FORMAT);
Entry e = ConstantPool.getUtf8Entry("L"+loc);
f.add(loc, fmt, e);
isU1 ^= true;
if (iptr < 10) {
// Make it close in.
nextLoc += fmtLen(fmt) + (iptr < 5 ? 0 : 1);
} else {
nextLoc += span;
span = (int)(span * 1.77);
}
// Here are the bytes that would have gone here:
locs[iptr] = loc;
if (fmt == U1_FORMAT) {
indexes[iptr++] = (loc & 0xFF);
} else {
indexes[iptr++] = ((loc & 0xFF) << 8) | ((loc+1) & 0xFF);
++loc; // skip a byte
}
continue;
}
bytes[loc] = (byte)loc;
}
System.out.println("size="+f.size()
+" overflow="+(f.bigDescs[BIGSIZE]-1));
System.out.println("Fixups: "+f);
// Test collection contents.
assert(iptr == 1+f.size());
List l = new ArrayList(f);
Collections.sort(l); // should not change the order
if (!l.equals(new ArrayList(f))) System.out.println("** disordered");
f.setBytes(null);
if (!l.equals(new ArrayList(f))) System.out.println("** bad set 1");
f.setBytes(bytes);
if (!l.equals(new ArrayList(f))) System.out.println("** bad set 2");
Fixups f3 = new Fixups(f);
if (!l.equals(new ArrayList(f3))) System.out.println("** bad set 3");
Iterator fi = f.iterator();
for (int i = 1; i < iptr; i++) {
Fixup fx = (Fixup) fi.next();
if (fx.location() != locs[i]) {
System.out.println("** "+fx+" != "+locs[i]);
}
if (fx.format() == U1_FORMAT)
System.out.println(fx+" -> "+bytes[locs[i]]);
else
System.out.println(fx+" -> "+bytes[locs[i]]+" "+bytes[locs[i]+1]);
}
assert(!fi.hasNext());
indexes[0] = 1; // like iptr
Index ix = new Index("ix") {
public int indexOf(Entry e) {
return indexes[indexes[0]++];
}
};
f.finishRefs(ix);
for (int loc = 0; loc < bytes.length; loc++) {
if (bytes[loc] != (byte)loc) {
System.out.println("** ["+loc+"] = "+bytes[loc]+" != "+(byte)loc);
}
}
}
//*/
}

View file

@ -1,818 +0,0 @@
/*
* Copyright (c) 2003, 2010, 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.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.util.Arrays;
/**
* Histogram derived from an integer array of events (int[]).
* @author John Rose
*/
final class Histogram {
// Compact histogram representation: 4 bytes per distinct value,
// plus 5 words per distinct count.
protected final int[][] matrix; // multi-row matrix {{counti,valueij...}}
protected final int totalWeight; // sum of all counts
// These are created eagerly also, since that saves work.
// They cost another 8 bytes per distinct value.
protected final int[] values; // unique values, sorted by value
protected final int[] counts; // counts, same order as values
private static final long LOW32 = (long)-1 >>> 32;
/** Build a histogram given a sequence of values.
* To save work, the input should be sorted, but need not be.
*/
public
Histogram(int[] valueSequence) {
long[] hist2col = computeHistogram2Col(maybeSort(valueSequence));
int[][] table = makeTable(hist2col);
values = table[0];
counts = table[1];
this.matrix = makeMatrix(hist2col);
this.totalWeight = valueSequence.length;
assert(assertWellFormed(valueSequence));
}
public
Histogram(int[] valueSequence, int start, int end) {
this(sortedSlice(valueSequence, start, end));
}
/** Build a histogram given a compact matrix of counts and values. */
public
Histogram(int[][] matrix) {
// sort the rows
matrix = normalizeMatrix(matrix); // clone and sort
this.matrix = matrix;
int length = 0;
int weight = 0;
for (int i = 0; i < matrix.length; i++) {
int rowLength = matrix[i].length-1;
length += rowLength;
weight += matrix[i][0] * rowLength;
}
this.totalWeight = weight;
long[] hist2col = new long[length];
int fillp = 0;
for (int i = 0; i < matrix.length; i++) {
for (int j = 1; j < matrix[i].length; j++) {
// sort key is value, so put it in the high 32!
hist2col[fillp++] = ((long) matrix[i][j] << 32)
| (LOW32 & matrix[i][0]);
}
}
assert(fillp == hist2col.length);
Arrays.sort(hist2col);
int[][] table = makeTable(hist2col);
values = table[1]; //backwards
counts = table[0]; //backwards
assert(assertWellFormed(null));
}
/** Histogram of int values, reported compactly as a ragged matrix,
* indexed by descending frequency rank.
* <p>
* Format of matrix:
* Each row in the matrix begins with an occurrence count,
* and continues with all int values that occur at that frequency.
* <pre>
* int[][] matrix = {
* { count1, value11, value12, value13, ... },
* { count2, value21, value22, ... },
* ...
* }
* </pre>
* The first column of the matrix { count1, count2, ... }
* is sorted in descending order, and contains no duplicates.
* Each row of the matrix (apart from its first element)
* is sorted in ascending order, and contains no duplicates.
* That is, each sequence { valuei1, valuei2, ... } is sorted.
*/
public
int[][] getMatrix() { return matrix; }
public
int getRowCount() { return matrix.length; }
public
int getRowFrequency(int rn) { return matrix[rn][0]; }
public
int getRowLength(int rn) { return matrix[rn].length-1; }
public
int getRowValue(int rn, int vn) { return matrix[rn][vn+1]; }
public
int getRowWeight(int rn) {
return getRowFrequency(rn) * getRowLength(rn);
}
public
int getTotalWeight() {
return totalWeight;
}
public
int getTotalLength() {
return values.length;
}
/** Returns an array of all values, sorted. */
public
int[] getAllValues() {
return values;
}
/** Returns an array parallel with {@link #getValues},
* with a frequency for each value.
*/
public
int[] getAllFrequencies() {
return counts;
}
private static double log2 = Math.log(2);
public
int getFrequency(int value) {
int pos = Arrays.binarySearch(values, value);
if (pos < 0) return 0;
assert(values[pos] == value);
return counts[pos];
}
public
double getBitLength(int value) {
double prob = (double) getFrequency(value) / getTotalWeight();
return - Math.log(prob) / log2;
}
public
double getRowBitLength(int rn) {
double prob = (double) getRowFrequency(rn) / getTotalWeight();
return - Math.log(prob) / log2;
}
public
interface BitMetric {
public double getBitLength(int value);
}
private final BitMetric bitMetric = new BitMetric() {
public double getBitLength(int value) {
return Histogram.this.getBitLength(value);
}
};
public BitMetric getBitMetric() {
return bitMetric;
}
/** bit-length is negative entropy: -H(matrix). */
public
double getBitLength() {
double sum = 0;
for (int i = 0; i < matrix.length; i++) {
sum += getRowBitLength(i) * getRowWeight(i);
}
assert(0.1 > Math.abs(sum - getBitLength(bitMetric)));
return sum;
}
/** bit-length in to another coding (cross-entropy) */
public
double getBitLength(BitMetric len) {
double sum = 0;
for (int i = 0; i < matrix.length; i++) {
for (int j = 1; j < matrix[i].length; j++) {
sum += matrix[i][0] * len.getBitLength(matrix[i][j]);
}
}
return sum;
}
private static
double round(double x, double scale) {
return Math.round(x * scale) / scale;
}
/** Sort rows and columns.
* Merge adjacent rows with the same key element [0].
* Make a fresh copy of all of it.
*/
public int[][] normalizeMatrix(int[][] matrix) {
long[] rowMap = new long[matrix.length];
for (int i = 0; i < matrix.length; i++) {
if (matrix[i].length <= 1) continue;
int count = matrix[i][0];
if (count <= 0) continue;
rowMap[i] = (long) count << 32 | i;
}
Arrays.sort(rowMap);
int[][] newMatrix = new int[matrix.length][];
int prevCount = -1;
int fillp1 = 0;
int fillp2 = 0;
for (int i = 0; ; i++) {
int[] row;
if (i < matrix.length) {
long rowMapEntry = rowMap[rowMap.length-i-1];
if (rowMapEntry == 0) continue;
row = matrix[(int)rowMapEntry];
assert(rowMapEntry>>>32 == row[0]);
} else {
row = new int[]{ -1 }; // close it off
}
if (row[0] != prevCount && fillp2 > fillp1) {
// Close off previous run.
int length = 0;
for (int p = fillp1; p < fillp2; p++) {
int[] row0 = newMatrix[p]; // previously visited row
assert(row0[0] == prevCount);
length += row0.length-1;
}
int[] row1 = new int[1+length]; // cloned & consolidated row
row1[0] = prevCount;
int rfillp = 1;
for (int p = fillp1; p < fillp2; p++) {
int[] row0 = newMatrix[p]; // previously visited row
assert(row0[0] == prevCount);
System.arraycopy(row0, 1, row1, rfillp, row0.length-1);
rfillp += row0.length-1;
}
if (!isSorted(row1, 1, true)) {
Arrays.sort(row1, 1, row1.length);
int jfillp = 2;
// Detect and squeeze out duplicates.
for (int j = 2; j < row1.length; j++) {
if (row1[j] != row1[j-1])
row1[jfillp++] = row1[j];
}
if (jfillp < row1.length) {
// Reallocate because of lost duplicates.
int[] newRow1 = new int[jfillp];
System.arraycopy(row1, 0, newRow1, 0, jfillp);
row1 = newRow1;
}
}
newMatrix[fillp1++] = row1;
fillp2 = fillp1;
}
if (i == matrix.length)
break;
prevCount = row[0];
newMatrix[fillp2++] = row;
}
assert(fillp1 == fillp2); // no unfinished business
// Now drop missing rows.
matrix = newMatrix;
if (fillp1 < matrix.length) {
newMatrix = new int[fillp1][];
System.arraycopy(matrix, 0, newMatrix, 0, fillp1);
matrix = newMatrix;
}
return matrix;
}
public
String[] getRowTitles(String name) {
int totalUnique = getTotalLength();
int ltotalWeight = getTotalWeight();
String[] histTitles = new String[matrix.length];
int cumWeight = 0;
int cumUnique = 0;
for (int i = 0; i < matrix.length; i++) {
int count = getRowFrequency(i);
int unique = getRowLength(i);
int weight = getRowWeight(i);
cumWeight += weight;
cumUnique += unique;
long wpct = ((long)cumWeight * 100 + ltotalWeight/2) / ltotalWeight;
long upct = ((long)cumUnique * 100 + totalUnique/2) / totalUnique;
double len = getRowBitLength(i);
assert(0.1 > Math.abs(len - getBitLength(matrix[i][1])));
histTitles[i] = name+"["+i+"]"
+" len="+round(len,10)
+" ("+count+"*["+unique+"])"
+" ("+cumWeight+":"+wpct+"%)"
+" ["+cumUnique+":"+upct+"%]";
}
return histTitles;
}
/** Print a report of this histogram.
*/
public
void print(PrintStream out) {
print("hist", out);
}
/** Print a report of this histogram.
*/
public
void print(String name, PrintStream out) {
print(name, getRowTitles(name), out);
}
/** Print a report of this histogram.
*/
public
void print(String name, String[] histTitles, PrintStream out) {
int totalUnique = getTotalLength();
int ltotalWeight = getTotalWeight();
double tlen = getBitLength();
double avgLen = tlen / ltotalWeight;
double avg = (double) ltotalWeight / totalUnique;
String title = (name
+" len="+round(tlen,10)
+" avgLen="+round(avgLen,10)
+" weight("+ltotalWeight+")"
+" unique["+totalUnique+"]"
+" avgWeight("+round(avg,100)+")");
if (histTitles == null) {
out.println(title);
} else {
out.println(title+" {");
StringBuffer buf = new StringBuffer();
for (int i = 0; i < matrix.length; i++) {
buf.setLength(0);
buf.append(" ").append(histTitles[i]).append(" {");
for (int j = 1; j < matrix[i].length; j++) {
buf.append(" ").append(matrix[i][j]);
}
buf.append(" }");
out.println(buf);
}
out.println("}");
}
}
/*
public static
int[][] makeHistogramMatrix(int[] values) {
// Make sure they are sorted.
values = maybeSort(values);
long[] hist2col = computeHistogram2Col(values);
int[][] matrix = makeMatrix(hist2col);
return matrix;
}
*/
private static
int[][] makeMatrix(long[] hist2col) {
// Sort by increasing count, then by increasing value.
Arrays.sort(hist2col);
int[] counts = new int[hist2col.length];
for (int i = 0; i < counts.length; i++) {
counts[i] = (int)( hist2col[i] >>> 32 );
}
long[] countHist = computeHistogram2Col(counts);
int[][] matrix = new int[countHist.length][];
int histp = 0; // cursor into hist2col (increasing count, value)
int countp = 0; // cursor into countHist (increasing count)
// Do a join between hist2col (resorted) and countHist.
for (int i = matrix.length; --i >= 0; ) {
long countAndRep = countHist[countp++];
int count = (int) (countAndRep); // what is the value count?
int repeat = (int) (countAndRep >>> 32); // # times repeated?
int[] row = new int[1+repeat];
row[0] = count;
for (int j = 0; j < repeat; j++) {
long countAndValue = hist2col[histp++];
assert(countAndValue >>> 32 == count);
row[1+j] = (int) countAndValue;
}
matrix[i] = row;
}
assert(histp == hist2col.length);
return matrix;
}
private static
int[][] makeTable(long[] hist2col) {
int[][] table = new int[2][hist2col.length];
// Break apart the entries in hist2col.
// table[0] gets values, table[1] gets entries.
for (int i = 0; i < hist2col.length; i++) {
table[0][i] = (int)( hist2col[i] );
table[1][i] = (int)( hist2col[i] >>> 32 );
}
return table;
}
/** Simple two-column histogram. Contains repeated counts.
* Assumes input is sorted. Does not sort output columns.
* <p>
* Format of result:
* <pre>
* long[] hist = {
* (count1 << 32) | (value1),
* (count2 << 32) | (value2),
* ...
* }
* </pre>
* In addition, the sequence {valuei...} is guaranteed to be sorted.
* Note that resorting this using Arrays.sort() will reorder the
* entries by increasing count.
*/
private static
long[] computeHistogram2Col(int[] sortedValues) {
switch (sortedValues.length) {
case 0:
return new long[]{ };
case 1:
return new long[]{ ((long)1 << 32) | (LOW32 & sortedValues[0]) };
}
long[] hist = null;
for (boolean sizeOnly = true; ; sizeOnly = false) {
int prevIndex = -1;
int prevValue = sortedValues[0] ^ -1; // force a difference
int prevCount = 0;
for (int i = 0; i <= sortedValues.length; i++) {
int thisValue;
if (i < sortedValues.length)
thisValue = sortedValues[i];
else
thisValue = prevValue ^ -1; // force a difference at end
if (thisValue == prevValue) {
prevCount += 1;
} else {
// Found a new value.
if (!sizeOnly && prevCount != 0) {
// Save away previous value.
hist[prevIndex] = ((long)prevCount << 32)
| (LOW32 & prevValue);
}
prevValue = thisValue;
prevCount = 1;
prevIndex += 1;
}
}
if (sizeOnly) {
// Finished the sizing pass. Allocate the histogram.
hist = new long[prevIndex];
} else {
break; // done
}
}
return hist;
}
/** Regroup the histogram, so that it becomes an approximate histogram
* whose rows are of the given lengths.
* If matrix rows must be split, the latter parts (larger values)
* are placed earlier in the new matrix.
* If matrix rows are joined, they are resorted into ascending order.
* In the new histogram, the counts are averaged over row entries.
*/
private static
int[][] regroupHistogram(int[][] matrix, int[] groups) {
long oldEntries = 0;
for (int i = 0; i < matrix.length; i++) {
oldEntries += matrix[i].length-1;
}
long newEntries = 0;
for (int ni = 0; ni < groups.length; ni++) {
newEntries += groups[ni];
}
if (newEntries > oldEntries) {
int newlen = groups.length;
long ok = oldEntries;
for (int ni = 0; ni < groups.length; ni++) {
if (ok < groups[ni]) {
int[] newGroups = new int[ni+1];
System.arraycopy(groups, 0, newGroups, 0, ni+1);
groups = newGroups;
groups[ni] = (int) ok;
ok = 0;
break;
}
ok -= groups[ni];
}
} else {
long excess = oldEntries - newEntries;
int[] newGroups = new int[groups.length+1];
System.arraycopy(groups, 0, newGroups, 0, groups.length);
newGroups[groups.length] = (int) excess;
groups = newGroups;
}
int[][] newMatrix = new int[groups.length][];
// Fill pointers.
int i = 0; // into matrix
int jMin = 1;
int jMax = matrix[i].length;
for (int ni = 0; ni < groups.length; ni++) {
int groupLength = groups[ni];
int[] group = new int[1+groupLength];
long groupWeight = 0; // count of all in new group
newMatrix[ni] = group;
int njFill = 1;
while (njFill < group.length) {
int len = group.length - njFill;
while (jMin == jMax) {
jMin = 1;
jMax = matrix[++i].length;
}
if (len > jMax - jMin) len = jMax - jMin;
groupWeight += (long) matrix[i][0] * len;
System.arraycopy(matrix[i], jMax - len, group, njFill, len);
jMax -= len;
njFill += len;
}
Arrays.sort(group, 1, group.length);
// compute average count of new group:
group[0] = (int) ((groupWeight + groupLength/2) / groupLength);
}
assert(jMin == jMax);
assert(i == matrix.length-1);
return newMatrix;
}
public static
Histogram makeByteHistogram(InputStream bytes) throws IOException {
byte[] buf = new byte[1<<12];
int[] tally = new int[1<<8];
for (int nr; (nr = bytes.read(buf)) > 0; ) {
for (int i = 0; i < nr; i++) {
tally[buf[i] & 0xFF] += 1;
}
}
// Build a matrix.
int[][] matrix = new int[1<<8][2];
for (int i = 0; i < tally.length; i++) {
matrix[i][0] = tally[i];
matrix[i][1] = i;
}
return new Histogram(matrix);
}
/** Slice and sort the given input array. */
private static
int[] sortedSlice(int[] valueSequence, int start, int end) {
if (start == 0 && end == valueSequence.length &&
isSorted(valueSequence, 0, false)) {
return valueSequence;
} else {
int[] slice = new int[end-start];
System.arraycopy(valueSequence, start, slice, 0, slice.length);
Arrays.sort(slice);
return slice;
}
}
/** Tell if an array is sorted. */
private static
boolean isSorted(int[] values, int from, boolean strict) {
for (int i = from+1; i < values.length; i++) {
if (strict ? !(values[i-1] < values[i])
: !(values[i-1] <= values[i])) {
return false; // found witness to disorder
}
}
return true; // no witness => sorted
}
/** Clone and sort the array, if not already sorted. */
private static
int[] maybeSort(int[] values) {
if (!isSorted(values, 0, false)) {
values = values.clone();
Arrays.sort(values);
}
return values;
}
/// Debug stuff follows.
private boolean assertWellFormed(int[] valueSequence) {
/*
// Sanity check.
int weight = 0;
int vlength = 0;
for (int i = 0; i < matrix.length; i++) {
int vlengthi = (matrix[i].length-1);
int count = matrix[i][0];
assert(vlengthi > 0); // no empty rows
assert(count > 0); // no impossible rows
vlength += vlengthi;
weight += count * vlengthi;
}
assert(isSorted(values, 0, true));
// make sure the counts all add up
assert(totalWeight == weight);
assert(vlength == values.length);
assert(vlength == counts.length);
int weight2 = 0;
for (int i = 0; i < counts.length; i++) {
weight2 += counts[i];
}
assert(weight2 == weight);
int[] revcol1 = new int[matrix.length]; //1st matrix colunm
for (int i = 0; i < matrix.length; i++) {
// spot checking: try a random query on each matrix row
assert(matrix[i].length > 1);
revcol1[matrix.length-i-1] = matrix[i][0];
assert(isSorted(matrix[i], 1, true));
int rand = (matrix[i].length+1) / 2;
int val = matrix[i][rand];
int count = matrix[i][0];
int pos = Arrays.binarySearch(values, val);
assert(values[pos] == val);
assert(counts[pos] == matrix[i][0]);
if (valueSequence != null) {
int count2 = 0;
for (int j = 0; j < valueSequence.length; j++) {
if (valueSequence[j] == val) count2++;
}
assert(count2 == count);
}
}
assert(isSorted(revcol1, 0, true));
//*/
return true;
}
/*
public static
int[] readValuesFrom(InputStream instr) {
return readValuesFrom(new InputStreamReader(instr));
}
public static
int[] readValuesFrom(Reader inrdr) {
inrdr = new BufferedReader(inrdr);
final StreamTokenizer in = new StreamTokenizer(inrdr);
final int TT_NOTHING = -99;
in.commentChar('#');
return readValuesFrom(new Iterator() {
int token = TT_NOTHING;
private int getToken() {
if (token == TT_NOTHING) {
try {
token = in.nextToken();
assert(token != TT_NOTHING);
} catch (IOException ee) {
throw new RuntimeException(ee);
}
}
return token;
}
public boolean hasNext() {
return getToken() != StreamTokenizer.TT_EOF;
}
public Object next() {
int ntok = getToken();
token = TT_NOTHING;
switch (ntok) {
case StreamTokenizer.TT_EOF:
throw new NoSuchElementException();
case StreamTokenizer.TT_NUMBER:
return new Integer((int) in.nval);
default:
assert(false);
return null;
}
}
public void remove() {
throw new UnsupportedOperationException();
}
});
}
public static
int[] readValuesFrom(Iterator iter) {
return readValuesFrom(iter, 0);
}
public static
int[] readValuesFrom(Iterator iter, int initSize) {
int[] na = new int[Math.max(10, initSize)];
int np = 0;
while (iter.hasNext()) {
Integer val = (Integer) iter.next();
if (np == na.length) {
int[] na2 = new int[np*2];
System.arraycopy(na, 0, na2, 0, np);
na = na2;
}
na[np++] = val.intValue();
}
if (np != na.length) {
int[] na2 = new int[np];
System.arraycopy(na, 0, na2, 0, np);
na = na2;
}
return na;
}
public static
Histogram makeByteHistogram(byte[] bytes) {
try {
return makeByteHistogram(new ByteArrayInputStream(bytes));
} catch (IOException ee) {
throw new RuntimeException(ee);
}
}
public static
void main(String[] av) throws IOException {
if (av.length > 0 && av[0].equals("-r")) {
int[] values = new int[Integer.parseInt(av[1])];
int limit = values.length;
if (av.length >= 3) {
limit = (int)( limit * Double.parseDouble(av[2]) );
}
Random rnd = new Random();
for (int i = 0; i < values.length; i++) {
values[i] = rnd.nextInt(limit);;
}
Histogram rh = new Histogram(values);
rh.print("random", System.out);
return;
}
if (av.length > 0 && av[0].equals("-s")) {
int[] values = readValuesFrom(System.in);
Random rnd = new Random();
for (int i = values.length; --i > 0; ) {
int j = rnd.nextInt(i+1);
if (j < i) {
int tem = values[i];
values[i] = values[j];
values[j] = tem;
}
}
for (int i = 0; i < values.length; i++)
System.out.println(values[i]);
return;
}
if (av.length > 0 && av[0].equals("-e")) {
// edge cases
new Histogram(new int[][] {
{1, 11, 111},
{0, 123, 456},
{1, 111, 1111},
{0, 456, 123},
{3},
{},
{3},
{2, 22},
{4}
}).print(System.out);
return;
}
if (av.length > 0 && av[0].equals("-b")) {
// edge cases
Histogram bh = makeByteHistogram(System.in);
bh.print("bytes", System.out);
return;
}
boolean regroup = false;
if (av.length > 0 && av[0].equals("-g")) {
regroup = true;
}
int[] values = readValuesFrom(System.in);
Histogram h = new Histogram(values);
if (!regroup)
h.print(System.out);
if (regroup) {
int[] groups = new int[12];
for (int i = 0; i < groups.length; i++) {
groups[i] = 1<<i;
}
int[][] gm = regroupHistogram(h.getMatrix(), groups);
Histogram g = new Histogram(gm);
System.out.println("h.getBitLength(g) = "+
h.getBitLength(g.getBitMetric()));
System.out.println("g.getBitLength(h) = "+
g.getBitLength(h.getBitMetric()));
g.print("regrouped", System.out);
}
}
//*/
}

View file

@ -1,689 +0,0 @@
/*
* Copyright (c) 2001, 2019, 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.io.IOException;
import java.util.Arrays;
import static com.sun.java.util.jar.pack.Constants.*;
/**
* A parsed bytecode instruction.
* Provides accessors to various relevant bits.
* @author John Rose
*/
class Instruction {
protected byte[] bytes; // bytecodes
protected int pc; // location of this instruction
protected int bc; // opcode of this instruction
protected int w; // 0 if normal, 1 if a _wide prefix at pc
protected int length; // bytes in this instruction
protected boolean special;
protected Instruction(byte[] bytes, int pc, int bc, int w, int length) {
reset(bytes, pc, bc, w, length);
}
private void reset(byte[] bytes, int pc, int bc, int w, int length) {
this.bytes = bytes;
this.pc = pc;
this.bc = bc;
this.w = w;
this.length = length;
}
public int getBC() {
return bc;
}
public boolean isWide() {
return w != 0;
}
public byte[] getBytes() {
return bytes;
}
public int getPC() {
return pc;
}
public int getLength() {
return length;
}
public int getNextPC() {
return pc + length;
}
public Instruction next() {
int npc = pc + length;
if (npc == bytes.length)
return null;
else
return Instruction.at(bytes, npc, this);
}
public boolean isNonstandard() {
return isNonstandard(bc);
}
public void setNonstandardLength(int length) {
assert(isNonstandard());
this.length = length;
}
/** A fake instruction at this pc whose next() will be at nextpc. */
public Instruction forceNextPC(int nextpc) {
int llength = nextpc - pc;
return new Instruction(bytes, pc, -1, -1, llength);
}
public static Instruction at(byte[] bytes, int pc) {
return Instruction.at(bytes, pc, null);
}
public static Instruction at(byte[] bytes, int pc, Instruction reuse) {
int bc = getByte(bytes, pc);
int prefix = -1;
int w = 0;
int length = BC_LENGTH[w][bc];
if (length == 0) {
// Hard cases:
switch (bc) {
case _wide:
bc = getByte(bytes, pc+1);
w = 1;
length = BC_LENGTH[w][bc];
if (length == 0) {
// unknown instruction; treat as one byte
length = 1;
}
break;
case _tableswitch:
return new TableSwitch(bytes, pc);
case _lookupswitch:
return new LookupSwitch(bytes, pc);
default:
// unknown instruction; treat as one byte
length = 1;
break;
}
}
assert(length > 0);
assert(pc+length <= bytes.length);
// Speed hack: Instruction.next reuses self if possible.
if (reuse != null && !reuse.special) {
reuse.reset(bytes, pc, bc, w, length);
return reuse;
}
return new Instruction(bytes, pc, bc, w, length);
}
// Return the constant pool reference type, or 0 if none.
public byte getCPTag() {
return BC_TAG[w][bc];
}
// Return the constant pool index, or -1 if none.
public int getCPIndex() {
int indexLoc = BC_INDEX[w][bc];
if (indexLoc == 0) return -1;
assert(w == 0);
if (length == 2)
return getByte(bytes, pc+indexLoc); // _ldc opcode only
else
return getShort(bytes, pc+indexLoc);
}
public void setCPIndex(int cpi) {
int indexLoc = BC_INDEX[w][bc];
assert(indexLoc != 0);
if (length == 2)
setByte(bytes, pc+indexLoc, cpi); // _ldc opcode only
else
setShort(bytes, pc+indexLoc, cpi);
assert(getCPIndex() == cpi);
}
public ConstantPool.Entry getCPRef(ConstantPool.Entry[] cpMap) {
int index = getCPIndex();
return (index < 0) ? null : cpMap[index];
}
// Return the slot of the affected local, or -1 if none.
public int getLocalSlot() {
int slotLoc = BC_SLOT[w][bc];
if (slotLoc == 0) return -1;
if (w == 0)
return getByte(bytes, pc+slotLoc);
else
return getShort(bytes, pc+slotLoc);
}
// Return the target of the branch, or -1 if none.
public int getBranchLabel() {
int branchLoc = BC_BRANCH[w][bc];
if (branchLoc == 0) return -1;
assert(w == 0);
assert(length == 3 || length == 5);
int offset;
if (length == 3)
offset = (short)getShort(bytes, pc+branchLoc);
else
offset = getInt(bytes, pc+branchLoc);
assert(offset+pc >= 0);
assert(offset+pc <= bytes.length);
return offset+pc;
}
public void setBranchLabel(int targetPC) {
int branchLoc = BC_BRANCH[w][bc];
assert(branchLoc != 0);
if (length == 3)
setShort(bytes, pc+branchLoc, targetPC-pc);
else
setInt(bytes, pc+branchLoc, targetPC-pc);
assert(targetPC == getBranchLabel());
}
// Return the trailing constant in the instruction (as a signed value).
// Return 0 if there is none.
public int getConstant() {
int conLoc = BC_CON[w][bc];
if (conLoc == 0) return 0;
switch (length - conLoc) {
case 1: return (byte) getByte(bytes, pc+conLoc);
case 2: return (short) getShort(bytes, pc+conLoc);
}
assert(false);
return 0;
}
public void setConstant(int con) {
int conLoc = BC_CON[w][bc];
assert(conLoc != 0);
switch (length - conLoc) {
case 1: setByte(bytes, pc+conLoc, con); break;
case 2: setShort(bytes, pc+conLoc, con); break;
}
assert(con == getConstant());
}
public abstract static class Switch extends Instruction {
// Each case is a (value, label) pair, indexed 0 <= n < caseCount
public abstract int getCaseCount();
public abstract int getCaseValue(int n);
public abstract int getCaseLabel(int n);
public abstract void setCaseCount(int caseCount);
public abstract void setCaseValue(int n, int value);
public abstract void setCaseLabel(int n, int targetPC);
protected abstract int getLength(int caseCount);
public int getDefaultLabel() { return intAt(0)+pc; }
public void setDefaultLabel(int targetPC) { setIntAt(0, targetPC-pc); }
protected int apc; // aligned pc (table base)
protected int intAt(int n) { return getInt(bytes, apc + n*4); }
protected void setIntAt(int n, int x) { setInt(bytes, apc + n*4, x); }
protected Switch(byte[] bytes, int pc, int bc) {
super(bytes, pc, bc, /*w*/0, /*length*/0);
this.apc = alignPC(pc+1);
this.special = true;
length = getLength(getCaseCount());
}
public int getAlignedPC() { return apc; }
public String toString() {
String s = super.toString();
s += " Default:"+labstr(getDefaultLabel());
int caseCount = getCaseCount();
for (int i = 0; i < caseCount; i++) {
s += "\n\tCase "+getCaseValue(i)+":"+labstr(getCaseLabel(i));
}
return s;
}
public static int alignPC(int apc) {
while (apc % 4 != 0) ++apc;
return apc;
}
}
public static class TableSwitch extends Switch {
// apc: (df, lo, hi, (hi-lo+1)*(label))
public int getLowCase() { return intAt(1); }
public int getHighCase() { return intAt(2); }
public int getCaseCount() { return intAt(2)-intAt(1)+1; }
public int getCaseValue(int n) { return getLowCase()+n; }
public int getCaseLabel(int n) { return intAt(3+n)+pc; }
public void setLowCase(int val) { setIntAt(1, val); }
public void setHighCase(int val) { setIntAt(2, val); }
public void setCaseLabel(int n, int tpc) { setIntAt(3+n, tpc-pc); }
public void setCaseCount(int caseCount) {
setHighCase(getLowCase() + caseCount - 1);
length = getLength(caseCount);
}
public void setCaseValue(int n, int val) {
if (n != 0) throw new UnsupportedOperationException();
int caseCount = getCaseCount();
setLowCase(val);
setCaseCount(caseCount); // keep invariant
}
TableSwitch(byte[] bytes, int pc) {
super(bytes, pc, _tableswitch);
}
protected int getLength(int caseCount) {
return (apc-pc) + (3 + caseCount) * 4;
}
}
public static class LookupSwitch extends Switch {
// apc: (df, nc, nc*(case, label))
public int getCaseCount() { return intAt(1); }
public int getCaseValue(int n) { return intAt(2+n*2+0); }
public int getCaseLabel(int n) { return intAt(2+n*2+1)+pc; }
public void setCaseCount(int caseCount) {
setIntAt(1, caseCount);
length = getLength(caseCount);
}
public void setCaseValue(int n, int val) { setIntAt(2+n*2+0, val); }
public void setCaseLabel(int n, int tpc) { setIntAt(2+n*2+1, tpc-pc); }
LookupSwitch(byte[] bytes, int pc) {
super(bytes, pc, _lookupswitch);
}
protected int getLength(int caseCount) {
return (apc-pc) + (2 + caseCount*2) * 4;
}
}
/** Two instructions are equal if they have the same bytes. */
public boolean equals(Object o) {
return (o != null) && (o.getClass() == Instruction.class)
&& equals((Instruction) o);
}
public int hashCode() {
int hash = 3;
hash = 11 * hash + Arrays.hashCode(this.bytes);
hash = 11 * hash + this.pc;
hash = 11 * hash + this.bc;
hash = 11 * hash + this.w;
hash = 11 * hash + this.length;
return hash;
}
public boolean equals(Instruction that) {
if (this.pc != that.pc) return false;
if (this.bc != that.bc) return false;
if (this.w != that.w) return false;
if (this.length != that.length) return false;
for (int i = 1; i < length; i++) {
if (this.bytes[this.pc+i] != that.bytes[that.pc+i])
return false;
}
return true;
}
static String labstr(int pc) {
if (pc >= 0 && pc < 100000)
return ((100000+pc)+"").substring(1);
return pc+"";
}
public String toString() {
return toString(null);
}
public String toString(ConstantPool.Entry[] cpMap) {
String s = labstr(pc) + ": ";
if (bc >= _bytecode_limit) {
s += Integer.toHexString(bc);
return s;
}
if (w == 1) s += "wide ";
String bcname = (bc < BC_NAME.length)? BC_NAME[bc]: null;
if (bcname == null) {
return s+"opcode#"+bc;
}
s += bcname;
int tag = getCPTag();
if (tag != 0) s += " "+ConstantPool.tagName(tag)+":";
int idx = getCPIndex();
if (idx >= 0) s += (cpMap == null) ? ""+idx : "="+cpMap[idx].stringValue();
int slt = getLocalSlot();
if (slt >= 0) s += " Local:"+slt;
int lab = getBranchLabel();
if (lab >= 0) s += " To:"+labstr(lab);
int con = getConstant();
if (con != 0) s += " Con:"+con;
return s;
}
//public static byte constantPoolTagFor(int bc) { return BC_TAG[0][bc]; }
/// Fetching values from byte arrays:
public int getIntAt(int off) {
return getInt(bytes, pc+off);
}
public int getShortAt(int off) {
return getShort(bytes, pc+off);
}
public int getByteAt(int off) {
return getByte(bytes, pc+off);
}
public static int getInt(byte[] bytes, int pc) {
return (getShort(bytes, pc+0) << 16) + (getShort(bytes, pc+2) << 0);
}
public static int getShort(byte[] bytes, int pc) {
return (getByte(bytes, pc+0) << 8) + (getByte(bytes, pc+1) << 0);
}
public static int getByte(byte[] bytes, int pc) {
return bytes[pc] & 0xFF;
}
public static void setInt(byte[] bytes, int pc, int x) {
setShort(bytes, pc+0, x >> 16);
setShort(bytes, pc+2, x >> 0);
}
public static void setShort(byte[] bytes, int pc, int x) {
setByte(bytes, pc+0, x >> 8);
setByte(bytes, pc+1, x >> 0);
}
public static void setByte(byte[] bytes, int pc, int x) {
bytes[pc] = (byte)x;
}
// some bytecode classifiers
public static boolean isNonstandard(int bc) {
return BC_LENGTH[0][bc] < 0;
}
public static int opLength(int bc) {
int l = BC_LENGTH[0][bc];
assert(l > 0);
return l;
}
public static int opWideLength(int bc) {
int l = BC_LENGTH[1][bc];
assert(l > 0);
return l;
}
public static boolean isLocalSlotOp(int bc) {
return (bc < BC_SLOT[0].length && BC_SLOT[0][bc] > 0);
}
public static boolean isBranchOp(int bc) {
return (bc < BC_BRANCH[0].length && BC_BRANCH[0][bc] > 0);
}
public static boolean isCPRefOp(int bc) {
if (bc < BC_INDEX[0].length && BC_INDEX[0][bc] > 0) return true;
if (bc >= _xldc_op && bc < _xldc_limit) return true;
if (bc == _invokespecial_int || bc == _invokestatic_int) return true;
return false;
}
public static byte getCPRefOpTag(int bc) {
if (bc < BC_INDEX[0].length && BC_INDEX[0][bc] > 0) return BC_TAG[0][bc];
if (bc >= _xldc_op && bc < _xldc_limit) return CONSTANT_LoadableValue;
if (bc == _invokestatic_int || bc == _invokespecial_int) return CONSTANT_InterfaceMethodref;
return CONSTANT_None;
}
public static boolean isFieldOp(int bc) {
return (bc >= _getstatic && bc <= _putfield);
}
public static boolean isInvokeInitOp(int bc) {
return (bc >= _invokeinit_op && bc < _invokeinit_limit);
}
public static boolean isSelfLinkerOp(int bc) {
return (bc >= _self_linker_op && bc < _self_linker_limit);
}
/// Format definitions.
private static final byte[][] BC_LENGTH = new byte[2][0x100];
private static final byte[][] BC_INDEX = new byte[2][0x100];
private static final byte[][] BC_TAG = new byte[2][0x100];
private static final byte[][] BC_BRANCH = new byte[2][0x100];
private static final byte[][] BC_SLOT = new byte[2][0x100];
private static final byte[][] BC_CON = new byte[2][0x100];
private static final String[] BC_NAME = new String[0x100]; // debug only
private static final String[][] BC_FORMAT = new String[2][_bytecode_limit]; // debug only
static {
for (int i = 0; i < _bytecode_limit; i++) {
BC_LENGTH[0][i] = -1;
BC_LENGTH[1][i] = -1;
}
def("b", _nop, _dconst_1);
def("bx", _bipush);
def("bxx", _sipush);
def("bk", _ldc); // do not pack
def("bkk", _ldc_w, _ldc2_w); // do not pack
def("blwbll", _iload, _aload);
def("b", _iload_0, _saload);
def("blwbll", _istore, _astore);
def("b", _istore_0, _lxor);
def("blxwbllxx", _iinc);
def("b", _i2l, _dcmpg);
def("boo", _ifeq, _jsr); // pack oo
def("blwbll", _ret);
def("", _tableswitch, _lookupswitch); // pack all ints, omit padding
def("b", _ireturn, _return);
def("bkf", _getstatic, _putfield); // pack kf (base=Field)
def("bkm", _invokevirtual, _invokestatic); // pack kn (base=Method)
def("bkixx", _invokeinterface); // pack ki (base=IMethod), omit xx
def("bkyxx", _invokedynamic); // pack ky (base=Any), omit xx
def("bkc", _new); // pack kc
def("bx", _newarray);
def("bkc", _anewarray); // pack kc
def("b", _arraylength, _athrow);
def("bkc", _checkcast, _instanceof); // pack kc
def("b", _monitorenter, _monitorexit);
def("", _wide);
def("bkcx", _multianewarray); // pack kc
def("boo", _ifnull, _ifnonnull); // pack oo
def("boooo", _goto_w, _jsr_w); // pack oooo
for (int i = 0; i < _bytecode_limit; i++) {
//System.out.println(i+": l="+BC_LENGTH[0][i]+" i="+BC_INDEX[0][i]);
//assert(BC_LENGTH[0][i] != -1);
if (BC_LENGTH[0][i] == -1) {
continue; // unknown opcode
}
// Have a complete mapping, to support spurious _wide prefixes.
if (BC_LENGTH[1][i] == -1)
BC_LENGTH[1][i] = (byte)(1+BC_LENGTH[0][i]);
}
String names =
"nop aconst_null iconst_m1 iconst_0 iconst_1 iconst_2 iconst_3 iconst_4 "+
"iconst_5 lconst_0 lconst_1 fconst_0 fconst_1 fconst_2 dconst_0 dconst_1 "+
"bipush sipush ldc ldc_w ldc2_w iload lload fload dload aload iload_0 "+
"iload_1 iload_2 iload_3 lload_0 lload_1 lload_2 lload_3 fload_0 fload_1 "+
"fload_2 fload_3 dload_0 dload_1 dload_2 dload_3 aload_0 aload_1 aload_2 "+
"aload_3 iaload laload faload daload aaload baload caload saload istore "+
"lstore fstore dstore astore istore_0 istore_1 istore_2 istore_3 lstore_0 "+
"lstore_1 lstore_2 lstore_3 fstore_0 fstore_1 fstore_2 fstore_3 dstore_0 "+
"dstore_1 dstore_2 dstore_3 astore_0 astore_1 astore_2 astore_3 iastore "+
"lastore fastore dastore aastore bastore castore sastore pop pop2 dup "+
"dup_x1 dup_x2 dup2 dup2_x1 dup2_x2 swap iadd ladd fadd dadd isub lsub "+
"fsub dsub imul lmul fmul dmul idiv ldiv fdiv ddiv irem lrem frem drem "+
"ineg lneg fneg dneg ishl lshl ishr lshr iushr lushr iand land ior lor "+
"ixor lxor iinc i2l i2f i2d l2i l2f l2d f2i f2l f2d d2i d2l d2f i2b i2c "+
"i2s lcmp fcmpl fcmpg dcmpl dcmpg ifeq ifne iflt ifge ifgt ifle if_icmpeq "+
"if_icmpne if_icmplt if_icmpge if_icmpgt if_icmple if_acmpeq if_acmpne "+
"goto jsr ret tableswitch lookupswitch ireturn lreturn freturn dreturn "+
"areturn return getstatic putstatic getfield putfield invokevirtual "+
"invokespecial invokestatic invokeinterface invokedynamic new newarray "+
"anewarray arraylength athrow checkcast instanceof monitorenter "+
"monitorexit wide multianewarray ifnull ifnonnull goto_w jsr_w ";
for (int bc = 0; names.length() > 0; bc++) {
int sp = names.indexOf(' ');
BC_NAME[bc] = names.substring(0, sp);
names = names.substring(sp+1);
}
}
public static String byteName(int bc) {
String iname;
if (bc < BC_NAME.length && BC_NAME[bc] != null) {
iname = BC_NAME[bc];
} else if (isSelfLinkerOp(bc)) {
int idx = (bc - _self_linker_op);
boolean isSuper = (idx >= _self_linker_super_flag);
if (isSuper) idx -= _self_linker_super_flag;
boolean isAload = (idx >= _self_linker_aload_flag);
if (isAload) idx -= _self_linker_aload_flag;
int origBC = _first_linker_op + idx;
assert(origBC >= _first_linker_op && origBC <= _last_linker_op);
iname = BC_NAME[origBC];
iname += (isSuper ? "_super" : "_this");
if (isAload) iname = "aload_0&" + iname;
iname = "*"+iname;
} else if (isInvokeInitOp(bc)) {
int idx = (bc - _invokeinit_op);
switch (idx) {
case _invokeinit_self_option:
iname = "*invokespecial_init_this"; break;
case _invokeinit_super_option:
iname = "*invokespecial_init_super"; break;
default:
assert(idx == _invokeinit_new_option);
iname = "*invokespecial_init_new"; break;
}
} else {
switch (bc) {
case _ildc: iname = "*ildc"; break;
case _fldc: iname = "*fldc"; break;
case _ildc_w: iname = "*ildc_w"; break;
case _fldc_w: iname = "*fldc_w"; break;
case _dldc2_w: iname = "*dldc2_w"; break;
case _cldc: iname = "*cldc"; break;
case _cldc_w: iname = "*cldc_w"; break;
case _qldc: iname = "*qldc"; break;
case _qldc_w: iname = "*qldc_w"; break;
case _byte_escape: iname = "*byte_escape"; break;
case _ref_escape: iname = "*ref_escape"; break;
case _end_marker: iname = "*end"; break;
default: iname = "*bc#"+bc; break;
}
}
return iname;
}
private static int BW = 4; // width of classification field
private static void def(String fmt, int bc) {
def(fmt, bc, bc);
}
private static void def(String fmt, int from_bc, int to_bc) {
String[] fmts = { fmt, null };
if (fmt.indexOf('w') > 0) {
fmts[1] = fmt.substring(fmt.indexOf('w'));
fmts[0] = fmt.substring(0, fmt.indexOf('w'));
}
for (int w = 0; w <= 1; w++) {
fmt = fmts[w];
if (fmt == null) continue;
int length = fmt.length();
int index = Math.max(0, fmt.indexOf('k'));
int tag = CONSTANT_None;
int branch = Math.max(0, fmt.indexOf('o'));
int slot = Math.max(0, fmt.indexOf('l'));
int con = Math.max(0, fmt.indexOf('x'));
if (index > 0 && index+1 < length) {
switch (fmt.charAt(index+1)) {
case 'c': tag = CONSTANT_Class; break;
case 'k': tag = CONSTANT_LoadableValue; break;
case 'f': tag = CONSTANT_Fieldref; break;
case 'm': tag = CONSTANT_Methodref; break;
case 'i': tag = CONSTANT_InterfaceMethodref; break;
case 'y': tag = CONSTANT_InvokeDynamic; break;
}
assert(tag != CONSTANT_None);
} else if (index > 0 && length == 2) {
assert(from_bc == _ldc);
tag = CONSTANT_LoadableValue; // _ldc opcode only
}
for (int bc = from_bc; bc <= to_bc; bc++) {
BC_FORMAT[w][bc] = fmt;
assert(BC_LENGTH[w][bc] == -1);
BC_LENGTH[w][bc] = (byte) length;
BC_INDEX[w][bc] = (byte) index;
BC_TAG[w][bc] = (byte) tag;
assert(!(index == 0 && tag != CONSTANT_None));
BC_BRANCH[w][bc] = (byte) branch;
BC_SLOT[w][bc] = (byte) slot;
assert(branch == 0 || slot == 0); // not both branch & local
assert(branch == 0 || index == 0); // not both branch & cp
assert(slot == 0 || index == 0); // not both local & cp
BC_CON[w][bc] = (byte) con;
}
}
}
public static void opcodeChecker(byte[] code, ConstantPool.Entry[] cpMap,
Package.Version clsVersion) throws FormatException {
Instruction i = at(code, 0);
while (i != null) {
int opcode = i.getBC();
if (opcode < _nop || opcode > _jsr_w) {
String message = "illegal opcode: " + opcode + " " + i;
throw new FormatException(message);
}
ConstantPool.Entry e = i.getCPRef(cpMap);
if (e != null) {
byte tag = i.getCPTag();
boolean match = e.tagMatches(tag);
if (!match &&
(i.bc == _invokespecial || i.bc == _invokestatic) &&
e.tagMatches(CONSTANT_InterfaceMethodref) &&
clsVersion.greaterThan(Constants.JAVA7_MAX_CLASS_VERSION)) {
match = true;
}
if (!match) {
String message = "illegal reference, expected type="
+ ConstantPool.tagName(tag) + ": "
+ i.toString(cpMap);
throw new FormatException(message);
}
}
i = i.next();
}
}
static class FormatException extends IOException {
@java.io.Serial
private static final long serialVersionUID = 3175572275651367015L;
FormatException(String message) {
super(message);
}
}
}

View file

@ -1,332 +0,0 @@
/*
* Copyright (c) 2003, 2013, 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.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.util.jar.JarOutputStream;
import java.util.jar.Pack200;
import java.util.zip.CRC32;
import java.util.zip.Deflater;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
@SuppressWarnings({"removal"})
class NativeUnpack {
// Pointer to the native unpacker obj
private long unpackerPtr;
// Input stream.
private BufferedInputStream in;
private static synchronized native void initIDs();
// Starts processing at the indicated position in the buffer.
// If the buffer is null, the readInputFn callback is used to get bytes.
// Returns (s<<32|f), the number of following segments and files.
private synchronized native long start(ByteBuffer buf, long offset);
// Returns true if there's another, and fills in the parts.
private synchronized native boolean getNextFile(Object[] parts);
private synchronized native ByteBuffer getUnusedInput();
// Resets the engine and frees all resources.
// Returns total number of bytes consumed by the engine.
private synchronized native long finish();
// Setting state in the unpacker.
protected synchronized native boolean setOption(String opt, String value);
protected synchronized native String getOption(String opt);
private int _verbose;
// State for progress bar:
private long _byteCount; // bytes read in current segment
private int _segCount; // number of segs scanned
private int _fileCount; // number of files written
private long _estByteLimit; // estimate of eventual total
private int _estSegLimit; // ditto
private int _estFileLimit; // ditto
private int _prevPercent = -1; // for monotonicity
private final CRC32 _crc32 = new CRC32();
private byte[] _buf = new byte[1<<14];
private UnpackerImpl _p200;
private PropMap _props;
static {
// If loading from stand alone build uncomment this.
// System.loadLibrary("unpack");
java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction<>() {
public Void run() {
System.loadLibrary("unpack");
return null;
}
});
initIDs();
}
NativeUnpack(UnpackerImpl p200) {
super();
_p200 = p200;
_props = p200.props;
p200._nunp = this;
}
// for JNI callbacks
private static Object currentInstance() {
UnpackerImpl p200 = (UnpackerImpl) Utils.getTLGlobals();
return (p200 == null)? null: p200._nunp;
}
private synchronized long getUnpackerPtr() {
return unpackerPtr;
}
// Callback from the unpacker engine to get more data.
private long readInputFn(ByteBuffer pbuf, long minlen) throws IOException {
if (in == null) return 0; // nothing is readable
long maxlen = pbuf.capacity() - pbuf.position();
assert(minlen <= maxlen); // don't talk nonsense
long numread = 0;
int steps = 0;
while (numread < minlen) {
steps++;
// read available input, up to buf.length or maxlen
int readlen = _buf.length;
if (readlen > (maxlen - numread))
readlen = (int)(maxlen - numread);
int nr = in.read(_buf, 0, readlen);
if (nr <= 0) break;
numread += nr;
assert(numread <= maxlen);
// %%% get rid of this extra copy by using nio?
pbuf.put(_buf, 0, nr);
}
if (_verbose > 1)
Utils.log.fine("readInputFn("+minlen+","+maxlen+") => "+numread+" steps="+steps);
if (maxlen > 100) {
_estByteLimit = _byteCount + maxlen;
} else {
_estByteLimit = (_byteCount + numread) * 20;
}
_byteCount += numread;
updateProgress();
return numread;
}
private void updateProgress() {
// Progress is a combination of segment reading and file writing.
final double READ_WT = 0.33;
final double WRITE_WT = 0.67;
double readProgress = _segCount;
if (_estByteLimit > 0 && _byteCount > 0)
readProgress += (double)_byteCount / _estByteLimit;
double writeProgress = _fileCount;
double scaledProgress
= READ_WT * readProgress / Math.max(_estSegLimit,1)
+ WRITE_WT * writeProgress / Math.max(_estFileLimit,1);
int percent = (int) Math.round(100*scaledProgress);
if (percent > 100) percent = 100;
if (percent > _prevPercent) {
_prevPercent = percent;
_props.setInteger(Pack200.Unpacker.PROGRESS, percent);
if (_verbose > 0)
Utils.log.info("progress = "+percent);
}
}
private void copyInOption(String opt) {
String val = _props.getProperty(opt);
if (_verbose > 0)
Utils.log.info("set "+opt+"="+val);
if (val != null) {
boolean set = setOption(opt, val);
if (!set)
Utils.log.warning("Invalid option "+opt+"="+val);
}
}
void run(InputStream inRaw, JarOutputStream jstream,
ByteBuffer presetInput) throws IOException {
BufferedInputStream in0 = new BufferedInputStream(inRaw);
this.in = in0; // for readInputFn to see
_verbose = _props.getInteger(Utils.DEBUG_VERBOSE);
// Fix for BugId: 4902477, -unpack.modification.time = 1059010598000
// TODO eliminate and fix in unpack.cpp
final int modtime = Pack200.Packer.KEEP.equals(_props.getProperty(Utils.UNPACK_MODIFICATION_TIME, "0")) ?
Constants.NO_MODTIME : _props.getTime(Utils.UNPACK_MODIFICATION_TIME);
copyInOption(Utils.DEBUG_VERBOSE);
copyInOption(Pack200.Unpacker.DEFLATE_HINT);
if (modtime == Constants.NO_MODTIME) // Don't pass KEEP && NOW
copyInOption(Utils.UNPACK_MODIFICATION_TIME);
updateProgress(); // reset progress bar
for (;;) {
// Read the packed bits.
long counts = start(presetInput, 0);
_byteCount = _estByteLimit = 0; // reset partial scan counts
++_segCount; // just finished scanning a whole segment...
int nextSeg = (int)( counts >>> 32 );
int nextFile = (int)( counts >>> 0 );
// Estimate eventual total number of segments and files.
_estSegLimit = _segCount + nextSeg;
double filesAfterThisSeg = _fileCount + nextFile;
_estFileLimit = (int)( (filesAfterThisSeg *
_estSegLimit) / _segCount );
// Write the files.
int[] intParts = { 0,0, 0, 0 };
// intParts = {size.hi/lo, mod, defl}
Object[] parts = { intParts, null, null, null };
// parts = { {intParts}, name, data0/1 }
while (getNextFile(parts)) {
//BandStructure.printArrayTo(System.out, intParts, 0, parts.length);
String name = (String) parts[1];
long size = ( (long)intParts[0] << 32)
+ (((long)intParts[1] << 32) >>> 32);
long mtime = (modtime != Constants.NO_MODTIME ) ?
modtime : intParts[2] ;
boolean deflateHint = (intParts[3] != 0);
ByteBuffer data0 = (ByteBuffer) parts[2];
ByteBuffer data1 = (ByteBuffer) parts[3];
writeEntry(jstream, name, mtime, size, deflateHint,
data0, data1);
++_fileCount;
updateProgress();
}
presetInput = getUnusedInput();
long consumed = finish();
if (_verbose > 0)
Utils.log.info("bytes consumed = "+consumed);
if (presetInput == null &&
!Utils.isPackMagic(Utils.readMagic(in0))) {
break;
}
if (_verbose > 0 ) {
if (presetInput != null)
Utils.log.info("unused input = "+presetInput);
}
}
}
void run(InputStream in, JarOutputStream jstream) throws IOException {
run(in, jstream, null);
}
void run(File inFile, JarOutputStream jstream) throws IOException {
// %%% maybe memory-map the file, and pass it straight into unpacker
ByteBuffer mappedFile = null;
try (FileInputStream fis = new FileInputStream(inFile)) {
run(fis, jstream, mappedFile);
}
// Note: caller is responsible to finish with jstream.
}
private void writeEntry(JarOutputStream j, String name,
long mtime, long lsize, boolean deflateHint,
ByteBuffer data0, ByteBuffer data1) throws IOException {
int size = (int)lsize;
if (size != lsize)
throw new IOException("file too large: "+lsize);
CRC32 crc32 = _crc32;
if (_verbose > 1)
Utils.log.fine("Writing entry: "+name+" size="+size
+(deflateHint?" deflated":""));
if (_buf.length < size) {
int newSize = size;
while (newSize < _buf.length) {
newSize <<= 1;
if (newSize <= 0) {
newSize = size;
break;
}
}
_buf = new byte[newSize];
}
assert(_buf.length >= size);
int fillp = 0;
if (data0 != null) {
int size0 = data0.capacity();
data0.get(_buf, fillp, size0);
fillp += size0;
}
if (data1 != null) {
int size1 = data1.capacity();
data1.get(_buf, fillp, size1);
fillp += size1;
}
while (fillp < size) {
// Fill in rest of data from the stream itself.
int nr = in.read(_buf, fillp, size - fillp);
if (nr <= 0) throw new IOException("EOF at end of archive");
fillp += nr;
}
ZipEntry z = new ZipEntry(name);
z.setTime(mtime * 1000);
if (size == 0) {
z.setMethod(ZipOutputStream.STORED);
z.setSize(0);
z.setCrc(0);
z.setCompressedSize(0);
} else if (!deflateHint) {
z.setMethod(ZipOutputStream.STORED);
z.setSize(size);
z.setCompressedSize(size);
crc32.reset();
crc32.update(_buf, 0, size);
z.setCrc(crc32.getValue());
} else {
z.setMethod(Deflater.DEFLATED);
z.setSize(size);
}
j.putNextEntry(z);
if (size > 0)
j.write(_buf, 0, size);
j.closeEntry();
if (_verbose > 0) Utils.log.info("Writing " + Utils.zeString(z));
}
}

View file

@ -1,611 +0,0 @@
/*
* Copyright (c) 2003, 2015, 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 com.sun.java.util.jar.pack.Attribute.Layout;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.SortedMap;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarInputStream;
import java.util.jar.Pack200;
/*
* Implementation of the Pack provider.
* </pre></blockquote>
* @author John Rose
* @author Kumar Srinivasan
*/
@SuppressWarnings({"removal"})
public class PackerImpl extends TLGlobals implements Pack200.Packer {
/**
* Constructs a Packer object and sets the initial state of
* the packer engines.
*/
public PackerImpl() {}
/**
* Get the set of options for the pack and unpack engines.
* @return A sorted association of option key strings to option values.
*/
public SortedMap<String, String> properties() {
return props;
}
//Driver routines
/**
* Takes a JarFile and converts into a pack-stream.
* <p>
* Closes its input but not its output. (Pack200 archives are appendable.)
* @param in a JarFile
* @param out an OutputStream
* @exception IOException if an error is encountered.
*/
public synchronized void pack(JarFile in, OutputStream out) throws IOException {
assert(Utils.currentInstance.get() == null);
try {
Utils.currentInstance.set(this);
if ("0".equals(props.getProperty(Pack200.Packer.EFFORT))) {
Utils.copyJarFile(in, out);
} else {
(new DoPack()).run(in, out);
}
} finally {
Utils.currentInstance.set(null);
in.close();
}
}
/**
* Takes a JarInputStream and converts into a pack-stream.
* <p>
* Closes its input but not its output. (Pack200 archives are appendable.)
* <p>
* The modification time and deflation hint attributes are not available,
* for the jar-manifest file and the directory containing the file.
*
* @see #MODIFICATION_TIME
* @see #DEFLATION_HINT
* @param in a JarInputStream
* @param out an OutputStream
* @exception IOException if an error is encountered.
*/
public synchronized void pack(JarInputStream in, OutputStream out) throws IOException {
assert(Utils.currentInstance.get() == null);
try {
Utils.currentInstance.set(this);
if ("0".equals(props.getProperty(Pack200.Packer.EFFORT))) {
Utils.copyJarFile(in, out);
} else {
(new DoPack()).run(in, out);
}
} finally {
Utils.currentInstance.set(null);
in.close();
}
}
// All the worker bees.....
// The packer worker.
private class DoPack {
final int verbose = props.getInteger(Utils.DEBUG_VERBOSE);
{
props.setInteger(Pack200.Packer.PROGRESS, 0);
if (verbose > 0) Utils.log.info(props.toString());
}
// Here's where the bits are collected before getting packed, we also
// initialize the version numbers now.
final Package pkg = new Package(Package.Version.makeVersion(props, "min.class"),
Package.Version.makeVersion(props, "max.class"),
Package.Version.makeVersion(props, "package"));
final String unknownAttrCommand;
{
String uaMode = props.getProperty(Pack200.Packer.UNKNOWN_ATTRIBUTE, Pack200.Packer.PASS);
if (!(Pack200.Packer.STRIP.equals(uaMode) ||
Pack200.Packer.PASS.equals(uaMode) ||
Pack200.Packer.ERROR.equals(uaMode))) {
throw new RuntimeException("Bad option: " + Pack200.Packer.UNKNOWN_ATTRIBUTE + " = " + uaMode);
}
unknownAttrCommand = uaMode.intern();
}
final String classFormatCommand;
{
String fmtMode = props.getProperty(Utils.CLASS_FORMAT_ERROR, Pack200.Packer.PASS);
if (!(Pack200.Packer.PASS.equals(fmtMode) ||
Pack200.Packer.ERROR.equals(fmtMode))) {
throw new RuntimeException("Bad option: " + Utils.CLASS_FORMAT_ERROR + " = " + fmtMode);
}
classFormatCommand = fmtMode.intern();
}
final Map<Attribute.Layout, Attribute> attrDefs;
final Map<Attribute.Layout, String> attrCommands;
{
Map<Attribute.Layout, Attribute> lattrDefs = new HashMap<>();
Map<Attribute.Layout, String> lattrCommands = new HashMap<>();
String[] keys = {
Pack200.Packer.CLASS_ATTRIBUTE_PFX,
Pack200.Packer.FIELD_ATTRIBUTE_PFX,
Pack200.Packer.METHOD_ATTRIBUTE_PFX,
Pack200.Packer.CODE_ATTRIBUTE_PFX
};
int[] ctypes = {
Constants.ATTR_CONTEXT_CLASS,
Constants.ATTR_CONTEXT_FIELD,
Constants.ATTR_CONTEXT_METHOD,
Constants.ATTR_CONTEXT_CODE
};
for (int i = 0; i < ctypes.length; i++) {
String pfx = keys[i];
Map<String, String> map = props.prefixMap(pfx);
for (String key : map.keySet()) {
assert(key.startsWith(pfx));
String name = key.substring(pfx.length());
String layout = props.getProperty(key);
Layout lkey = Attribute.keyForLookup(ctypes[i], name);
if (Pack200.Packer.STRIP.equals(layout) ||
Pack200.Packer.PASS.equals(layout) ||
Pack200.Packer.ERROR.equals(layout)) {
lattrCommands.put(lkey, layout.intern());
} else {
Attribute.define(lattrDefs, ctypes[i], name, layout);
if (verbose > 1) {
Utils.log.fine("Added layout for "+Constants.ATTR_CONTEXT_NAME[i]+" attribute "+name+" = "+layout);
}
assert(lattrDefs.containsKey(lkey));
}
}
}
this.attrDefs = (lattrDefs.isEmpty()) ? null : lattrDefs;
this.attrCommands = (lattrCommands.isEmpty()) ? null : lattrCommands;
}
final boolean keepFileOrder
= props.getBoolean(Pack200.Packer.KEEP_FILE_ORDER);
final boolean keepClassOrder
= props.getBoolean(Utils.PACK_KEEP_CLASS_ORDER);
final boolean keepModtime
= Pack200.Packer.KEEP.equals(props.getProperty(Pack200.Packer.MODIFICATION_TIME));
final boolean latestModtime
= Pack200.Packer.LATEST.equals(props.getProperty(Pack200.Packer.MODIFICATION_TIME));
final boolean keepDeflateHint
= Pack200.Packer.KEEP.equals(props.getProperty(Pack200.Packer.DEFLATE_HINT));
{
if (!keepModtime && !latestModtime) {
int modtime = props.getTime(Pack200.Packer.MODIFICATION_TIME);
if (modtime != Constants.NO_MODTIME) {
pkg.default_modtime = modtime;
}
}
if (!keepDeflateHint) {
boolean deflate_hint = props.getBoolean(Pack200.Packer.DEFLATE_HINT);
if (deflate_hint) {
pkg.default_options |= Constants.AO_DEFLATE_HINT;
}
}
}
long totalOutputSize = 0;
int segmentCount = 0;
long segmentTotalSize = 0;
long segmentSize = 0; // running counter
final long segmentLimit;
{
long limit;
if (props.getProperty(Pack200.Packer.SEGMENT_LIMIT, "").isEmpty())
limit = -1;
else
limit = props.getLong(Pack200.Packer.SEGMENT_LIMIT);
limit = Math.min(Integer.MAX_VALUE, limit);
limit = Math.max(-1, limit);
if (limit == -1)
limit = Long.MAX_VALUE;
segmentLimit = limit;
}
final List<String> passFiles; // parsed pack.pass.file options
{
// Which class files will be passed through?
passFiles = props.getProperties(Pack200.Packer.PASS_FILE_PFX);
for (ListIterator<String> i = passFiles.listIterator(); i.hasNext(); ) {
String file = i.next();
if (file == null) { i.remove(); continue; }
file = Utils.getJarEntryName(file); // normalize '\\' to '/'
if (file.endsWith("/"))
file = file.substring(0, file.length()-1);
i.set(file);
}
if (verbose > 0) Utils.log.info("passFiles = " + passFiles);
}
{
// Hook for testing: Forces use of special archive modes.
int opt = props.getInteger(Utils.COM_PREFIX+"archive.options");
if (opt != 0)
pkg.default_options |= opt;
}
// (Done collecting options from props.)
// Get a new package, based on the old one.
private void makeNextPackage() {
pkg.reset();
}
final class InFile {
final String name;
final JarFile jf;
final JarEntry je;
final File f;
int modtime = Constants.NO_MODTIME;
int options;
InFile(String name) {
this.name = Utils.getJarEntryName(name);
this.f = new File(name);
this.jf = null;
this.je = null;
int timeSecs = getModtime(f.lastModified());
if (keepModtime && timeSecs != Constants.NO_MODTIME) {
this.modtime = timeSecs;
} else if (latestModtime && timeSecs > pkg.default_modtime) {
pkg.default_modtime = timeSecs;
}
}
InFile(JarFile jf, JarEntry je) {
this.name = Utils.getJarEntryName(je.getName());
this.f = null;
this.jf = jf;
this.je = je;
int timeSecs = (int) je.getTimeLocal()
.atOffset(ZoneOffset.UTC)
.toEpochSecond();
if (keepModtime && timeSecs != Constants.NO_MODTIME) {
this.modtime = timeSecs;
} else if (latestModtime && timeSecs > pkg.default_modtime) {
pkg.default_modtime = timeSecs;
}
if (keepDeflateHint && je.getMethod() == JarEntry.DEFLATED) {
options |= Constants.FO_DEFLATE_HINT;
}
}
InFile(JarEntry je) {
this(null, je);
}
boolean isClassFile() {
if (!name.endsWith(".class") || name.endsWith("module-info.class")) {
return false;
}
for (String prefix = name;;) {
if (passFiles.contains(prefix)) {
return false;
}
int chop = prefix.lastIndexOf('/');
if (chop < 0) {
break;
}
prefix = prefix.substring(0, chop);
}
return true;
}
boolean isMetaInfFile() {
return name.startsWith("/" + Utils.METAINF)
|| name.startsWith(Utils.METAINF);
}
boolean mustProcess() {
return !isMetaInfFile() && isClassFile();
}
long getInputLength() {
long len = (je != null)? je.getSize(): f.length();
assert(len >= 0) : this+".len="+len;
// Bump size by pathname length and modtime/def-hint bytes.
return Math.max(0, len) + name.length() + 5;
}
int getModtime(long timeMillis) {
// Convert milliseconds to seconds.
long seconds = (timeMillis+500) / 1000;
if ((int)seconds == seconds) {
return (int)seconds;
} else {
Utils.log.warning("overflow in modtime for "+f);
return Constants.NO_MODTIME;
}
}
void copyTo(Package.File file) {
if (modtime != Constants.NO_MODTIME)
file.modtime = modtime;
file.options |= options;
}
InputStream getInputStream() throws IOException {
if (jf != null)
return jf.getInputStream(je);
else
return new FileInputStream(f);
}
public String toString() {
return name;
}
}
private int nread = 0; // used only if (verbose > 0)
private void noteRead(InFile f) {
nread++;
if (verbose > 2)
Utils.log.fine("...read "+f.name);
if (verbose > 0 && (nread % 1000) == 0)
Utils.log.info("Have read "+nread+" files...");
}
void run(JarInputStream in, OutputStream out) throws IOException {
// First thing we do is get the manifest, as JIS does
// not provide the Manifest as an entry.
if (in.getManifest() != null) {
ByteArrayOutputStream tmp = new ByteArrayOutputStream();
in.getManifest().write(tmp);
InputStream tmpIn = new ByteArrayInputStream(tmp.toByteArray());
pkg.addFile(readFile(JarFile.MANIFEST_NAME, tmpIn));
}
for (JarEntry je; (je = in.getNextJarEntry()) != null; ) {
InFile inFile = new InFile(je);
String name = inFile.name;
Package.File bits = readFile(name, in);
Package.File file = null;
// (5078608) : discount the resource files in META-INF
// from segment computation.
long inflen = (inFile.isMetaInfFile())
? 0L
: inFile.getInputLength();
if ((segmentSize += inflen) > segmentLimit) {
segmentSize -= inflen;
int nextCount = -1; // don't know; it's a stream
flushPartial(out, nextCount);
}
if (verbose > 1) {
Utils.log.fine("Reading " + name);
}
assert(je.isDirectory() == name.endsWith("/"));
if (inFile.mustProcess()) {
file = readClass(name, bits.getInputStream());
}
if (file == null) {
file = bits;
pkg.addFile(file);
}
inFile.copyTo(file);
noteRead(inFile);
}
flushAll(out);
}
void run(JarFile in, OutputStream out) throws IOException {
List<InFile> inFiles = scanJar(in);
if (verbose > 0)
Utils.log.info("Reading " + inFiles.size() + " files...");
int numDone = 0;
for (InFile inFile : inFiles) {
String name = inFile.name;
// (5078608) : discount the resource files completely from segmenting
long inflen = (inFile.isMetaInfFile())
? 0L
: inFile.getInputLength() ;
if ((segmentSize += inflen) > segmentLimit) {
segmentSize -= inflen;
// Estimate number of remaining segments:
float filesDone = numDone+1;
float segsDone = segmentCount+1;
float filesToDo = inFiles.size() - filesDone;
float segsToDo = filesToDo * (segsDone/filesDone);
if (verbose > 1)
Utils.log.fine("Estimated segments to do: "+segsToDo);
flushPartial(out, (int) Math.ceil(segsToDo));
}
InputStream strm = inFile.getInputStream();
if (verbose > 1)
Utils.log.fine("Reading " + name);
Package.File file = null;
if (inFile.mustProcess()) {
file = readClass(name, strm);
if (file == null) {
strm.close();
strm = inFile.getInputStream();
}
}
if (file == null) {
file = readFile(name, strm);
pkg.addFile(file);
}
inFile.copyTo(file);
strm.close(); // tidy up
noteRead(inFile);
numDone += 1;
}
flushAll(out);
}
Package.File readClass(String fname, InputStream in) throws IOException {
Package.Class cls = pkg.new Class(fname);
in = new BufferedInputStream(in);
ClassReader reader = new ClassReader(cls, in);
reader.setAttrDefs(attrDefs);
reader.setAttrCommands(attrCommands);
reader.unknownAttrCommand = unknownAttrCommand;
try {
reader.read();
} catch (IOException ioe) {
String message = "Passing class file uncompressed due to";
if (ioe instanceof Attribute.FormatException) {
Attribute.FormatException ee = (Attribute.FormatException) ioe;
// He passed up the category to us in layout.
if (ee.layout.equals(Pack200.Packer.PASS)) {
Utils.log.info(ee.toString());
Utils.log.warning(message + " unrecognized attribute: " +
fname);
return null;
}
} else if (ioe instanceof ClassReader.ClassFormatException) {
ClassReader.ClassFormatException ce = (ClassReader.ClassFormatException) ioe;
if (classFormatCommand.equals(Pack200.Packer.PASS)) {
Utils.log.info(ce.toString());
Utils.log.warning(message + " unknown class format: " +
fname);
return null;
}
}
// Otherwise, it must be an error.
throw ioe;
}
pkg.addClass(cls);
return cls.file;
}
// Read raw data.
Package.File readFile(String fname, InputStream in) throws IOException {
Package.File file = pkg.new File(fname);
file.readFrom(in);
if (file.isDirectory() && file.getFileLength() != 0)
throw new IllegalArgumentException("Non-empty directory: "+file.getFileName());
return file;
}
void flushPartial(OutputStream out, int nextCount) throws IOException {
if (pkg.files.isEmpty() && pkg.classes.isEmpty()) {
return; // do not flush an empty segment
}
flushPackage(out, Math.max(1, nextCount));
props.setInteger(Pack200.Packer.PROGRESS, 25);
// In case there will be another segment:
makeNextPackage();
segmentCount += 1;
segmentTotalSize += segmentSize;
segmentSize = 0;
}
void flushAll(OutputStream out) throws IOException {
props.setInteger(Pack200.Packer.PROGRESS, 50);
flushPackage(out, 0);
out.flush();
props.setInteger(Pack200.Packer.PROGRESS, 100);
segmentCount += 1;
segmentTotalSize += segmentSize;
segmentSize = 0;
if (verbose > 0 && segmentCount > 1) {
Utils.log.info("Transmitted "
+segmentTotalSize+" input bytes in "
+segmentCount+" segments totaling "
+totalOutputSize+" bytes");
}
}
/** Write all information in the current package segment
* to the output stream.
*/
void flushPackage(OutputStream out, int nextCount) throws IOException {
int nfiles = pkg.files.size();
if (!keepFileOrder) {
// Keeping the order of classes costs about 1%
// Keeping the order of all files costs something more.
if (verbose > 1) Utils.log.fine("Reordering files.");
boolean stripDirectories = true;
pkg.reorderFiles(keepClassOrder, stripDirectories);
} else {
// Package builder must have created a stub for each class.
assert(pkg.files.containsAll(pkg.getClassStubs()));
// Order of stubs in file list must agree with classes.
List<Package.File> res = pkg.files;
assert((res = new ArrayList<>(pkg.files))
.retainAll(pkg.getClassStubs()) || true);
assert(res.equals(pkg.getClassStubs()));
}
pkg.trimStubs();
// Do some stripping, maybe.
if (props.getBoolean(Utils.COM_PREFIX+"strip.debug")) pkg.stripAttributeKind("Debug");
if (props.getBoolean(Utils.COM_PREFIX+"strip.compile")) pkg.stripAttributeKind("Compile");
if (props.getBoolean(Utils.COM_PREFIX+"strip.constants")) pkg.stripAttributeKind("Constant");
if (props.getBoolean(Utils.COM_PREFIX+"strip.exceptions")) pkg.stripAttributeKind("Exceptions");
if (props.getBoolean(Utils.COM_PREFIX+"strip.innerclasses")) pkg.stripAttributeKind("InnerClasses");
PackageWriter pw = new PackageWriter(pkg, out);
pw.archiveNextCount = nextCount;
pw.write();
out.flush();
if (verbose > 0) {
long outSize = pw.archiveSize0+pw.archiveSize1;
totalOutputSize += outSize;
long inSize = segmentSize;
Utils.log.info("Transmitted "
+nfiles+" files of "
+inSize+" input bytes in a segment of "
+outSize+" bytes");
}
}
List<InFile> scanJar(JarFile jf) throws IOException {
// Collect jar entries, preserving order.
List<InFile> inFiles = new ArrayList<>();
try {
for (JarEntry je : Collections.list(jf.entries())) {
InFile inFile = new InFile(jf, je);
assert(je.isDirectory() == inFile.name.endsWith("/"));
inFiles.add(inFile);
}
} catch (IllegalStateException ise) {
throw new IOException(ise.getLocalizedMessage(), ise);
}
return inFiles;
}
}
}

View file

@ -1,500 +0,0 @@
/*
* Copyright (c) 2003, 2010, 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.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import static com.sun.java.util.jar.pack.Constants.*;
/**
* Population-based coding.
* See the section "Encodings of Uncorrelated Values" in the Pack200 spec.
* @author John Rose
*/
// This tactic alone reduces the final zipped rt.jar by about a percent.
class PopulationCoding implements CodingMethod {
Histogram vHist; // histogram of all values
int[] fValues; // list of favored values
int fVlen; // inclusive max index
long[] symtab; // int map of favored value -> token [1..#fValues]
CodingMethod favoredCoding;
CodingMethod tokenCoding;
CodingMethod unfavoredCoding;
int L = -1; //preferred L value for tokenCoding
public void setFavoredValues(int[] fValues, int fVlen) {
// Note: {f} is allFavoredValues[1..fvlen], not [0..fvlen-1].
// This is because zero is an exceptional favored value index.
assert(fValues[0] == 0); // must be empty
assert(this.fValues == null); // do not do this twice
this.fValues = fValues;
this.fVlen = fVlen;
if (L >= 0) {
setL(L); // reassert
}
}
public void setFavoredValues(int[] fValues) {
int lfVlen = fValues.length-1;
setFavoredValues(fValues, lfVlen);
}
public void setHistogram(Histogram vHist) {
this.vHist = vHist;
}
public void setL(int L) {
this.L = L;
if (L >= 0 && fValues != null && tokenCoding == null) {
tokenCoding = fitTokenCoding(fVlen, L);
assert(tokenCoding != null);
}
}
public static Coding fitTokenCoding(int fVlen, int L) {
// Find the smallest B s.t. (B,H,0) covers fVlen.
if (fVlen < 256)
// H/L do not matter when B==1
return BandStructure.BYTE1;
Coding longest = BandStructure.UNSIGNED5.setL(L);
if (!longest.canRepresentUnsigned(fVlen))
return null; // failure; L is too sharp and fVlen too large
Coding tc = longest;
for (Coding shorter = longest; ; ) {
shorter = shorter.setB(shorter.B()-1);
if (shorter.umax() < fVlen)
break;
tc = shorter; // shorten it by reducing B
}
return tc;
}
public void setFavoredCoding(CodingMethod favoredCoding) {
this.favoredCoding = favoredCoding;
}
public void setTokenCoding(CodingMethod tokenCoding) {
this.tokenCoding = tokenCoding;
this.L = -1;
if (tokenCoding instanceof Coding && fValues != null) {
Coding tc = (Coding) tokenCoding;
if (tc == fitTokenCoding(fVlen, tc.L()))
this.L = tc.L();
// Otherwise, it's a non-default coding.
}
}
public void setUnfavoredCoding(CodingMethod unfavoredCoding) {
this.unfavoredCoding = unfavoredCoding;
}
public int favoredValueMaxLength() {
if (L == 0)
return Integer.MAX_VALUE;
else
return BandStructure.UNSIGNED5.setL(L).umax();
}
public void resortFavoredValues() {
Coding tc = (Coding) tokenCoding;
// Make a local copy before reordering.
fValues = BandStructure.realloc(fValues, 1+fVlen);
// Resort favoredValues within each byte-size cadre.
int fillp = 1; // skip initial zero
for (int n = 1; n <= tc.B(); n++) {
int nmax = tc.byteMax(n);
if (nmax > fVlen)
nmax = fVlen;
if (nmax < tc.byteMin(n))
break;
int low = fillp;
int high = nmax+1;
if (high == low) continue;
assert(high > low)
: high+"!>"+low;
assert(tc.getLength(low) == n)
: n+" != len("+(low)+") == "+
tc.getLength(low);
assert(tc.getLength(high-1) == n)
: n+" != len("+(high-1)+") == "+
tc.getLength(high-1);
int midTarget = low + (high-low)/2;
int mid = low;
// Divide the values into cadres, and sort within each.
int prevCount = -1;
int prevLimit = low;
for (int i = low; i < high; i++) {
int val = fValues[i];
int count = vHist.getFrequency(val);
if (prevCount != count) {
if (n == 1) {
// For the single-byte encoding, keep strict order
// among frequency groups.
Arrays.sort(fValues, prevLimit, i);
} else if (Math.abs(mid - midTarget) >
Math.abs(i - midTarget)) {
// Find a single inflection point
// close to the middle of the byte-size cadre.
mid = i;
}
prevCount = count;
prevLimit = i;
}
}
if (n == 1) {
Arrays.sort(fValues, prevLimit, high);
} else {
// Sort up to the midpoint, if any.
Arrays.sort(fValues, low, mid);
Arrays.sort(fValues, mid, high);
}
assert(tc.getLength(low) == tc.getLength(mid));
assert(tc.getLength(low) == tc.getLength(high-1));
fillp = nmax+1;
}
assert(fillp == fValues.length);
// Reset symtab.
symtab = null;
}
public int getToken(int value) {
if (symtab == null)
symtab = makeSymtab();
int pos = Arrays.binarySearch(symtab, (long)value << 32);
if (pos < 0) pos = -pos-1;
if (pos < symtab.length && value == (int)(symtab[pos] >>> 32))
return (int)symtab[pos];
else
return 0;
}
public int[][] encodeValues(int[] values, int start, int end) {
// Compute token sequence.
int[] tokens = new int[end-start];
int nuv = 0;
for (int i = 0; i < tokens.length; i++) {
int val = values[start+i];
int tok = getToken(val);
if (tok != 0)
tokens[i] = tok;
else
nuv += 1;
}
// Compute unfavored value sequence.
int[] unfavoredValues = new int[nuv];
nuv = 0; // reset
for (int i = 0; i < tokens.length; i++) {
if (tokens[i] != 0) continue; // already covered
int val = values[start+i];
unfavoredValues[nuv++] = val;
}
assert(nuv == unfavoredValues.length);
return new int[][]{ tokens, unfavoredValues };
}
private long[] makeSymtab() {
long[] lsymtab = new long[fVlen];
for (int token = 1; token <= fVlen; token++) {
lsymtab[token-1] = ((long)fValues[token] << 32) | token;
}
// Index by value:
Arrays.sort(lsymtab);
return lsymtab;
}
private Coding getTailCoding(CodingMethod c) {
while (c instanceof AdaptiveCoding)
c = ((AdaptiveCoding)c).tailCoding;
return (Coding) c;
}
// CodingMethod methods.
public void writeArrayTo(OutputStream out, int[] a, int start, int end) throws IOException {
int[][] vals = encodeValues(a, start, end);
writeSequencesTo(out, vals[0], vals[1]);
}
void writeSequencesTo(OutputStream out, int[] tokens, int[] uValues) throws IOException {
favoredCoding.writeArrayTo(out, fValues, 1, 1+fVlen);
getTailCoding(favoredCoding).writeTo(out, computeSentinelValue());
tokenCoding.writeArrayTo(out, tokens, 0, tokens.length);
if (uValues.length > 0)
unfavoredCoding.writeArrayTo(out, uValues, 0, uValues.length);
}
int computeSentinelValue() {
Coding fc = getTailCoding(favoredCoding);
if (fc.isDelta()) {
// repeat the last favored value, using delta=0
return 0;
} else {
// else repeat the shorter of the min or last value
int min = fValues[1];
int last = min;
// (remember that fVlen is an inclusive limit in fValues)
for (int i = 2; i <= fVlen; i++) {
last = fValues[i];
min = moreCentral(min, last);
}
int endVal;
if (fc.getLength(min) <= fc.getLength(last))
return min;
else
return last;
}
}
public void readArrayFrom(InputStream in, int[] a, int start, int end) throws IOException {
// Parameters are fCode, L, uCode.
setFavoredValues(readFavoredValuesFrom(in, end-start));
// Read the tokens. Read them into the final array, for the moment.
tokenCoding.readArrayFrom(in, a, start, end);
// Decode the favored tokens.
int headp = 0, tailp = -1;
int uVlen = 0;
for (int i = start; i < end; i++) {
int tok = a[i];
if (tok == 0) {
// Make a linked list, and decode in a second pass.
if (tailp < 0) {
headp = i;
} else {
a[tailp] = i;
}
tailp = i;
uVlen += 1;
} else {
a[i] = fValues[tok];
}
}
// Walk the linked list of "zero" locations, decoding unfavored vals.
int[] uValues = new int[uVlen];
if (uVlen > 0)
unfavoredCoding.readArrayFrom(in, uValues, 0, uVlen);
for (int i = 0; i < uVlen; i++) {
int nextp = a[headp];
a[headp] = uValues[i];
headp = nextp;
}
}
int[] readFavoredValuesFrom(InputStream in, int maxForDebug) throws IOException {
int[] lfValues = new int[1000]; // realloc as needed
// The set uniqueValuesForDebug records all favored values.
// As each new value is added, we assert that the value
// was not already in the set.
Set<Integer> uniqueValuesForDebug = null;
assert((uniqueValuesForDebug = new HashSet<>()) != null);
int fillp = 1;
maxForDebug += fillp;
int min = Integer.MIN_VALUE; // farthest from the center
//int min2 = Integer.MIN_VALUE; // emulate buggy 150.7 spec.
int last = 0;
CodingMethod fcm = favoredCoding;
while (fcm instanceof AdaptiveCoding) {
AdaptiveCoding ac = (AdaptiveCoding) fcm;
int len = ac.headLength;
while (fillp + len > lfValues.length) {
lfValues = BandStructure.realloc(lfValues);
}
int newFillp = fillp + len;
ac.headCoding.readArrayFrom(in, lfValues, fillp, newFillp);
while (fillp < newFillp) {
int val = lfValues[fillp++];
assert(uniqueValuesForDebug.add(val));
assert(fillp <= maxForDebug);
last = val;
min = moreCentral(min, val);
//min2 = moreCentral2(min2, val, min);
}
fcm = ac.tailCoding;
}
Coding fc = (Coding) fcm;
if (fc.isDelta()) {
for (long state = 0;;) {
// Read a new value:
state += fc.readFrom(in);
int val;
if (fc.isSubrange())
val = fc.reduceToUnsignedRange(state);
else
val = (int)state;
state = val;
if (fillp > 1 && (val == last || val == min)) //|| val == min2
break;
if (fillp == lfValues.length)
lfValues = BandStructure.realloc(lfValues);
lfValues[fillp++] = val;
assert(uniqueValuesForDebug.add(val));
assert(fillp <= maxForDebug);
last = val;
min = moreCentral(min, val);
//min2 = moreCentral(min2, val);
}
} else {
for (;;) {
int val = fc.readFrom(in);
if (fillp > 1 && (val == last || val == min)) //|| val == min2
break;
if (fillp == lfValues.length)
lfValues = BandStructure.realloc(lfValues);
lfValues[fillp++] = val;
assert(uniqueValuesForDebug.add(val));
assert(fillp <= maxForDebug);
last = val;
min = moreCentral(min, val);
//min2 = moreCentral2(min2, val, min);
}
}
return BandStructure.realloc(lfValues, fillp);
}
private static int moreCentral(int x, int y) {
int kx = (x >> 31) ^ (x << 1);
int ky = (y >> 31) ^ (y << 1);
// bias kx/ky to get an unsigned comparison:
kx -= Integer.MIN_VALUE;
ky -= Integer.MIN_VALUE;
int xy = (kx < ky? x: y);
// assert that this ALU-ish version is the same:
assert(xy == moreCentralSlow(x, y));
return xy;
}
// private static int moreCentral2(int x, int y, int min) {
// // Strict implementation of buggy 150.7 specification.
// // The bug is that the spec. says absolute-value ties are broken
// // in favor of positive numbers, but the suggested implementation
// // (also mentioned in the spec.) breaks ties in favor of negatives.
// if (x + y == 0) return (x > y? x : y);
// return min;
// }
private static int moreCentralSlow(int x, int y) {
int ax = x;
if (ax < 0) ax = -ax;
if (ax < 0) return y; //x is MIN_VALUE
int ay = y;
if (ay < 0) ay = -ay;
if (ay < 0) return x; //y is MIN_VALUE
if (ax < ay) return x;
if (ax > ay) return y;
// At this point the absolute values agree, and the negative wins.
return x < y ? x : y;
}
static final int[] LValuesCoded
= { -1, 4, 8, 16, 32, 64, 128, 192, 224, 240, 248, 252 };
public byte[] getMetaCoding(Coding dflt) {
int K = fVlen;
int LCoded = 0;
if (tokenCoding instanceof Coding) {
Coding tc = (Coding) tokenCoding;
if (tc.B() == 1) {
LCoded = 1;
} else if (L >= 0) {
assert(L == tc.L());
for (int i = 1; i < LValuesCoded.length; i++) {
if (LValuesCoded[i] == L) { LCoded = i; break; }
}
}
}
CodingMethod tokenDflt = null;
if (LCoded != 0 && tokenCoding == fitTokenCoding(fVlen, L)) {
// A simple L value is enough to recover the tokenCoding.
tokenDflt = tokenCoding;
}
int FDef = (favoredCoding == dflt)?1:0;
int UDef = (unfavoredCoding == dflt || unfavoredCoding == null)?1:0;
int TDef = (tokenCoding == tokenDflt)?1:0;
int TDefL = (TDef == 1) ? LCoded : 0;
assert(TDef == ((TDefL>0)?1:0));
ByteArrayOutputStream bytes = new ByteArrayOutputStream(10);
bytes.write(_meta_pop + FDef + 2*UDef + 4*TDefL);
try {
if (FDef == 0) bytes.write(favoredCoding.getMetaCoding(dflt));
if (TDef == 0) bytes.write(tokenCoding.getMetaCoding(dflt));
if (UDef == 0) bytes.write(unfavoredCoding.getMetaCoding(dflt));
} catch (IOException ee) {
throw new RuntimeException(ee);
}
return bytes.toByteArray();
}
public static int parseMetaCoding(byte[] bytes, int pos, Coding dflt, CodingMethod res[]) {
int op = bytes[pos++] & 0xFF;
if (op < _meta_pop || op >= _meta_limit) return pos-1; // backup
op -= _meta_pop;
int FDef = op % 2;
int UDef = (op / 2) % 2;
int TDefL = (op / 4);
int TDef = (TDefL > 0)?1:0;
int L = LValuesCoded[TDefL];
CodingMethod[] FCode = {dflt}, TCode = {null}, UCode = {dflt};
if (FDef == 0)
pos = BandStructure.parseMetaCoding(bytes, pos, dflt, FCode);
if (TDef == 0)
pos = BandStructure.parseMetaCoding(bytes, pos, dflt, TCode);
if (UDef == 0)
pos = BandStructure.parseMetaCoding(bytes, pos, dflt, UCode);
PopulationCoding pop = new PopulationCoding();
pop.L = L; // might be -1
pop.favoredCoding = FCode[0];
pop.tokenCoding = TCode[0]; // might be null!
pop.unfavoredCoding = UCode[0];
res[0] = pop;
return pos;
}
private String keyString(CodingMethod m) {
if (m instanceof Coding)
return ((Coding)m).keyString();
if (m == null)
return "none";
return m.toString();
}
public String toString() {
PropMap p200 = Utils.currentPropMap();
boolean verbose
= (p200 != null &&
p200.getBoolean(Utils.COM_PREFIX+"verbose.pop"));
StringBuilder res = new StringBuilder(100);
res.append("pop(").append("fVlen=").append(fVlen);
if (verbose && fValues != null) {
res.append(" fV=[");
for (int i = 1; i <= fVlen; i++) {
res.append(i==1?"":",").append(fValues[i]);
}
res.append(";").append(computeSentinelValue());
res.append("]");
}
res.append(" fc=").append(keyString(favoredCoding));
res.append(" tc=").append(keyString(tokenCoding));
res.append(" uc=").append(keyString(unfavoredCoding));
res.append(")");
return res.toString();
}
}

View file

@ -1,332 +0,0 @@
/*
* Copyright (c) 2003, 2015, 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.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.jar.Pack200;
/**
* Control block for publishing Pack200 options to the other classes.
*/
@SuppressWarnings({"removal"})
final class PropMap implements SortedMap<String, String> {
private final TreeMap<String, String> theMap = new TreeMap<>();;
// Override:
public String put(String key, String value) {
String oldValue = theMap.put(key, value);
return oldValue;
}
// All this other stuff is private to the current package.
// Outide clients of Pack200 do not need to use it; they can
// get by with generic SortedMap functionality.
private static Map<String, String> defaultProps;
static {
Properties props = new Properties();
// Allow implementation selected via -Dpack.disable.native=true
String propValue = getPropertyValue(Utils.DEBUG_DISABLE_NATIVE, "false");
props.put(Utils.DEBUG_DISABLE_NATIVE,
String.valueOf(Boolean.parseBoolean(propValue)));
// Set the DEBUG_VERBOSE from system
int verbose = 0;
try {
verbose = Integer.decode(getPropertyValue(Utils.DEBUG_VERBOSE, "0"));
} catch (NumberFormatException e) {
}
props.put(Utils.DEBUG_VERBOSE, String.valueOf(verbose));
// The segment size is unlimited
props.put(Pack200.Packer.SEGMENT_LIMIT, "-1");
// Preserve file ordering by default.
props.put(Pack200.Packer.KEEP_FILE_ORDER, Pack200.Packer.TRUE);
// Preserve all modification times by default.
props.put(Pack200.Packer.MODIFICATION_TIME, Pack200.Packer.KEEP);
// Preserve deflation hints by default.
props.put(Pack200.Packer.DEFLATE_HINT, Pack200.Packer.KEEP);
// Pass through files with unrecognized attributes by default.
props.put(Pack200.Packer.UNKNOWN_ATTRIBUTE, Pack200.Packer.PASS);
// Pass through files with unrecognized format by default, also
// allow system property to be set
props.put(Utils.CLASS_FORMAT_ERROR,
getPropertyValue(Utils.CLASS_FORMAT_ERROR, Pack200.Packer.PASS));
// Default effort is 5, midway between 1 and 9.
props.put(Pack200.Packer.EFFORT, "5");
// Define certain attribute layouts by default.
// Do this after the previous props are put in place,
// to allow override if necessary.
String propFile = "intrinsic.properties";
PrivilegedAction<InputStream> pa =
() -> PackerImpl.class.getResourceAsStream(propFile);
try (InputStream propStr = AccessController.doPrivileged(pa)) {
if (propStr == null) {
throw new RuntimeException(propFile + " cannot be loaded");
}
props.load(propStr);
} catch (IOException ee) {
throw new RuntimeException(ee);
}
for (Map.Entry<Object, Object> e : props.entrySet()) {
String key = (String) e.getKey();
String val = (String) e.getValue();
if (key.startsWith("attribute.")) {
e.setValue(Attribute.normalizeLayoutString(val));
}
}
@SuppressWarnings({"unchecked", "rawtypes"})
HashMap<String, String> temp = new HashMap(props); // shrink to fit
defaultProps = temp;
}
private static String getPropertyValue(String key, String defaultValue) {
PrivilegedAction<String> pa = () -> System.getProperty(key);
String s = AccessController.doPrivileged(pa);
return s != null ? s : defaultValue;
}
PropMap() {
theMap.putAll(defaultProps);
}
// Return a view of this map which includes only properties
// that begin with the given prefix. This is easy because
// the map is sorted, and has a subMap accessor.
SortedMap<String, String> prefixMap(String prefix) {
int len = prefix.length();
if (len == 0)
return this;
char nextch = (char)(prefix.charAt(len-1) + 1);
String limit = prefix.substring(0, len-1)+nextch;
//System.out.println(prefix+" => "+subMap(prefix, limit));
return subMap(prefix, limit);
}
String getProperty(String s) {
return get(s);
}
String getProperty(String s, String defaultVal) {
String val = getProperty(s);
if (val == null)
return defaultVal;
return val;
}
String setProperty(String s, String val) {
return put(s, val);
}
// Get sequence of props for "prefix", and "prefix.*".
List<String> getProperties(String prefix) {
Collection<String> values = prefixMap(prefix).values();
List<String> res = new ArrayList<>(values.size());
res.addAll(values);
while (res.remove(null));
return res;
}
private boolean toBoolean(String val) {
return Boolean.valueOf(val).booleanValue();
}
boolean getBoolean(String s) {
return toBoolean(getProperty(s));
}
boolean setBoolean(String s, boolean val) {
return toBoolean(setProperty(s, String.valueOf(val)));
}
int toInteger(String val) {
return toInteger(val, 0);
}
int toInteger(String val, int def) {
if (val == null) return def;
if (Pack200.Packer.TRUE.equals(val)) return 1;
if (Pack200.Packer.FALSE.equals(val)) return 0;
return Integer.parseInt(val);
}
int getInteger(String s, int def) {
return toInteger(getProperty(s), def);
}
int getInteger(String s) {
return toInteger(getProperty(s));
}
int setInteger(String s, int val) {
return toInteger(setProperty(s, String.valueOf(val)));
}
long toLong(String val) {
try {
return val == null ? 0 : Long.parseLong(val);
} catch (java.lang.NumberFormatException nfe) {
throw new IllegalArgumentException("Invalid value");
}
}
long getLong(String s) {
return toLong(getProperty(s));
}
long setLong(String s, long val) {
return toLong(setProperty(s, String.valueOf(val)));
}
int getTime(String s) {
String sval = getProperty(s, "0");
if (Utils.NOW.equals(sval)) {
return (int)((System.currentTimeMillis()+500)/1000);
}
long lval = toLong(sval);
final long recentSecondCount = 1000000000;
if (lval < recentSecondCount*10 && !"0".equals(sval))
Utils.log.warning("Supplied modtime appears to be seconds rather than milliseconds: "+sval);
return (int)((lval+500)/1000);
}
void list(PrintStream out) {
PrintWriter outw = new PrintWriter(out);
list(outw);
outw.flush();
}
void list(PrintWriter out) {
out.println("#"+Utils.PACK_ZIP_ARCHIVE_MARKER_COMMENT+"[");
Set<Map.Entry<String, String>> defaults = defaultProps.entrySet();
for (Map.Entry<String, String> e : theMap.entrySet()) {
if (defaults.contains(e)) continue;
out.println(" " + e.getKey() + " = " + e.getValue());
}
out.println("#]");
}
@Override
public int size() {
return theMap.size();
}
@Override
public boolean isEmpty() {
return theMap.isEmpty();
}
@Override
public boolean containsKey(Object key) {
return theMap.containsKey(key);
}
@Override
public boolean containsValue(Object value) {
return theMap.containsValue(value);
}
@Override
public String get(Object key) {
return theMap.get(key);
}
@Override
public String remove(Object key) {
return theMap.remove(key);
}
@Override
public void putAll(Map<? extends String, ? extends String> m) {
theMap.putAll(m);
}
@Override
public void clear() {
theMap.clear();
}
@Override
public Set<String> keySet() {
return theMap.keySet();
}
@Override
public Collection<String> values() {
return theMap.values();
}
@Override
public Set<Map.Entry<String, String>> entrySet() {
return theMap.entrySet();
}
@Override
public Comparator<? super String> comparator() {
return theMap.comparator();
}
@Override
public SortedMap<String, String> subMap(String fromKey, String toKey) {
return theMap.subMap(fromKey, toKey);
}
@Override
public SortedMap<String, String> headMap(String toKey) {
return theMap.headMap(toKey);
}
@Override
public SortedMap<String, String> tailMap(String fromKey) {
return theMap.tailMap(fromKey);
}
@Override
public String firstKey() {
return theMap.firstKey();
}
@Override
public String lastKey() {
return theMap.lastKey();
}
}

View file

@ -1,125 +0,0 @@
/*
* Copyright (c) 2010, 2012, 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 com.sun.java.util.jar.pack.ConstantPool.ClassEntry;
import com.sun.java.util.jar.pack.ConstantPool.DescriptorEntry;
import com.sun.java.util.jar.pack.ConstantPool.LiteralEntry;
import com.sun.java.util.jar.pack.ConstantPool.MemberEntry;
import com.sun.java.util.jar.pack.ConstantPool.MethodHandleEntry;
import com.sun.java.util.jar.pack.ConstantPool.MethodTypeEntry;
import com.sun.java.util.jar.pack.ConstantPool.InvokeDynamicEntry;
import com.sun.java.util.jar.pack.ConstantPool.BootstrapMethodEntry;
import com.sun.java.util.jar.pack.ConstantPool.SignatureEntry;
import com.sun.java.util.jar.pack.ConstantPool.Utf8Entry;
import java.util.HashMap;
import java.util.Map;
import java.util.SortedMap;
/*
* @author ksrini
*/
/*
* This class provides a container to hold the global variables, for packer
* and unpacker instances. This is typically stashed away in a ThreadLocal,
* and the storage is destroyed upon completion. Therefore any local
* references to these members must be eliminated appropriately to prevent a
* memory leak.
*/
class TLGlobals {
// Global environment
final PropMap props;
// Needed by ConstantPool.java
private final Map<String, Utf8Entry> utf8Entries;
private final Map<String, ClassEntry> classEntries;
private final Map<Object, LiteralEntry> literalEntries;
private final Map<String, SignatureEntry> signatureEntries;
private final Map<String, DescriptorEntry> descriptorEntries;
private final Map<String, MemberEntry> memberEntries;
private final Map<String, MethodHandleEntry> methodHandleEntries;
private final Map<String, MethodTypeEntry> methodTypeEntries;
private final Map<String, InvokeDynamicEntry> invokeDynamicEntries;
private final Map<String, BootstrapMethodEntry> bootstrapMethodEntries;
TLGlobals() {
utf8Entries = new HashMap<>();
classEntries = new HashMap<>();
literalEntries = new HashMap<>();
signatureEntries = new HashMap<>();
descriptorEntries = new HashMap<>();
memberEntries = new HashMap<>();
methodHandleEntries = new HashMap<>();
methodTypeEntries = new HashMap<>();
invokeDynamicEntries = new HashMap<>();
bootstrapMethodEntries = new HashMap<>();
props = new PropMap();
}
SortedMap<String, String> getPropMap() {
return props;
}
Map<String, Utf8Entry> getUtf8Entries() {
return utf8Entries;
}
Map<String, ClassEntry> getClassEntries() {
return classEntries;
}
Map<Object, LiteralEntry> getLiteralEntries() {
return literalEntries;
}
Map<String, DescriptorEntry> getDescriptorEntries() {
return descriptorEntries;
}
Map<String, SignatureEntry> getSignatureEntries() {
return signatureEntries;
}
Map<String, MemberEntry> getMemberEntries() {
return memberEntries;
}
Map<String, MethodHandleEntry> getMethodHandleEntries() {
return methodHandleEntries;
}
Map<String, MethodTypeEntry> getMethodTypeEntries() {
return methodTypeEntries;
}
Map<String, InvokeDynamicEntry> getInvokeDynamicEntries() {
return invokeDynamicEntries;
}
Map<String, BootstrapMethodEntry> getBootstrapMethodEntries() {
return bootstrapMethodEntries;
}
}

View file

@ -1,263 +0,0 @@
/*
* Copyright (c) 2003, 2015, 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.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.HashSet;
import java.util.Set;
import java.util.SortedMap;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;
import java.util.jar.JarOutputStream;
import java.util.jar.Pack200;
import java.util.zip.CRC32;
import java.util.zip.CheckedOutputStream;
import java.util.zip.ZipEntry;
/*
* Implementation of the Pack provider.
* </pre></blockquote>
* @author John Rose
* @author Kumar Srinivasan
*/
@SuppressWarnings({"removal"})
public class UnpackerImpl extends TLGlobals implements Pack200.Unpacker {
public UnpackerImpl() {}
/**
* Get the set of options for the pack and unpack engines.
* @return A sorted association of option key strings to option values.
*/
public SortedMap<String, String> properties() {
return props;
}
// Back-pointer to NativeUnpacker, when active.
Object _nunp;
public String toString() {
return Utils.getVersionString();
}
//Driver routines
// The unpack worker...
/**
* Takes a packed-stream InputStream, and writes to a JarOutputStream. Internally
* the entire buffer must be read, it may be more efficient to read the packed-stream
* to a file and pass the File object, in the alternate method described below.
* <p>
* Closes its input but not its output. (The output can accumulate more elements.)
* @param in an InputStream.
* @param out a JarOutputStream.
* @exception IOException if an error is encountered.
*/
public synchronized void unpack(InputStream in, JarOutputStream out) throws IOException {
if (in == null) {
throw new NullPointerException("null input");
}
if (out == null) {
throw new NullPointerException("null output");
}
assert(Utils.currentInstance.get() == null);
try {
Utils.currentInstance.set(this);
final int verbose = props.getInteger(Utils.DEBUG_VERBOSE);
BufferedInputStream in0 = new BufferedInputStream(in);
if (Utils.isJarMagic(Utils.readMagic(in0))) {
if (verbose > 0)
Utils.log.info("Copying unpacked JAR file...");
Utils.copyJarFile(new JarInputStream(in0), out);
} else if (props.getBoolean(Utils.DEBUG_DISABLE_NATIVE)) {
(new DoUnpack()).run(in0, out);
in0.close();
Utils.markJarFile(out);
} else {
try {
(new NativeUnpack(this)).run(in0, out);
} catch (UnsatisfiedLinkError | NoClassDefFoundError ex) {
// failover to java implementation
(new DoUnpack()).run(in0, out);
}
in0.close();
Utils.markJarFile(out);
}
} finally {
_nunp = null;
Utils.currentInstance.set(null);
}
}
/**
* Takes an input File containing the pack file, and generates a JarOutputStream.
* <p>
* Does not close its output. (The output can accumulate more elements.)
* @param in a File.
* @param out a JarOutputStream.
* @exception IOException if an error is encountered.
*/
public synchronized void unpack(File in, JarOutputStream out) throws IOException {
if (in == null) {
throw new NullPointerException("null input");
}
if (out == null) {
throw new NullPointerException("null output");
}
// Use the stream-based implementation.
// %%% Reconsider if native unpacker learns to memory-map the file.
try (FileInputStream instr = new FileInputStream(in)) {
unpack(instr, out);
}
if (props.getBoolean(Utils.UNPACK_REMOVE_PACKFILE)) {
in.delete();
}
}
private class DoUnpack {
final int verbose = props.getInteger(Utils.DEBUG_VERBOSE);
{
props.setInteger(Pack200.Unpacker.PROGRESS, 0);
}
// Here's where the bits are read from disk:
final Package pkg = new Package();
final boolean keepModtime
= Pack200.Packer.KEEP.equals(
props.getProperty(Utils.UNPACK_MODIFICATION_TIME, Pack200.Packer.KEEP));
final boolean keepDeflateHint
= Pack200.Packer.KEEP.equals(
props.getProperty(Pack200.Unpacker.DEFLATE_HINT, Pack200.Packer.KEEP));
final int modtime;
final boolean deflateHint;
{
if (!keepModtime) {
modtime = props.getTime(Utils.UNPACK_MODIFICATION_TIME);
} else {
modtime = pkg.default_modtime;
}
deflateHint = (keepDeflateHint) ? false :
props.getBoolean(java.util.jar.Pack200.Unpacker.DEFLATE_HINT);
}
// Checksum apparatus.
final CRC32 crc = new CRC32();
final ByteArrayOutputStream bufOut = new ByteArrayOutputStream();
final OutputStream crcOut = new CheckedOutputStream(bufOut, crc);
public void run(BufferedInputStream in, JarOutputStream out) throws IOException {
if (verbose > 0) {
props.list(System.out);
}
for (int seg = 1; ; seg++) {
unpackSegment(in, out);
// Try to get another segment.
if (!Utils.isPackMagic(Utils.readMagic(in))) break;
if (verbose > 0)
Utils.log.info("Finished segment #"+seg);
}
}
private void unpackSegment(InputStream in, JarOutputStream out) throws IOException {
props.setProperty(java.util.jar.Pack200.Unpacker.PROGRESS,"0");
// Process the output directory or jar output.
new PackageReader(pkg, in).read();
if (props.getBoolean("unpack.strip.debug")) pkg.stripAttributeKind("Debug");
if (props.getBoolean("unpack.strip.compile")) pkg.stripAttributeKind("Compile");
props.setProperty(java.util.jar.Pack200.Unpacker.PROGRESS,"50");
pkg.ensureAllClassFiles();
// Now write out the files.
Set<Package.Class> classesToWrite = new HashSet<>(pkg.getClasses());
for (Package.File file : pkg.getFiles()) {
String name = file.nameString;
JarEntry je = new JarEntry(Utils.getJarEntryName(name));
boolean deflate;
deflate = (keepDeflateHint)
? (((file.options & Constants.FO_DEFLATE_HINT) != 0) ||
((pkg.default_options & Constants.AO_DEFLATE_HINT) != 0))
: deflateHint;
boolean needCRC = !deflate; // STORE mode requires CRC
if (needCRC) crc.reset();
bufOut.reset();
if (file.isClassStub()) {
Package.Class cls = file.getStubClass();
assert(cls != null);
new ClassWriter(cls, needCRC ? crcOut : bufOut).write();
classesToWrite.remove(cls); // for an error check
} else {
// collect data & maybe CRC
file.writeTo(needCRC ? crcOut : bufOut);
}
je.setMethod(deflate ? JarEntry.DEFLATED : JarEntry.STORED);
if (needCRC) {
if (verbose > 0)
Utils.log.info("stored size="+bufOut.size()+" and crc="+crc.getValue());
je.setMethod(JarEntry.STORED);
je.setSize(bufOut.size());
je.setCrc(crc.getValue());
}
if (keepModtime) {
LocalDateTime ldt = LocalDateTime
.ofEpochSecond(file.modtime, 0, ZoneOffset.UTC);
je.setTimeLocal(ldt);
} else {
je.setTime((long)modtime * 1000);
}
out.putNextEntry(je);
bufOut.writeTo(out);
out.closeEntry();
if (verbose > 0)
Utils.log.info("Writing "+Utils.zeString((ZipEntry)je));
}
assert(classesToWrite.isEmpty());
props.setProperty(java.util.jar.Pack200.Unpacker.PROGRESS,"100");
pkg.reset(); // reset for the next segment, if any
}
}
}

View file

@ -1,320 +0,0 @@
/*
* Copyright (c) 2003, 2015, 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.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Collections;
import java.util.Date;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarInputStream;
import java.util.jar.JarOutputStream;
import java.util.zip.ZipEntry;
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 = 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";
/*
* 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";
/*
* behaviour when we hit a class format error, but not necessarily
* an unknown attribute, by default it is allowed to PASS.
*/
static final String CLASS_FORMAT_ERROR = COM_PREFIX+"class.format.error";
// Keep a TLS point to the global data and environment.
// This makes it simpler to supply environmental options
// to the engine code, especially the native code.
static final ThreadLocal<TLGlobals> currentInstance = new ThreadLocal<>();
// convenience method to access the TL globals
static TLGlobals getTLGlobals() {
return currentInstance.get();
}
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(COM_PREFIX+"nolog");
static final boolean SORT_MEMBERS_DESCR_MAJOR
= Boolean.getBoolean(COM_PREFIX+"sort.members.descr.major");
static final boolean SORT_HANDLES_KIND_MAJOR
= Boolean.getBoolean(COM_PREFIX+"sort.handles.kind.major");
static final boolean SORT_INDY_BSS_MAJOR
= Boolean.getBoolean(COM_PREFIX+"sort.indy.bss.major");
static final boolean SORT_BSS_BSM_MAJOR
= Boolean.getBoolean(COM_PREFIX+"sort.bss.bsm.major");
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) {
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: " +
System.getProperty("java.vendor") +
", Version: " + Constants.MAX_PACKAGE_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 (JarEntry je : Collections.list(in.entries())) {
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()
try (JarOutputStream jout = new JarOutputStream(out)) {
copyJarFile(in, jout);
}
}
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()
try (JarOutputStream jout = new JarOutputStream(out)) {
copyJarFile(in, jout);
}
}
// Wrapper to prevent closing of client-supplied stream.
private static
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 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
}

View file

@ -1,48 +0,0 @@
# Properties which are known to Pack without further instruction,
# but are not part of the JSR 200 standard.
# They amount to default Pack properties.
# Additional standard properties are hardwired into the code,
# but may be overridden here, if necessary.
# The makefile for this directory must copy this file
# into the target class hierarchy so it will get into runtime image.
# JCOV attributes
pack.code.attribute.CoverageTable = NH[PHHII]
pack.code.attribute.CharacterRangeTable = NH[PHPOHIIH]
pack.class.attribute.SourceID = RUH
pack.class.attribute.CompilationID = RUH
pack.class.attribute.NestHost = RCH
pack.class.attribute.NestMembers = NH[RCH]
# Note: Zero-length ("marker") attributes do not need to be specified here.
# They are automatically defined to have an empty layout.
#pack.class.attribute.Deprecated =
#pack.field.attribute.Deprecated =
#pack.method.attribute.Deprecated =
## Example layouts for builtins. (Do not uncomment.)
#pack.class.attribute.Signature = RSH
#pack.field.attribute.Signature = RSH
#pack.method.attribute.Signature = RSH
# Signature = { signature:u2 }
#pack.class.attribute.SourceFile = RUH
# SourceFile = { utf8:u2 }
#pack.class.attribute.InnerClasses = NH[RCH RCNH RUNH FH]
# InnerClasses = { (N:u2)*{ class:u2 class?:u2 utf8?:u2 flags:u2 } }
#pack.method.attribute.Exceptions = NH[RCH]
# Exceptions = { (N:u2)*{ class:u2 } }
#pack.code.attribute.StackMap = \
# [NH[PH NH[(1)] NH[(1)]]] \
# [TB (7)[RCH] (8,9)[PH] ()[]]
#pack.code.attribute.LineNumberTable = NH[PH H]
#pack.code.attribute.LocalVariableTable = NH[PH OH RUH RSH H]
# Set this property if the classfile version number is bumped,
# as long as the format remains compatible with Pack200.
#com.sun.java.util.jar.pack.max.class.majver = 59
# Uncomment this line if the C-coded unpacker seems broken.
#com.sun.java.util.jar.pack.disable.native = true

View file

@ -1,101 +0,0 @@
/*
* Copyright (c) 2003, 2011, 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.
*/
/**
* This package provides methods to read files from a JAR file and to
* transform them to a more compact transfer format called Pack200.
* It also provides methods to receive the transmitted data and expand
* it into a JAR file equivalent to the original JAR file.
*
* <p>
* The {@code pack} methods may be used by application developers who
* wish to deploy large JARs on the web. The {@code unpack} methods
* may be used by deployment applications such as Java Web Start and
* Java Plugin.
*
* <p>
* In typical use, the packed output should be further compressed
* using a suitable tool such as gzip or
* {@code java.util.zip.GZIPOutputStream}. The resulting file (with
* a suffix ".pack.gz") should be hosted on a HTTP/1.1 compliant
* server, which will be capable of handling "Accept-Encoding", as
* specified by the HTTP 1.1 RFC2616 specification.
*
* <p>
* <b>NOTE:</b> It is recommended that the original ".jar" file be
* hosted in addition to the ".pack.gz" file, so that older client
* implementations will continue to work reliably. (On-demand
* compression by the server is not recommended.)
*
* <p>
* When a client application requests a ".jar" file (call it
* "Large.jar"), the client will transmit the headers
* "Content-Type=application/x-java-archive" as well as
* "Accept-Encoding=pack200-gzip". This indicates to the server that
* the client application desires an version of the file encoded with
* Pack200 and further compressed with gzip.
*
* <p>
* The server implementation will typically check for the existence of
* "Large.pack.gz". If that file is available, the server will
* transmit it with the headers "Content-Encoding=pack200-gzip" and
* "Content-Type=application/x-java-archive".
*
* <p>
* If the ".pack.gz" file, is not available, then the server will
* transmit the original ".jar" with "Content-Encoding=null" and
* "Content-Type=application/x-java-archive".
*
* <p>
* A MIME type of "application/x-java-pack200" may be specified by the
* client application to indicate a ".pack" file is required.
* However, this has limited capability, and is not recommended.
*
* <h2> Package Specification</h2>
* Network Transfer Format Specification :<a href="http://jcp.org/en/jsr/detail?id=200">
* http://jcp.org/en/jsr/detail?id=200</a>
*
* <h2> Related Documentation</h2>
* For overviews, tutorials, examples, guides, and tool documentation, please
* see:
* <ul>
*
* <li>
* Jar File Specification :<a href="http://java.sun.com/j2se/1.3/docs/guide/jar/jar.html">
* http://java.sun.com/j2se/1.3/docs/guide/jar/jar.html</a></li>
*
* <li>
* Class File Specification: Chapter 4 of
* <em>The Java&trade; Virtual Machine Specification</em>
*
* <li>
* Hypertext Transfer Protocol -- HTTP/1.1 : <a href="http://www.ietf.org/rfc/rfc2616.txt">
* http://www.ietf.org/rfc/rfc2616.txt
* </ul>
*
* <li>
* @since 1.5</li>
*/
package com.sun.java.util.jar.pack;

View file

@ -1,733 +0,0 @@
/*
* Copyright (c) 2003, 2019, 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 java.util.jar;
import java.util.SortedMap;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.File;
import java.io.IOException;
import sun.security.action.GetPropertyAction;
/**
* Transforms a JAR file to or from a packed stream in Pack200 format.
* Please refer to <a href="{@docRoot}/../specs/pack-spec.html">Network Transfer Format JSR 200 Specification</a>
* <p>
* Typically the packer engine is used by application developers
* to deploy or host JAR files on a website.
* The unpacker engine is used by deployment applications to
* transform the byte-stream back to JAR format.
* <p>
* Here is an example using packer and unpacker:
* <pre>{@code
* import java.util.jar.Pack200;
* import java.util.jar.Pack200.*;
* ...
* // Create the Packer object
* Packer packer = Pack200.newPacker();
*
* // Initialize the state by setting the desired properties
* Map p = packer.properties();
* // take more time choosing codings for better compression
* p.put(Packer.EFFORT, "7"); // default is "5"
* // use largest-possible archive segments (>10% better compression).
* p.put(Packer.SEGMENT_LIMIT, "-1");
* // reorder files for better compression.
* p.put(Packer.KEEP_FILE_ORDER, Packer.FALSE);
* // smear modification times to a single value.
* p.put(Packer.MODIFICATION_TIME, Packer.LATEST);
* // ignore all JAR deflation requests,
* // transmitting a single request to use "store" mode.
* p.put(Packer.DEFLATE_HINT, Packer.FALSE);
* // discard debug attributes
* p.put(Packer.CODE_ATTRIBUTE_PFX+"LineNumberTable", Packer.STRIP);
* // throw an error if an attribute is unrecognized
* p.put(Packer.UNKNOWN_ATTRIBUTE, Packer.ERROR);
* // pass one class file uncompressed:
* p.put(Packer.PASS_FILE_PFX+0, "mutants/Rogue.class");
* try {
* JarFile jarFile = new JarFile("/tmp/testref.jar");
* FileOutputStream fos = new FileOutputStream("/tmp/test.pack");
* // Call the packer
* packer.pack(jarFile, fos);
* jarFile.close();
* fos.close();
*
* File f = new File("/tmp/test.pack");
* FileOutputStream fostream = new FileOutputStream("/tmp/test.jar");
* JarOutputStream jostream = new JarOutputStream(fostream);
* Unpacker unpacker = Pack200.newUnpacker();
* // Call the unpacker
* unpacker.unpack(f, jostream);
* // Must explicitly close the output.
* jostream.close();
* } catch (IOException ioe) {
* ioe.printStackTrace();
* }
* }</pre>
* <p>
* A Pack200 file compressed with gzip can be hosted on HTTP/1.1 web servers.
* The deployment applications can use "Accept-Encoding=pack200-gzip". This
* indicates to the server that the client application desires a version of
* the file encoded with Pack200 and further compressed with gzip. Please
* refer to the Java Deployment Guide for techniques and details.
* <p>
* Unless otherwise noted, passing a {@code null} argument to a constructor or
* method in this class will cause a {@link NullPointerException} to be thrown.
*
* @author John Rose
* @author Kumar Srinivasan
* @since 1.5
* @deprecated This class is deprecated, and is planned for removal in a future
* release.
*/
@Deprecated(since="11", forRemoval=true)
public abstract class Pack200 {
private Pack200() {} //prevent instantiation
// Static methods of the Pack200 class.
/**
* Obtain new instance of a class that implements Packer.
* <ul>
* <li><p>If the system property {@systemProperty java.util.jar.Pack200.Packer}
* is defined, then the value is taken to be the fully-qualified name
* of a concrete implementation class, which must implement Packer.
* This class is loaded and instantiated. If this process fails
* then an unspecified error is thrown.</p></li>
*
* <li><p>If an implementation has not been specified with the system
* property, then the system-default implementation class is instantiated,
* and the result is returned.</p></li>
* </ul>
*
* <p>Note: The returned object is not guaranteed to operate
* correctly if multiple threads use it at the same time.
* A multi-threaded application should either allocate multiple
* packer engines, or else serialize use of one engine with a lock.
*
* @return A newly allocated Packer engine.
*/
public static synchronized Packer newPacker() {
return (Packer) newInstance(PACK_PROVIDER);
}
/**
* Obtain new instance of a class that implements Unpacker.
* <ul>
* <li><p>If the system property {@systemProperty java.util.jar.Pack200.Unpacker}
* is defined, then the value is taken to be the fully-qualified
* name of a concrete implementation class, which must implement Unpacker.
* The class is loaded and instantiated. If this process fails
* then an unspecified error is thrown.</p></li>
*
* <li><p>If an implementation has not been specified with the
* system property, then the system-default implementation class
* is instantiated, and the result is returned.</p></li>
* </ul>
*
* <p>Note: The returned object is not guaranteed to operate
* correctly if multiple threads use it at the same time.
* A multi-threaded application should either allocate multiple
* unpacker engines, or else serialize use of one engine with a lock.
*
* @return A newly allocated Unpacker engine.
*/
public static Unpacker newUnpacker() {
return (Unpacker) newInstance(UNPACK_PROVIDER);
}
// Interfaces
/**
* The packer engine applies various transformations to the input JAR file,
* making the pack stream highly compressible by a compressor such as
* gzip or zip. An instance of the engine can be obtained
* using {@link #newPacker}.
* The high degree of compression is achieved
* by using a number of techniques described in the JSR 200 specification.
* Some of the techniques are sorting, re-ordering and co-location of the
* constant pool.
* <p>
* The pack engine is initialized to an initial state as described
* by their properties below.
* The initial state can be manipulated by getting the
* engine properties (using {@link #properties}) and storing
* the modified properties on the map.
* The resource files will be passed through with no changes at all.
* The class files will not contain identical bytes, since the unpacker
* is free to change minor class file features such as constant pool order.
* However, the class files will be semantically identical,
* as specified in
* <cite>The Java&trade; Virtual Machine Specification</cite>.
* <p>
* By default, the packer does not change the order of JAR elements.
* Also, the modification time and deflation hint of each
* JAR element is passed unchanged.
* (Any other ZIP-archive information, such as extra attributes
* giving Unix file permissions, are lost.)
* <p>
* Note that packing and unpacking a JAR will in general alter the
* bytewise contents of classfiles in the JAR. This means that packing
* and unpacking will in general invalidate any digital signatures
* which rely on bytewise images of JAR elements. In order both to sign
* and to pack a JAR, you must first pack and unpack the JAR to
* "normalize" it, then compute signatures on the unpacked JAR elements,
* and finally repack the signed JAR.
* Both packing steps should
* use precisely the same options, and the segment limit may also
* need to be set to "-1", to prevent accidental variation of segment
* boundaries as class file sizes change slightly.
* <p>
* (Here's why this works: Any reordering the packer does
* of any classfile structures is idempotent, so the second packing
* does not change the orderings produced by the first packing.
* Also, the unpacker is guaranteed by the JSR 200 specification
* to produce a specific bytewise image for any given transmission
* ordering of archive elements.)
* <p>
* In order to maintain backward compatibility, the pack file's version is
* set to accommodate the class files present in the input JAR file. In
* other words, the pack file version will be the latest, if the class files
* are the latest and conversely the pack file version will be the oldest
* if the class file versions are also the oldest. For intermediate class
* file versions the corresponding pack file version will be used.
* For example:
* If the input JAR-files are solely comprised of 1.5 (or lesser)
* class files, a 1.5 compatible pack file is produced. This will also be
* the case for archives that have no class files.
* If the input JAR-files contains a 1.6 class file, then the pack file
* version will be set to 1.6.
* <p>
* Note: Unless otherwise noted, passing a {@code null} argument to a
* constructor or method in this class will cause a {@link NullPointerException}
* to be thrown.
*
* @since 1.5
* @deprecated This interface is deprecated, and is planned for removal in a
* future release.
*/
@Deprecated(since="11", forRemoval=true)
public interface Packer {
/**
* This property is a numeral giving the estimated target size N
* (in bytes) of each archive segment.
* If a single input file requires more than N bytes,
* it will be given its own archive segment.
* <p>
* As a special case, a value of -1 will produce a single large
* segment with all input files, while a value of 0 will
* produce one segment for each class.
* Larger archive segments result in less fragmentation and
* better compression, but processing them requires more memory.
* <p>
* The size of each segment is estimated by counting the size of each
* input file to be transmitted in the segment, along with the size
* of its name and other transmitted properties.
* <p>
* The default is -1, which means the packer will always create a single
* segment output file. In cases where extremely large output files are
* generated, users are strongly encouraged to use segmenting or break
* up the input file into smaller JARs.
* <p>
* A 10Mb JAR packed without this limit will
* typically pack about 10% smaller, but the packer may require
* a larger Java heap (about ten times the segment limit).
*/
String SEGMENT_LIMIT = "pack.segment.limit";
/**
* If this property is set to {@link #TRUE}, the packer will transmit
* all elements in their original order within the source archive.
* <p>
* If it is set to {@link #FALSE}, the packer may reorder elements,
* and also remove JAR directory entries, which carry no useful
* information for Java applications.
* (Typically this enables better compression.)
* <p>
* The default is {@link #TRUE}, which preserves the input information,
* but may cause the transmitted archive to be larger than necessary.
*/
String KEEP_FILE_ORDER = "pack.keep.file.order";
/**
* If this property is set to a single decimal digit, the packer will
* use the indicated amount of effort in compressing the archive.
* Level 1 may produce somewhat larger size and faster compression speed,
* while level 9 will take much longer but may produce better compression.
* <p>
* The special value 0 instructs the packer to copy through the
* original JAR file directly, with no compression. The JSR 200
* standard requires any unpacker to understand this special case
* as a pass-through of the entire archive.
* <p>
* The default is 5, investing a modest amount of time to
* produce reasonable compression.
*/
String EFFORT = "pack.effort";
/**
* If this property is set to {@link #TRUE} or {@link #FALSE}, the packer
* will set the deflation hint accordingly in the output archive, and
* will not transmit the individual deflation hints of archive elements.
* <p>
* If this property is set to the special string {@link #KEEP}, the packer
* will attempt to determine an independent deflation hint for each
* available element of the input archive, and transmit this hint separately.
* <p>
* The default is {@link #KEEP}, which preserves the input information,
* but may cause the transmitted archive to be larger than necessary.
* <p>
* It is up to the unpacker implementation
* to take action upon the hint to suitably compress the elements of
* the resulting unpacked jar.
* <p>
* The deflation hint of a ZIP or JAR element indicates
* whether the element was deflated or stored directly.
*/
String DEFLATE_HINT = "pack.deflate.hint";
/**
* If this property is set to the special string {@link #LATEST},
* the packer will attempt to determine the latest modification time,
* among all the available entries in the original archive or the latest
* modification time of all the available entries in each segment.
* This single value will be transmitted as part of the segment and applied
* to all the entries in each segment, {@link #SEGMENT_LIMIT}.
* <p>
* This can marginally decrease the transmitted size of the
* archive, at the expense of setting all installed files to a single
* date.
* <p>
* If this property is set to the special string {@link #KEEP},
* the packer transmits a separate modification time for each input
* element.
* <p>
* The default is {@link #KEEP}, which preserves the input information,
* but may cause the transmitted archive to be larger than necessary.
* <p>
* It is up to the unpacker implementation to take action to suitably
* set the modification time of each element of its output file.
* @see #SEGMENT_LIMIT
*/
String MODIFICATION_TIME = "pack.modification.time";
/**
* Indicates that a file should be passed through bytewise, with no
* compression. Multiple files may be specified by specifying
* additional properties with distinct strings appended, to
* make a family of properties with the common prefix.
* <p>
* There is no pathname transformation, except
* that the system file separator is replaced by the JAR file
* separator '/'.
* <p>
* The resulting file names must match exactly as strings with their
* occurrences in the JAR file.
* <p>
* If a property value is a directory name, all files under that
* directory will be passed also.
* <p>
* Examples:
* <pre>{@code
* Map p = packer.properties();
* p.put(PASS_FILE_PFX+0, "mutants/Rogue.class");
* p.put(PASS_FILE_PFX+1, "mutants/Wolverine.class");
* p.put(PASS_FILE_PFX+2, "mutants/Storm.class");
* # Pass all files in an entire directory hierarchy:
* p.put(PASS_FILE_PFX+3, "police/");
* }</pre>
*/
String PASS_FILE_PFX = "pack.pass.file.";
/// Attribute control.
/**
* Indicates the action to take when a class-file containing an unknown
* attribute is encountered. Possible values are the strings {@link #ERROR},
* {@link #STRIP}, and {@link #PASS}.
* <p>
* The string {@link #ERROR} means that the pack operation
* as a whole will fail, with an exception of type {@code IOException}.
* The string
* {@link #STRIP} means that the attribute will be dropped.
* The string
* {@link #PASS} means that the whole class-file will be passed through
* (as if it were a resource file) without compression, with a suitable warning.
* This is the default value for this property.
* <p>
* Examples:
* <pre>{@code
* Map p = pack200.getProperties();
* p.put(UNKNOWN_ATTRIBUTE, ERROR);
* p.put(UNKNOWN_ATTRIBUTE, STRIP);
* p.put(UNKNOWN_ATTRIBUTE, PASS);
* }</pre>
*/
String UNKNOWN_ATTRIBUTE = "pack.unknown.attribute";
/**
* When concatenated with a class attribute name,
* indicates the format of that attribute,
* using the layout language specified in the JSR 200 specification.
* <p>
* For example, the effect of this option is built in:
* {@code pack.class.attribute.SourceFile=RUH}.
* <p>
* The special strings {@link #ERROR}, {@link #STRIP}, and {@link #PASS} are
* also allowed, with the same meaning as {@link #UNKNOWN_ATTRIBUTE}.
* This provides a way for users to request that specific attributes be
* refused, stripped, or passed bitwise (with no class compression).
* <p>
* Code like this might be used to support attributes for JCOV:
* <pre>{@code
* Map p = packer.properties();
* p.put(CODE_ATTRIBUTE_PFX+"CoverageTable", "NH[PHHII]");
* p.put(CODE_ATTRIBUTE_PFX+"CharacterRangeTable", "NH[PHPOHIIH]");
* p.put(CLASS_ATTRIBUTE_PFX+"SourceID", "RUH");
* p.put(CLASS_ATTRIBUTE_PFX+"CompilationID", "RUH");
* }</pre>
* <p>
* Code like this might be used to strip debugging attributes:
* <pre>{@code
* Map p = packer.properties();
* p.put(CODE_ATTRIBUTE_PFX+"LineNumberTable", STRIP);
* p.put(CODE_ATTRIBUTE_PFX+"LocalVariableTable", STRIP);
* p.put(CLASS_ATTRIBUTE_PFX+"SourceFile", STRIP);
* }</pre>
*/
String CLASS_ATTRIBUTE_PFX = "pack.class.attribute.";
/**
* When concatenated with a field attribute name,
* indicates the format of that attribute.
* For example, the effect of this option is built in:
* {@code pack.field.attribute.Deprecated=}.
* The special strings {@link #ERROR}, {@link #STRIP}, and
* {@link #PASS} are also allowed.
* @see #CLASS_ATTRIBUTE_PFX
*/
String FIELD_ATTRIBUTE_PFX = "pack.field.attribute.";
/**
* When concatenated with a method attribute name,
* indicates the format of that attribute.
* For example, the effect of this option is built in:
* {@code pack.method.attribute.Exceptions=NH[RCH]}.
* The special strings {@link #ERROR}, {@link #STRIP}, and {@link #PASS}
* are also allowed.
* @see #CLASS_ATTRIBUTE_PFX
*/
String METHOD_ATTRIBUTE_PFX = "pack.method.attribute.";
/**
* When concatenated with a code attribute name,
* indicates the format of that attribute.
* For example, the effect of this option is built in:
* {@code pack.code.attribute.LocalVariableTable=NH[PHOHRUHRSHH]}.
* The special strings {@link #ERROR}, {@link #STRIP}, and {@link #PASS}
* are also allowed.
* @see #CLASS_ATTRIBUTE_PFX
*/
String CODE_ATTRIBUTE_PFX = "pack.code.attribute.";
/**
* The packer's progress as a percentage, as periodically
* updated by the packer.
* Values of 0 - 100 are normal, and -1 indicates a stall.
* Progress can be monitored by polling the value of this
* property.
* <p>
* At a minimum, the packer must set progress to 0
* at the beginning of a packing operation, and to 100
* at the end.
*/
String PROGRESS = "pack.progress";
/** The string "keep", a possible value for certain properties.
* @see #DEFLATE_HINT
* @see #MODIFICATION_TIME
*/
String KEEP = "keep";
/** The string "pass", a possible value for certain properties.
* @see #UNKNOWN_ATTRIBUTE
* @see #CLASS_ATTRIBUTE_PFX
* @see #FIELD_ATTRIBUTE_PFX
* @see #METHOD_ATTRIBUTE_PFX
* @see #CODE_ATTRIBUTE_PFX
*/
String PASS = "pass";
/** The string "strip", a possible value for certain properties.
* @see #UNKNOWN_ATTRIBUTE
* @see #CLASS_ATTRIBUTE_PFX
* @see #FIELD_ATTRIBUTE_PFX
* @see #METHOD_ATTRIBUTE_PFX
* @see #CODE_ATTRIBUTE_PFX
*/
String STRIP = "strip";
/** The string "error", a possible value for certain properties.
* @see #UNKNOWN_ATTRIBUTE
* @see #CLASS_ATTRIBUTE_PFX
* @see #FIELD_ATTRIBUTE_PFX
* @see #METHOD_ATTRIBUTE_PFX
* @see #CODE_ATTRIBUTE_PFX
*/
String ERROR = "error";
/** The string "true", a possible value for certain properties.
* @see #KEEP_FILE_ORDER
* @see #DEFLATE_HINT
*/
String TRUE = "true";
/** The string "false", a possible value for certain properties.
* @see #KEEP_FILE_ORDER
* @see #DEFLATE_HINT
*/
String FALSE = "false";
/** The string "latest", a possible value for certain properties.
* @see #MODIFICATION_TIME
*/
String LATEST = "latest";
/**
* Get the set of this engine's properties.
* This set is a "live view", so that changing its
* contents immediately affects the Packer engine, and
* changes from the engine (such as progress indications)
* are immediately visible in the map.
*
* <p>The property map may contain pre-defined implementation
* specific and default properties. Users are encouraged to
* read the information and fully understand the implications,
* before modifying pre-existing properties.
* <p>
* Implementation specific properties are prefixed with a
* package name associated with the implementor, beginning
* with {@code com.} or a similar prefix.
* All property names beginning with {@code pack.} and
* {@code unpack.} are reserved for use by this API.
* <p>
* Unknown properties may be ignored or rejected with an
* unspecified error, and invalid entries may cause an
* unspecified error to be thrown.
*
* <p>
* The returned map implements all optional {@link SortedMap} operations
* @return A sorted association of property key strings to property
* values.
*/
SortedMap<String,String> properties();
/**
* Takes a JarFile and converts it into a Pack200 archive.
* <p>
* Closes its input but not its output. (Pack200 archives are appendable.)
* @param in a JarFile
* @param out an OutputStream
* @throws IOException if an error is encountered.
*/
void pack(JarFile in, OutputStream out) throws IOException ;
/**
* Takes a JarInputStream and converts it into a Pack200 archive.
* <p>
* Closes its input but not its output. (Pack200 archives are appendable.)
* <p>
* The modification time and deflation hint attributes are not available,
* for the JAR manifest file and its containing directory.
*
* @see #MODIFICATION_TIME
* @see #DEFLATE_HINT
* @param in a JarInputStream
* @param out an OutputStream
* @throws IOException if an error is encountered.
*/
void pack(JarInputStream in, OutputStream out) throws IOException ;
}
/**
* The unpacker engine converts the packed stream to a JAR file.
* An instance of the engine can be obtained
* using {@link #newUnpacker}.
* <p>
* Every JAR file produced by this engine will include the string
* "{@code PACK200}" as a zip file comment.
* This allows a deployer to detect if a JAR archive was packed and unpacked.
* <p>
* Note: Unless otherwise noted, passing a {@code null} argument to a
* constructor or method in this class will cause a {@link NullPointerException}
* to be thrown.
* <p>
* This version of the unpacker is compatible with all previous versions.
* @since 1.5
* @deprecated This interface is deprecated, and is planned for removal in a
* future release.
*/
@Deprecated(since="11", forRemoval=true)
public interface Unpacker {
/** The string "keep", a possible value for certain properties.
* @see #DEFLATE_HINT
*/
String KEEP = "keep";
/** The string "true", a possible value for certain properties.
* @see #DEFLATE_HINT
*/
String TRUE = "true";
/** The string "false", a possible value for certain properties.
* @see #DEFLATE_HINT
*/
String FALSE = "false";
/**
* Property indicating that the unpacker should
* ignore all transmitted values for DEFLATE_HINT,
* replacing them by the given value, {@link #TRUE} or {@link #FALSE}.
* The default value is the special string {@link #KEEP},
* which asks the unpacker to preserve all transmitted
* deflation hints.
*/
String DEFLATE_HINT = "unpack.deflate.hint";
/**
* The unpacker's progress as a percentage, as periodically
* updated by the unpacker.
* Values of 0 - 100 are normal, and -1 indicates a stall.
* Progress can be monitored by polling the value of this
* property.
* <p>
* At a minimum, the unpacker must set progress to 0
* at the beginning of an unpacking operation, and to 100
* at the end.
*/
String PROGRESS = "unpack.progress";
/**
* Get the set of this engine's properties. This set is
* a "live view", so that changing its
* contents immediately affects the Unpacker engine, and
* changes from the engine (such as progress indications)
* are immediately visible in the map.
*
* <p>The property map may contain pre-defined implementation
* specific and default properties. Users are encouraged to
* read the information and fully understand the implications,
* before modifying pre-existing properties.
* <p>
* Implementation specific properties are prefixed with a
* package name associated with the implementor, beginning
* with {@code com.} or a similar prefix.
* All property names beginning with {@code pack.} and
* {@code unpack.} are reserved for use by this API.
* <p>
* Unknown properties may be ignored or rejected with an
* unspecified error, and invalid entries may cause an
* unspecified error to be thrown.
*
* @return A sorted association of option key strings to option values.
*/
SortedMap<String,String> properties();
/**
* Read a Pack200 archive, and write the encoded JAR to
* a JarOutputStream.
* The entire contents of the input stream will be read.
* It may be more efficient to read the Pack200 archive
* to a file and pass the File object, using the alternate
* method described below.
* <p>
* Closes its input but not its output. (The output can accumulate more elements.)
* @param in an InputStream.
* @param out a JarOutputStream.
* @throws IOException if an error is encountered.
*/
void unpack(InputStream in, JarOutputStream out) throws IOException;
/**
* Read a Pack200 archive, and write the encoded JAR to
* a JarOutputStream.
* <p>
* Does not close its output. (The output can accumulate more elements.)
* @param in a File.
* @param out a JarOutputStream.
* @throws IOException if an error is encountered.
*/
void unpack(File in, JarOutputStream out) throws IOException;
}
// Private stuff....
private static final String PACK_PROVIDER = "java.util.jar.Pack200.Packer";
private static final String UNPACK_PROVIDER = "java.util.jar.Pack200.Unpacker";
private static Class<?> packerImpl;
private static Class<?> unpackerImpl;
private static synchronized Object newInstance(String prop) {
String implName = "(unknown)";
try {
Class<?> impl = (PACK_PROVIDER.equals(prop))? packerImpl: unpackerImpl;
if (impl == null) {
// The first time, we must decide which class to use.
implName = GetPropertyAction.privilegedGetProperty(prop,"");
if (implName != null && !implName.isEmpty())
impl = Class.forName(implName);
else if (PACK_PROVIDER.equals(prop))
impl = com.sun.java.util.jar.pack.PackerImpl.class;
else
impl = com.sun.java.util.jar.pack.UnpackerImpl.class;
}
// We have a class. Now instantiate it.
@SuppressWarnings("deprecation")
Object result = impl.newInstance();
return result;
} catch (ClassNotFoundException e) {
throw new Error("Class not found: " + implName +
":\ncheck property " + prop +
" in your properties file.", e);
} catch (InstantiationException e) {
throw new Error("Could not instantiate: " + implName +
":\ncheck property " + prop +
" in your properties file.", e);
} catch (IllegalAccessException e) {
throw new Error("Cannot access class: " + implName +
":\ncheck property " + prop +
" in your properties file.", e);
}
}
}

View file

@ -111,12 +111,6 @@ class GNUStyleOptions {
jartool.vflag = true; jartool.vflag = true;
} }
}, },
new Option(false, OptionType.CREATE, "--normalize", "-n") {
void process(Main jartool, String opt, String arg) {
jartool.nflag = true;
}
boolean isExtra() { return true; }
},
new Option(true, OptionType.CREATE_UPDATE, "--main-class", "-e") { new Option(true, OptionType.CREATE_UPDATE, "--main-class", "-e") {
void process(Main jartool, String opt, String arg) { void process(Main jartool, String opt, String arg) {
jartool.ename = arg; jartool.ename = arg;

View file

@ -150,7 +150,7 @@ public class Main {
* pflag: preserve/don't strip leading slash and .. component from file name * pflag: preserve/don't strip leading slash and .. component from file name
* dflag: print module descriptor * dflag: print module descriptor
*/ */
boolean cflag, uflag, xflag, tflag, vflag, flag0, Mflag, iflag, nflag, pflag, dflag; boolean cflag, uflag, xflag, tflag, vflag, flag0, Mflag, iflag, pflag, dflag;
boolean suppressDeprecateMsg = false; boolean suppressDeprecateMsg = false;
@ -318,34 +318,6 @@ public class Main {
try (OutputStream out = new FileOutputStream(tmpFile)) { try (OutputStream out = new FileOutputStream(tmpFile)) {
create(new BufferedOutputStream(out, 4096), manifest); create(new BufferedOutputStream(out, 4096), manifest);
} }
if (nflag) {
if (!suppressDeprecateMsg) {
warn(formatMsg("warn.flag.is.deprecated", "-n"));
}
File packFile = createTemporaryFile(tmpbase, ".pack");
try {
java.util.jar.Pack200.Packer packer = java.util.jar.Pack200.newPacker();
Map<String, String> p = packer.properties();
p.put(java.util.jar.Pack200.Packer.EFFORT, "1"); // Minimal effort to conserve CPU
try (JarFile jarFile = new JarFile(tmpFile.getCanonicalPath());
OutputStream pack = new FileOutputStream(packFile))
{
packer.pack(jarFile, pack);
}
if (tmpFile.exists()) {
tmpFile.delete();
}
tmpFile = createTemporaryFile(tmpbase, ".jar");
try (OutputStream out = new FileOutputStream(tmpFile);
JarOutputStream jos = new JarOutputStream(out))
{
java.util.jar.Pack200.Unpacker unpacker = java.util.jar.Pack200.newUnpacker();
unpacker.unpack(packFile, jos);
}
} finally {
Files.deleteIfExists(packFile.toPath());
}
}
validateAndClose(tmpFile); validateAndClose(tmpFile);
} else if (uflag) { } else if (uflag) {
File inputFile = null; File inputFile = null;
@ -587,9 +559,6 @@ public class Main {
rootjar = args[count++]; rootjar = args[count++];
iflag = true; iflag = true;
break; break;
case 'n':
nflag = true;
break;
case 'e': case 'e':
ename = args[count++]; ename = args[count++];
break; break;

View file

@ -172,8 +172,6 @@ Options:\n\
\ \ -v generate verbose output on standard output\n\ \ \ -v generate verbose output on standard output\n\
\ \ -f specify archive file name\n\ \ \ -f specify archive file name\n\
\ \ -m include manifest information from specified manifest file\n\ \ \ -m include manifest information from specified manifest file\n\
\ \ -n perform Pack200 normalization after creating a new archive,\n\
\ \ this option is deprecated, and is planned for removal in a future JDK release\n\
\ \ -e specify application entry point for stand-alone application \n\ \ \ -e specify application entry point for stand-alone application \n\
\ \ bundled into an executable jar file\n\ \ \ bundled into an executable jar file\n\
\ \ -0 store only; use no ZIP compression\n\ \ \ -0 store only; use no ZIP compression\n\

View file

@ -1,42 +0,0 @@
/*
* Copyright (c) 2014, 2019, 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.
*/
/**
* Defines tools for transforming a JAR file into a compressed pack200 file
* and transforming a packed file into a JAR file, including the
* <em>{@index pack200 pack200 tool}</em> and
* <em>{@index unpack200 unpack200 tool}</em> tools.
*
* @toolGuide pack200
* @toolGuide unpack200
*
* @moduleGraph
* @deprecated This module is deprecated, and is planned for removal in a
* future release.
* @since 9
*/
@Deprecated(since="11", forRemoval=true)
module jdk.pack {
}

View file

@ -1,357 +0,0 @@
.\" Copyright (c) 1994, 2019, 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.
.\"
.\" 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.
.\"
.\" Automatically generated by Pandoc 2.3.1
.\"
.TH "PACK200" "1" "2018" "JDK 13" "JDK Commands"
.hy
.SH NAME
.PP
pack200 \- transform a Java Archive (JAR) file into a compressed pack200
file with the Java gzip compressor
.SH SYNOPSIS
.PP
\f[CB]pack200\f[R] [\f[I]\-opt...\f[R] | \f[I]\-\-option=value\f[R]]
\f[I]x.pack[.gz]\f[R] \f[I]JAR\-file\f[R]
.TP
.B \f[I]\-opt...\f[R] | \f[I]\-\-option=value\f[R]
Options can be in any order.
The last option on the command line or in a properties file supersedes
all previously specified options.
See \f[B]Options for the pack200 Command\f[R].
.RS
.RE
.TP
.B \f[I]x.pack[.gz]\f[R]
Name of the output file.
.RS
.RE
.TP
.B \f[I]JAR\-file\f[R]
Name of the input file.
.RS
.RE
.SH DESCRIPTION
.PP
The \f[CB]pack200\f[R] command is a Java application that transforms a JAR
file into a compressed \f[CB]pack200\f[R] file with the Java gzip
compressor.
This command packages a JAR file into a compressed \f[CB]pack200\f[R] file
for web deployment.
The \f[CB]pack200\f[R] files are highly compressed files that can be
directly deployed to save bandwidth and reduce download time.
.PP
Typical usage is shown in the following example, where
\f[CB]myarchive.pack.gz\f[R] is produced with the default \f[CB]pack200\f[R]
command settings:
.RS
.PP
\f[CB]pack200\ myarchive.pack.gz\ myarchive.jar\f[R]
.RE
.PP
\f[B]Note:\f[R]
.PP
This command shouldn\[aq]t be confused with \f[CB]pack\f[R].
The \f[CB]pack\f[R] and \f[CB]pack200\f[R] commands are separate products.
The Java SE API Specification provided with the JDK is the superseding
authority, when there are discrepancies.
.SH EXIT STATUS
.PP
The following exit values are returned: 0 for successful completion and
a number greater than 0 when an error occurs.
.SH OPTIONS FOR THE PACK200 COMMAND
.PP
The \f[CB]pack200\f[R] command has several options to fine\-tune and set
the compression engine.
The typical usage is shown in the following example, where
\f[CB]myarchive.pack.gz\f[R] is produced with the default \f[CB]pack200\f[R]
command settings:
.RS
.PP
\f[CB]pack200\ myarchive.pack.gz\ myarchive.jar\f[R]
.RE
.TP
.B \f[CB]\-r\f[R] or \f[CB]\-\-repack\f[R]
Produces a JAR file by packing and unpacking a JAR file.
The resulting file can be used as an input to the \f[CB]jarsigner\f[R]
tool.
The following example packs and unpacks the myarchive.jar file:
.RS
.RS
.PP
\f[CB]pack200\ \-\-repack\ myarchive\-packer.jar\ myarchive.jar\f[R]
.RE
.RS
.PP
\f[CB]pack200\ \-\-repack\ myarchive.jar\f[R]
.RE
.RE
.TP
.B \f[CB]\-g\f[R] or\f[CB]\-\-no\-gzip\f[R]
Produces a \f[CB]pack200\f[R] file.
With this option, a suitable compressor must be used, and the target
system must use a corresponding decompresser.
.RS
.RS
.PP
\f[CB]pack200\ \-\-no\-gzip\ myarchive.pack\ myarchive.jar\f[R]
.RE
.RE
.TP
.B \f[CB]\-\-gzip\f[R]
(Default) Post\-compresses the pack output with \f[CB]gzip\f[R].
.RS
.RE
.TP
.B \f[CB]\-G\f[R] or \f[CB]\-\-strip\-debug\f[R]
Strips debugging attributes from the output.
These include \f[CB]SourceFile\f[R], \f[CB]LineNumberTable\f[R],
\f[CB]LocalVariableTable\f[R] and \f[CB]LocalVariableTypeTable\f[R].
Removing these attributes reduces the size of both downloads and
installations, also reduces the usefulness of debuggers.
.RS
.RE
.TP
.B \f[CB]\-\-keep\-file\-order\f[R]
Preserves the order of files in the input file.
This is the default behavior.
.RS
.RE
.TP
.B \f[CB]\-O\f[R] or\f[CB]\-\-no\-keep\-file\-order\f[R]
Reorders and transmits all elements.
The packer can also remove JAR directory names to reduce the download
size.
However, certain JAR file optimizations, such as indexing, might not
work correctly.
.RS
.RE
.TP
.B \f[CB]\-S\f[R]\f[I]N\f[R] or \f[CB]\-\-segment\-limit=\f[R]\f[I]N\f[R]
The value is the estimated target size \f[I]N\f[R] (in bytes) of each
archive segment.
If a single input file requires more than \f[I]N\f[R] bytes, then its own
archive segment is provided.
As a special case, a value of \f[CB]\-1\f[R] produces a single large
segment with all input files, while a value of 0 produces one segment
for each class.
Larger archive segments result in less fragmentation and better
compression, but processing them requires more memory.
.RS
.PP
The size of each segment is estimated by counting the size of each input
file to be transmitted in the segment with the size of its name and
other transmitted properties.
.PP
The default is \f[CB]\-1\f[R], which means that the packer creates a
single segment output file.
In cases where extremely large output files are generated, users are
strongly encouraged to use segmenting or break up the input file into
smaller JAR file.
.PP
A 10 MB JAR packed without this limit typically packs about 10 percent
smaller, but the packer might require a larger Java heap (about 10 times
the segment limit).
.RE
.TP
.B \f[CB]\-E\f[R]\f[I]value\f[R] or \f[CB]\-\-effort=\f[R]\f[I]value\f[R]
If the value is set to a single decimal digit, then the packer uses the
indicated amount of effort in compressing the archive.
Level 1 might produce somewhat larger size and faster compression speed,
while level 9 takes much longer, but can produce better compression.
The special value 0 instructs the \f[CB]pack200\f[R] command to copy
through the original JAR file directly with no compression.
The JSR 200 standard requires any unpacker to understand this special
case as a pass\-through of the entire archive.
.RS
.PP
The default is 5, to invest a modest amount of time to produce
reasonable compression.
.RE
.TP
.B \f[CB]\-H\f[R]\f[I]value\f[R] or \f[CB]\-\-deflate\-hint=\f[R]\f[I]value\f[R]
Overrides the default, which preserves the input information, but can
cause the transmitted archive to be larger.
The possible values are: \f[CB]true\f[R], \f[CB]false\f[R], or
\f[CB]keep\f[R].
.RS
.PP
If the \f[CB]value\f[R] is \f[CB]true\f[R] or false, then the
\f[CB]packer200\f[R] command sets the deflation hint accordingly in the
output archive and doesn\[aq]t transmit the individual deflation hints
of archive elements.
.PP
The \f[CB]keep\f[R] value preserves deflation hints observed in the input
JAR.
This is the default.
.RE
.TP
.B \f[CB]\-m\f[R]\f[I]value\f[R] or \f[CB]\-\-modification\-time=\f[R]\f[I]value\f[R]
The possible values are \f[CB]latest\f[R] and \f[CB]keep\f[R].
.RS
.PP
If the value is \f[CB]latest\f[R], then the packer attempts to determine
the latest modification time, among all the available entries in the
original archive, or the latest modification time of all the available
entries in that segment.
This single value is transmitted as part of the segment and applied to
all the entries in each segment.
This can marginally decrease the transmitted size of the archive at the
expense of setting all installed files to a single date.
.PP
If the value is \f[CB]keep\f[R], then modification times observed in the
input JAR are preserved.
This is the default.
.RE
.TP
.B \f[CB]\-P\f[R]\f[I]file\f[R] or \f[CB]\-\-pass\-file=\f[R]\f[I]file\f[R]
Indicates that a file should be passed through bytewise with no
compression.
By repeating the option, multiple files can be specified.
There is no path name transformation, except that the system file
separator is replaced by the JAR file separator forward slash (/).
The resulting file names must match exactly as strings with their
occurrences in the JAR file.
If \f[I]file\f[R] is a directory name, then all files under that
directory are passed.
.RS
.RE
.TP
.B \f[CB]\-U\f[R]\f[I]action\f[R] or \f[CB]\-\-unknown\-attribute=\f[R]\f[I]action\f[R]
Overrides the default behavior, which means that the class file that
contains the unknown attribute is passed through with the specified
\f[I]action\f[R].
The possible values for actions are \f[CB]error\f[R], \f[CB]strip\f[R], or
\f[CB]pass\f[R].
.RS
.PP
If the value is \f[CB]error\f[R], then the entire \f[CB]pack200\f[R] command
operation fails with a suitable explanation.
.PP
If the value is \f[CB]strip\f[R], then the attribute is dropped.
Removing the required Java Virtual Machine (JVM) attributes can cause
class loader failures.
.PP
If the value is \f[CB]pass\f[R], then the entire class is transmitted as
though it is a resource.
.RE
.TP
.B \f[CB]\-C\f[R]\f[I]attribute\-name\f[R]\f[CB]=\f[R]\f[I]layout\f[R] or \f[CB]\-\-class\-attribute=\f[R]\f[I]attribute\-name\f[R]\f[CB]=\f[R]\f[I]layout\f[R]
(user\-defined attribute) See the description for
\f[CB]\-D\f[R]\f[I]attribute\-name\f[R]\f[CB]=\f[R]\f[I]layout\f[R].
.RS
.RE
.TP
.B \f[CB]\-F\f[R]\f[I]attribute\-name\f[R]\f[CB]=\f[R]\f[I]layout\f[R] or \f[CB]\-\-field\-attribute=\f[R]\f[I]attribute\-name\f[R]\f[CB]=\f[R]\f[I]layout\f[R]
(user\-defined attribute) See the description for
\f[CB]\-D\f[R]\f[I]attribute\-name\f[R]\f[CB]=\f[R]\f[I]layout\f[R].
.RS
.RE
.TP
.B \f[CB]\-M\f[R]\f[I]attribute\-name\f[R]\f[CB]=\f[R]\f[I]layout\f[R] or \f[CB]\-\-method\-attribute=\f[R]\f[I]attribute\-name\f[R]\f[CB]=\f[R]\f[I]layout\f[R]
(user\-defined attribute) See the description for
\f[CB]\-D\f[R]\f[I]attribute\-name\f[R]\f[CB]=\f[R]\f[I]layout\f[R].
.RS
.RE
.TP
.B \f[CB]\-D\f[R]\f[I]attribute\-name\f[R]\f[CB]=\f[R]\f[I]layout\f[R] or \f[CB]\-\-code\-attribute=\f[R]\f[I]attribute\-name\f[R]\f[CB]=\f[R]\f[I]layout\f[R]
(user\-defined attribute) The attribute layout can be specified for a
class entity, such as \f[CB]class\-attribute\f[R],
\f[CB]field\-attribute\f[R], \f[CB]method\-attribute\f[R], and
\f[CB]code\-attribute\f[R].
The \f[I]attribute\-name\f[R] is the name of the attribute for which the
layout or action is being defined.
The possible values for \f[I]action\f[R] are
\f[I]some\-layout\-string\f[R], \f[CB]error\f[R], \f[CB]strip\f[R],
\f[CB]pass\f[R].
.RS
.PP
\f[I]some\-layout\-string\f[R]: The layout language is defined in the JSR
200 specification, for example:
\f[CB]\-\-class\-attribute=SourceFile=RUH\f[R].
.PP
If the value is \f[CB]error\f[R], then the \f[CB]pack200\f[R] operation
fails with an explanation.
.PP
If the value is \f[CB]strip\f[R], then the attribute is removed from the
output.
Removing JVM\-required attributes can cause class loader failures.
For example, \f[CB]\-\-class\-attribute=CompilationID=pass\f[R] causes the
class file that contains this attribute to be passed through without
further action by the packer.
.PP
If the value is \f[CB]pass\f[R], then the entire class is transmitted as
though it\[aq]s a resource.
.RE
.TP
.B \f[CB]\-f\f[R]\f[I]pack.properties\f[R] or \f[CB]\-\-config\-file=\f[R]\f[I]pack.properties\f[R]
Indicates a configuration file, containing Java properties to initialize
the packer, can be specified on the command line.
.RS
.IP
.nf
\f[CB]
pack200\ \-f\ pack.properties\ myarchive.pack.gz\ myarchive.jar
more\ pack.properties
#\ Generic\ properties\ for\ the\ packer.
modification.time=latest
deflate.hint=false
keep.file.order=false
#\ This\ option\ will\ cause\ the\ files\ bearing\ new\ attributes\ to
#\ be\ reported\ as\ an\ error\ rather\ than\ passed\ uncompressed.
unknown.attribute=error
#\ Change\ the\ segment\ limit\ to\ be\ unlimited.
segment.limit=\-1
\f[R]
.fi
.RE
.TP
.B \f[CB]\-v\f[R] or \f[CB]\-\-verbose\f[R]
Outputs minimal messages.
Multiple specification of this option will create more verbose messages.
.RS
.RE
.TP
.B \f[CB]\-q\f[R] or \f[CB]\-\-quiet\f[R]
Specifies quiet operation with no messages.
.RS
.RE
.TP
.B \f[CB]\-l\f[R]\f[I]filename\f[R] or \f[CB]\-\-log\-file=\f[R]\f[I]filename\f[R]
Specifies a log file to output messages.
.RS
.RE
.TP
.B \f[CB]\-?\f[R], \f[CB]\-h\f[R], or\f[CB]\-\-help\f[R]
Prints help information about this command.
.RS
.RE
.TP
.B \f[CB]\-V\f[R] or \f[CB]\-\-version\f[R]
Prints version information about this command.
.RS
.RE
.TP
.B \f[CB]\-J\f[R]\f[I]option\f[R]
Passes the specified \f[I]option\f[R] to the Java Virtual Machine.
For example, \f[CB]\-J\-Xms48m\f[R] sets the startup memory to 48 MB.
.RS
.RE

View file

@ -1,126 +0,0 @@
.\" Copyright (c) 1994, 2019, 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.
.\"
.\" 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.
.\"
.\" Automatically generated by Pandoc 2.3.1
.\"
.TH "UNPACK200" "1" "2018" "JDK 13" "JDK Commands"
.hy
.SH NAME
.PP
unpack200 \- transform a packed file into a JAR file for web deployment
.SH SYNOPSIS
.PP
\f[CB]unpack200\f[R] [\f[I]options\f[R]] \f[I]input\-file\f[R]
\f[I]JAR\-file\f[R]
.TP
.B \f[I]options\f[R]
The command\-line options.
See \f[B]Options for the unpack200 Command\f[R].
.RS
.RE
.TP
.B \f[I]input\-file\f[R]
Name of the input file, which can be a \f[CB]pack200\ gzip\f[R] file or a
\f[CB]pack200\f[R] file.
The input can also be a JAR file produced by \f[CB]pack200\f[R] with an
effort of \f[CB]0\f[R], in which case the contents of the input file are
copied to the output JAR file with the \f[CB]pack200\f[R] marker.
.RS
.RE
.TP
.B \f[I]JAR\-file\f[R]
Name of the output JAR file.
.RS
.RE
.SH DESCRIPTION
.PP
The \f[CB]unpack200\f[R] command is a native implementation that
transforms a packed file produced by the \f[CB]pack200\f[R] into a JAR
file for web deployment.
An example of typical usage follows.
In the following example, the \f[CB]myarchive.jar\f[R] file is produced
from \f[CB]myarchive.pack.gz\f[R] with the default \f[CB]unpack200\f[R]
command settings.
.RS
.PP
\f[CB]unpack200\ myarchive.pack.gz\ myarchive.jar\f[R]
.RE
.SH OPTIONS FOR THE UNPACK200 COMMAND
.TP
.B \f[CB]\-H\f[R]\f[I]value\f[R] or \f[CB]\-\-deflate\-hint=\f[R]\f[I]value\f[R]
Sets the deflation to be \f[CB]true\f[R], \f[CB]false\f[R], or \f[CB]keep\f[R]
on all entries within a JAR file.
The default mode is \f[CB]keep\f[R].
If the value is \f[CB]true\f[R] or \f[CB]false\f[R], then the
\f[CB]\-\-deflate=hint\f[R] option overrides the default behavior and sets
the deflation mode on all entries within the output JAR file.
.RS
.RE
.TP
.B \f[CB]\-r\f[R] or \f[CB]\-\-remove\-pack\-file\f[R]
Removes the input pack file.
.RS
.RE
.TP
.B \f[CB]\-v\f[R] or \f[CB]\-\-verbose\f[R]
Displays minimal messages.
Multiple specifications of this option displays more verbose messages.
.RS
.RE
.TP
.B \f[CB]\-q\f[R] or \f[CB]\-\-quiet\f[R]
Specifies quiet operation with no messages.
.RS
.RE
.TP
.B \f[CB]\-l\f[R] \f[I]filename\f[R] or \f[CB]\-\-log\-file=\f[R]\f[I]filename\f[R]
Specifies a log file where output messages are logged.
.RS
.RE
.TP
.B \f[CB]\-?\f[R] or \f[CB]\-h\f[R] or \f[CB]\-\-help\f[R]
Prints help information about the \f[CB]unpack200\f[R] command.
.RS
.RE
.TP
.B \f[CB]\-V\f[R] or \f[CB]\-\-version\f[R]
Prints version information about the \f[CB]unpack200\f[R] command.
.RS
.RE
.TP
.B \f[CB]\-J\f[R]\f[I]option\f[R]
Passes \f[I]option\f[R] to the Java Virtual Machine, where
\f[CB]option\f[R] is one of the options described on the reference page
for the Java application launcher.
For example, \f[CB]\-J\-Xms48m\f[R] sets the startup memory to 48 MB.
.RS
.RE
.SH NOTES
.PP
This command shouldn\[aq]t be confused with the \f[CB]unpack\f[R] command.
They\[aq]re distinctly separate products.
.PP
The Java SE API Specification provided with the JDK is the superseding
authority in case of discrepancies.
.SH EXIT STATUS
.PP
The following exit values are returned: 0 for successful completion, and
a value that is greater than 0 when an error occurred.

View file

@ -1,486 +0,0 @@
/*
* Copyright (c) 2002, 2013, 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.
*/
// -*- C++ -*-
// Small program for unpacking specially compressed Java packages.
// John R. Rose
#include <sys/types.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include "defines.h"
#include "bytes.h"
#include "utils.h"
#include "coding.h"
#include "bands.h"
#include "constants.h"
#include "unpack.h"
inline void band::abort(const char* msg) { u->abort(msg); }
inline bool band::aborting() { return u->aborting(); }
void band::readData(int expectedLength) {
CHECK;
assert(expectedLength >= 0);
assert(vs[0].cmk == cmk_ERROR);
if (expectedLength != 0) {
assert(length == 0);
length = expectedLength;
}
if (length == 0) {
assert((rplimit = cm.vs0.rp = u->rp) != null);
return;
}
assert(length > 0);
bool is_BYTE1 = (defc->spec == BYTE1_spec);
if (is_BYTE1) {
// No possibility of coding change. Sizing is exact.
u->ensure_input(length);
} else {
// Make a conservatively generous estimate of band size in bytes.
// Assume B == 5 everywhere.
// Assume awkward pop with all {U} values (2*5 per value)
jlong generous = (jlong) length * (B_MAX*3+1) + C_SLOP;
u->ensure_input(generous);
}
// Read one value to see what it might be.
int XB = _meta_default;
int cp1 = 0, cp2 = 0;
if (!is_BYTE1) {
// must be a variable-length coding
assert(defc->B() > 1 && defc->L() > 0);
// must have already read from previous band:
assert(bn >= BAND_LIMIT || bn <= 0
|| bn == e_cp_Utf8_big_chars
|| endsWith(name, "_lo") // preceded by _hi conditional band
|| bn == e_file_options // preceded by conditional band
|| u->rp == u->all_bands[bn-1].maxRP()
|| u->all_bands[bn-1].defc == null);
value_stream xvs;
coding* valc = defc;
if (valc->D() != 0) {
valc = coding::findBySpec(defc->B(), defc->H(), defc->S());
assert(!valc->isMalloc);
}
xvs.init(u->rp, u->rplimit, valc);
CHECK;
int X = xvs.getInt();
if (valc->S() != 0) {
assert(valc->min <= -256);
XB = -1-X;
} else {
int L = valc->L();
assert(valc->max >= L+255);
XB = X-L;
}
if (0 <= XB && XB < 256) {
// Skip over the escape value.
u->rp = xvs.rp;
cp1 = 1;
} else {
// No, it's still default.
XB = _meta_default;
}
}
if (XB <= _meta_canon_max) {
byte XB_byte = (byte) XB;
byte* XB_ptr = &XB_byte;
cm.init(u->rp, u->rplimit, XB_ptr, 0, defc, length, null);
CHECK;
} else {
NOT_PRODUCT(byte* meta_rp0 = u->meta_rp);
assert(u->meta_rp != null);
// Scribble the initial byte onto the band.
byte* save_meta_rp = --u->meta_rp;
byte save_meta_xb = (*save_meta_rp);
(*save_meta_rp) = (byte) XB;
cm.init(u->rp, u->rplimit, u->meta_rp, 0, defc, length, null);
(*save_meta_rp) = save_meta_xb; // put it back, just to be tidy
NOT_PRODUCT(cp2 = (int)(u->meta_rp - meta_rp0));
}
rplimit = u->rp;
rewind();
#ifndef PRODUCT
PRINTCR((3,"readFrom %s at %p [%d values, %d bytes, cp=%d/%d]",
(name?name:"(band)"), minRP(), length, size(), cp1, cp2));
if (u->verbose_bands || u->verbose >= 4) dump();
if (ix != null && u->verbose != 0 && length > 0) {
// Check referential integrity early, for easier debugging.
band saved = (*this); // save state
for (int i = 0; i < length; i++) {
int n = vs[0].getInt() - nullOK;
entry *ref = ix->get(n);
assert(ref != null || n == -1);
}
(*this) = saved;
}
#endif
}
#ifndef PRODUCT
void band::dump() {
band saved = (*this); // save state
const char* b_name = name;
char b_name_buf[100];
if (b_name == null) {
char* bp = &b_name_buf[0];
b_name = bp;
sprintf(bp, "#%d/%d", bn, le_kind); bp += strlen(bp);
if (le_bci != 0) { sprintf(bp, "/bci%d", le_bci); bp += strlen(bp); }
if (le_back != 0) { sprintf(bp, "/back%d", le_back); bp += strlen(bp); }
if (le_len != 0) { sprintf(bp, "/len%d", le_len); bp += strlen(bp); }
}
fprintf(u->errstrm, "band %s[%d]%s", b_name, length, (length==0?"\n":" {"));
if (length > 0) {
for (int i = 0; i < length; i++) {
const char* eol = (length > 10 && i % 10 == 0) ? "\n" : " ";
fprintf(u->errstrm, "%s%d", eol, vs[0].getInt());
}
fprintf(u->errstrm, " }\n");
}
(*this) = saved;
}
#endif
void band::setIndex(cpindex* ix_) {
assert(ix_ == null || ixTag == ix_->ixTag);
ix = ix_;
}
void band::setIndexByTag(byte tag) {
setIndex(u->cp.getIndex(tag));
}
entry* band::getRefCommon(cpindex* ix_, bool nullOKwithCaller) {
CHECK_0;
if (ix_ == NULL) {
abort("no index");
return NULL;
}
assert(ix_->ixTag == ixTag
|| ((ixTag == CONSTANT_All ||
ixTag == CONSTANT_LoadableValue ||
ixTag == CONSTANT_AnyMember)
|| (ixTag == CONSTANT_FieldSpecific &&
ix_->ixTag >= CONSTANT_Integer &&
ix_->ixTag <= CONSTANT_String))
);
int n = vs[0].getInt() - nullOK;
// Note: band-local nullOK means null encodes as 0.
// But nullOKwithCaller means caller is willing to tolerate a null.
entry *ref = ix_->get(n);
if (ref == null && !(nullOKwithCaller && n == -1))
abort(n == -1 ? "null ref" : "bad ref");
return ref;
}
jlong band::getLong(band& lo_band, bool have_hi) {
band& hi_band = (*this);
assert(lo_band.bn == hi_band.bn + 1);
uint lo = lo_band.getInt();
if (!have_hi) {
assert(hi_band.length == 0);
return makeLong(0, lo);
}
uint hi = hi_band.getInt();
return makeLong(hi, lo);
}
int band::getIntTotal() {
CHECK_0;
if (length == 0) return 0;
if (total_memo > 0) return total_memo-1;
int total = getInt();
// overflow checks require that none of the addends are <0,
// and that the partial sums never overflow (wrap negative)
if (total < 0) {
abort("overflow detected");
return 0;
}
for (int k = length-1; k > 0; k--) {
int prev_total = total;
total += vs[0].getInt();
if (total < prev_total) {
abort("overflow detected");
return 0;
}
}
rewind();
total_memo = total+1;
return total;
}
int band::getIntCount(int tag) {
CHECK_0;
if (length == 0) return 0;
if (tag >= HIST0_MIN && tag <= HIST0_MAX) {
if (hist0 == null) {
// Lazily calculate an approximate histogram.
hist0 = U_NEW(int, (HIST0_MAX - HIST0_MIN)+1);
CHECK_0;
for (int k = length; k > 0; k--) {
int x = vs[0].getInt();
if (x >= HIST0_MIN && x <= HIST0_MAX)
hist0[x - HIST0_MIN] += 1;
}
rewind();
}
return hist0[tag - HIST0_MIN];
}
int total = 0;
for (int k = length; k > 0; k--) {
total += (vs[0].getInt() == tag) ? 1 : 0;
}
rewind();
return total;
}
#define INDEX_INIT(tag, nullOK, subindex) \
((tag) + (subindex)*SUBINDEX_BIT + (nullOK)*256)
#define INDEX(tag) INDEX_INIT(tag, 0, 0)
#define NULL_OR_INDEX(tag) INDEX_INIT(tag, 1, 0)
#define SUB_INDEX(tag) INDEX_INIT(tag, 0, 1)
#define NO_INDEX 0
struct band_init {
int bn;
const char* name;
int defc;
int index;
};
#define BAND_INIT(name, cspec, ix) \
{ e_##name, #name, /*debug only*/ \
cspec, ix }
const band_init all_band_inits[BAND_LIMIT+1] = {
//BAND_INIT(archive_magic, BYTE1_spec, 0),
//BAND_INIT(archive_header, UNSIGNED5_spec, 0),
//BAND_INIT(band_headers, BYTE1_spec, 0),
BAND_INIT(cp_Utf8_prefix, DELTA5_spec, 0),
BAND_INIT(cp_Utf8_suffix, UNSIGNED5_spec, 0),
BAND_INIT(cp_Utf8_chars, CHAR3_spec, 0),
BAND_INIT(cp_Utf8_big_suffix, DELTA5_spec, 0),
BAND_INIT(cp_Utf8_big_chars, DELTA5_spec, 0),
BAND_INIT(cp_Int, UDELTA5_spec, 0),
BAND_INIT(cp_Float, UDELTA5_spec, 0),
BAND_INIT(cp_Long_hi, UDELTA5_spec, 0),
BAND_INIT(cp_Long_lo, DELTA5_spec, 0),
BAND_INIT(cp_Double_hi, UDELTA5_spec, 0),
BAND_INIT(cp_Double_lo, DELTA5_spec, 0),
BAND_INIT(cp_String, UDELTA5_spec, INDEX(CONSTANT_Utf8)),
BAND_INIT(cp_Class, UDELTA5_spec, INDEX(CONSTANT_Utf8)),
BAND_INIT(cp_Signature_form, DELTA5_spec, INDEX(CONSTANT_Utf8)),
BAND_INIT(cp_Signature_classes, UDELTA5_spec, INDEX(CONSTANT_Class)),
BAND_INIT(cp_Descr_name, DELTA5_spec, INDEX(CONSTANT_Utf8)),
BAND_INIT(cp_Descr_type, UDELTA5_spec, INDEX(CONSTANT_Signature)),
BAND_INIT(cp_Field_class, DELTA5_spec, INDEX(CONSTANT_Class)),
BAND_INIT(cp_Field_desc, UDELTA5_spec, INDEX(CONSTANT_NameandType)),
BAND_INIT(cp_Method_class, DELTA5_spec, INDEX(CONSTANT_Class)),
BAND_INIT(cp_Method_desc, UDELTA5_spec, INDEX(CONSTANT_NameandType)),
BAND_INIT(cp_Imethod_class, DELTA5_spec, INDEX(CONSTANT_Class)),
BAND_INIT(cp_Imethod_desc, UDELTA5_spec, INDEX(CONSTANT_NameandType)),
BAND_INIT(cp_MethodHandle_refkind, DELTA5_spec, 0),
BAND_INIT(cp_MethodHandle_member, UDELTA5_spec, INDEX(CONSTANT_AnyMember)),
BAND_INIT(cp_MethodType, UDELTA5_spec, INDEX(CONSTANT_Signature)),
BAND_INIT(cp_BootstrapMethod_ref, DELTA5_spec, INDEX(CONSTANT_MethodHandle)),
BAND_INIT(cp_BootstrapMethod_arg_count, UDELTA5_spec, 0),
BAND_INIT(cp_BootstrapMethod_arg, DELTA5_spec, INDEX(CONSTANT_LoadableValue)),
BAND_INIT(cp_InvokeDynamic_spec, DELTA5_spec, INDEX(CONSTANT_BootstrapMethod)),
BAND_INIT(cp_InvokeDynamic_desc, UDELTA5_spec, INDEX(CONSTANT_NameandType)),
BAND_INIT(attr_definition_headers, BYTE1_spec, 0),
BAND_INIT(attr_definition_name, UNSIGNED5_spec, INDEX(CONSTANT_Utf8)),
BAND_INIT(attr_definition_layout, UNSIGNED5_spec, INDEX(CONSTANT_Utf8)),
BAND_INIT(ic_this_class, UDELTA5_spec, INDEX(CONSTANT_Class)),
BAND_INIT(ic_flags, UNSIGNED5_spec, 0),
BAND_INIT(ic_outer_class, DELTA5_spec, NULL_OR_INDEX(CONSTANT_Class)),
BAND_INIT(ic_name, DELTA5_spec, NULL_OR_INDEX(CONSTANT_Utf8)),
BAND_INIT(class_this, DELTA5_spec, INDEX(CONSTANT_Class)),
BAND_INIT(class_super, DELTA5_spec, INDEX(CONSTANT_Class)),
BAND_INIT(class_interface_count, DELTA5_spec, 0),
BAND_INIT(class_interface, DELTA5_spec, INDEX(CONSTANT_Class)),
BAND_INIT(class_field_count, DELTA5_spec, 0),
BAND_INIT(class_method_count, DELTA5_spec, 0),
BAND_INIT(field_descr, DELTA5_spec, INDEX(CONSTANT_NameandType)),
BAND_INIT(field_flags_hi, UNSIGNED5_spec, 0),
BAND_INIT(field_flags_lo, UNSIGNED5_spec, 0),
BAND_INIT(field_attr_count, UNSIGNED5_spec, 0),
BAND_INIT(field_attr_indexes, UNSIGNED5_spec, 0),
BAND_INIT(field_attr_calls, UNSIGNED5_spec, 0),
BAND_INIT(field_ConstantValue_KQ, UNSIGNED5_spec, INDEX(CONSTANT_FieldSpecific)),
BAND_INIT(field_Signature_RS, UNSIGNED5_spec, INDEX(CONSTANT_Signature)),
BAND_INIT(field_metadata_bands, -1, -1),
BAND_INIT(field_attr_bands, -1, -1),
BAND_INIT(method_descr, MDELTA5_spec, INDEX(CONSTANT_NameandType)),
BAND_INIT(method_flags_hi, UNSIGNED5_spec, 0),
BAND_INIT(method_flags_lo, UNSIGNED5_spec, 0),
BAND_INIT(method_attr_count, UNSIGNED5_spec, 0),
BAND_INIT(method_attr_indexes, UNSIGNED5_spec, 0),
BAND_INIT(method_attr_calls, UNSIGNED5_spec, 0),
BAND_INIT(method_Exceptions_N, UNSIGNED5_spec, 0),
BAND_INIT(method_Exceptions_RC, UNSIGNED5_spec, INDEX(CONSTANT_Class)),
BAND_INIT(method_Signature_RS, UNSIGNED5_spec, INDEX(CONSTANT_Signature)),
BAND_INIT(method_metadata_bands, -1, -1),
BAND_INIT(method_MethodParameters_NB, BYTE1_spec, 0),
BAND_INIT(method_MethodParameters_name_RUN, UNSIGNED5_spec, NULL_OR_INDEX(CONSTANT_Utf8)),
BAND_INIT(method_MethodParameters_flag_FH, UNSIGNED5_spec, 0),
BAND_INIT(method_attr_bands, -1, -1),
BAND_INIT(class_flags_hi, UNSIGNED5_spec, 0),
BAND_INIT(class_flags_lo, UNSIGNED5_spec, 0),
BAND_INIT(class_attr_count, UNSIGNED5_spec, 0),
BAND_INIT(class_attr_indexes, UNSIGNED5_spec, 0),
BAND_INIT(class_attr_calls, UNSIGNED5_spec, 0),
BAND_INIT(class_SourceFile_RUN, UNSIGNED5_spec, NULL_OR_INDEX(CONSTANT_Utf8)),
BAND_INIT(class_EnclosingMethod_RC, UNSIGNED5_spec, INDEX(CONSTANT_Class)),
BAND_INIT(class_EnclosingMethod_RDN, UNSIGNED5_spec, NULL_OR_INDEX(CONSTANT_NameandType)),
BAND_INIT(class_Signature_RS, UNSIGNED5_spec, INDEX(CONSTANT_Signature)),
BAND_INIT(class_metadata_bands, -1, -1),
BAND_INIT(class_InnerClasses_N, UNSIGNED5_spec, 0),
BAND_INIT(class_InnerClasses_RC, UNSIGNED5_spec, INDEX(CONSTANT_Class)),
BAND_INIT(class_InnerClasses_F, UNSIGNED5_spec, 0),
BAND_INIT(class_InnerClasses_outer_RCN, UNSIGNED5_spec, NULL_OR_INDEX(CONSTANT_Class)),
BAND_INIT(class_InnerClasses_name_RUN, UNSIGNED5_spec, NULL_OR_INDEX(CONSTANT_Utf8)),
BAND_INIT(class_ClassFile_version_minor_H, UNSIGNED5_spec, 0),
BAND_INIT(class_ClassFile_version_major_H, UNSIGNED5_spec, 0),
BAND_INIT(class_attr_bands, -1, -1),
BAND_INIT(code_headers, BYTE1_spec, 0),
BAND_INIT(code_max_stack, UNSIGNED5_spec, 0),
BAND_INIT(code_max_na_locals, UNSIGNED5_spec, 0),
BAND_INIT(code_handler_count, UNSIGNED5_spec, 0),
BAND_INIT(code_handler_start_P, BCI5_spec, 0),
BAND_INIT(code_handler_end_PO, BRANCH5_spec, 0),
BAND_INIT(code_handler_catch_PO, BRANCH5_spec, 0),
BAND_INIT(code_handler_class_RCN, UNSIGNED5_spec, NULL_OR_INDEX(CONSTANT_Class)),
BAND_INIT(code_flags_hi, UNSIGNED5_spec, 0),
BAND_INIT(code_flags_lo, UNSIGNED5_spec, 0),
BAND_INIT(code_attr_count, UNSIGNED5_spec, 0),
BAND_INIT(code_attr_indexes, UNSIGNED5_spec, 0),
BAND_INIT(code_attr_calls, UNSIGNED5_spec, 0),
BAND_INIT(code_StackMapTable_N, UNSIGNED5_spec, 0),
BAND_INIT(code_StackMapTable_frame_T, BYTE1_spec, 0),
BAND_INIT(code_StackMapTable_local_N, UNSIGNED5_spec, 0),
BAND_INIT(code_StackMapTable_stack_N, UNSIGNED5_spec, 0),
BAND_INIT(code_StackMapTable_offset, UNSIGNED5_spec, 0),
BAND_INIT(code_StackMapTable_T, BYTE1_spec, 0),
BAND_INIT(code_StackMapTable_RC, UNSIGNED5_spec, INDEX(CONSTANT_Class)),
BAND_INIT(code_StackMapTable_P, BCI5_spec, 0),
BAND_INIT(code_LineNumberTable_N, UNSIGNED5_spec, 0),
BAND_INIT(code_LineNumberTable_bci_P, BCI5_spec, 0),
BAND_INIT(code_LineNumberTable_line, UNSIGNED5_spec, 0),
BAND_INIT(code_LocalVariableTable_N, UNSIGNED5_spec, 0),
BAND_INIT(code_LocalVariableTable_bci_P, BCI5_spec, 0),
BAND_INIT(code_LocalVariableTable_span_O, BRANCH5_spec, 0),
BAND_INIT(code_LocalVariableTable_name_RU, UNSIGNED5_spec, INDEX(CONSTANT_Utf8)),
BAND_INIT(code_LocalVariableTable_type_RS, UNSIGNED5_spec, INDEX(CONSTANT_Signature)),
BAND_INIT(code_LocalVariableTable_slot, UNSIGNED5_spec, 0),
BAND_INIT(code_LocalVariableTypeTable_N, UNSIGNED5_spec, 0),
BAND_INIT(code_LocalVariableTypeTable_bci_P, BCI5_spec, 0),
BAND_INIT(code_LocalVariableTypeTable_span_O, BRANCH5_spec, 0),
BAND_INIT(code_LocalVariableTypeTable_name_RU, UNSIGNED5_spec, INDEX(CONSTANT_Utf8)),
BAND_INIT(code_LocalVariableTypeTable_type_RS, UNSIGNED5_spec, INDEX(CONSTANT_Signature)),
BAND_INIT(code_LocalVariableTypeTable_slot, UNSIGNED5_spec, 0),
BAND_INIT(code_attr_bands, -1, -1),
BAND_INIT(bc_codes, BYTE1_spec, 0),
BAND_INIT(bc_case_count, UNSIGNED5_spec, 0),
BAND_INIT(bc_case_value, DELTA5_spec, 0),
BAND_INIT(bc_byte, BYTE1_spec, 0),
BAND_INIT(bc_short, DELTA5_spec, 0),
BAND_INIT(bc_local, UNSIGNED5_spec, 0),
BAND_INIT(bc_label, BRANCH5_spec, 0),
BAND_INIT(bc_intref, DELTA5_spec, INDEX(CONSTANT_Integer)),
BAND_INIT(bc_floatref, DELTA5_spec, INDEX(CONSTANT_Float)),
BAND_INIT(bc_longref, DELTA5_spec, INDEX(CONSTANT_Long)),
BAND_INIT(bc_doubleref, DELTA5_spec, INDEX(CONSTANT_Double)),
BAND_INIT(bc_stringref, DELTA5_spec, INDEX(CONSTANT_String)),
BAND_INIT(bc_loadablevalueref, DELTA5_spec, INDEX(CONSTANT_LoadableValue)),
BAND_INIT(bc_classref, UNSIGNED5_spec, NULL_OR_INDEX(CONSTANT_Class)),
BAND_INIT(bc_fieldref, DELTA5_spec, INDEX(CONSTANT_Fieldref)),
BAND_INIT(bc_methodref, UNSIGNED5_spec, INDEX(CONSTANT_Methodref)),
BAND_INIT(bc_imethodref, DELTA5_spec, INDEX(CONSTANT_InterfaceMethodref)),
BAND_INIT(bc_indyref, DELTA5_spec, INDEX(CONSTANT_InvokeDynamic)),
BAND_INIT(bc_thisfield, UNSIGNED5_spec, SUB_INDEX(CONSTANT_Fieldref)),
BAND_INIT(bc_superfield, UNSIGNED5_spec, SUB_INDEX(CONSTANT_Fieldref)),
BAND_INIT(bc_thismethod, UNSIGNED5_spec, SUB_INDEX(CONSTANT_Methodref)),
BAND_INIT(bc_supermethod, UNSIGNED5_spec, SUB_INDEX(CONSTANT_Methodref)),
BAND_INIT(bc_initref, UNSIGNED5_spec, SUB_INDEX(CONSTANT_Methodref)),
BAND_INIT(bc_escref, UNSIGNED5_spec, INDEX(CONSTANT_All)),
BAND_INIT(bc_escrefsize, UNSIGNED5_spec, 0),
BAND_INIT(bc_escsize, UNSIGNED5_spec, 0),
BAND_INIT(bc_escbyte, BYTE1_spec, 0),
BAND_INIT(file_name, UNSIGNED5_spec, INDEX(CONSTANT_Utf8)),
BAND_INIT(file_size_hi, UNSIGNED5_spec, 0),
BAND_INIT(file_size_lo, UNSIGNED5_spec, 0),
BAND_INIT(file_modtime, DELTA5_spec, 0),
BAND_INIT(file_options, UNSIGNED5_spec, 0),
//BAND_INIT(file_bits, BYTE1_spec, 0),
{ 0, NULL, 0, 0 }
};
band* band::makeBands(unpacker* u) {
band* tmp_all_bands = U_NEW(band, BAND_LIMIT);
for (int i = 0; i < BAND_LIMIT; i++) {
assert((byte*)&all_band_inits[i+1]
< (byte*)all_band_inits+sizeof(all_band_inits));
const band_init& bi = all_band_inits[i];
band& b = tmp_all_bands[i];
coding* defc = coding::findBySpec(bi.defc);
assert((defc == null) == (bi.defc == -1)); // no garbage, please
assert(defc == null || !defc->isMalloc);
assert(bi.bn == i); // band array consistent w/ band enum
b.init(u, i, defc);
if (bi.index > 0) {
b.nullOK = ((bi.index >> 8) & 1);
b.ixTag = (bi.index & 0xFF);
}
#ifndef PRODUCT
b.name = bi.name;
#endif
}
return tmp_all_bands;
}
void band::initIndexes(unpacker* u) {
band* tmp_all_bands = u->all_bands;
for (int i = 0; i < BAND_LIMIT; i++) {
band* scan = &tmp_all_bands[i];
uint tag = scan->ixTag; // Cf. #define INDEX(tag) above
if (tag != 0 && tag != CONSTANT_FieldSpecific && (tag & SUBINDEX_BIT) == 0) {
scan->setIndex(u->cp.getIndex(tag));
}
}
}

View file

@ -1,481 +0,0 @@
/*
* Copyright (c) 2002, 2013, 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.
*/
// -*- C++ -*-
struct entry;
struct cpindex;
struct unpacker;
struct band {
const char* name;
int bn; // band_number of this band
coding* defc; // default coding method
cpindex* ix; // CP entry mapping, if CPRefBand
byte ixTag; // 0 or 1; null is coded as (nullOK?0:-1)
byte nullOK; // 0 or 1; null is coded as (nullOK?0:-1)
int length; // expected # values
unpacker* u; // back pointer
value_stream vs[2]; // source of values
coding_method cm; // method used for initial state of vs[0]
byte* rplimit; // end of band (encoded, transmitted)
int total_memo; // cached value of getIntTotal, or -1
int* hist0; // approximate. histogram
enum { HIST0_MIN = 0, HIST0_MAX = 255 }; // catches the usual cases
// properties for attribute layout elements:
byte le_kind; // EK_XXX
byte le_bci; // 0,EK_BCI,EK_BCD,EK_BCO
byte le_back; // ==EF_BACK
byte le_len; // 0,1,2,4 (size in classfile), or call addr
band** le_body; // body of repl, union, call (null-terminated)
// Note: EK_CASE elements use hist0 to record union tags.
#define le_casetags hist0
band& nextBand() { return this[1]; }
band& prevBand() { return this[-1]; }
void init(unpacker* u_, int bn_, coding* defc_) {
u = u_;
cm.u = u_;
bn = bn_;
defc = defc_;
}
void init(unpacker* u_, int bn_, int defcSpec) {
init(u_, bn_, coding::findBySpec(defcSpec));
}
void initRef(int ixTag_ = 0, bool nullOK_ = false) {
ixTag = ixTag_;
nullOK = nullOK_;
setIndexByTag(ixTag);
}
void expectMoreLength(int l) {
assert(length >= 0); // able to accept a length
assert((int)l >= 0); // no overflow
assert(rplimit == null); // readData not yet called
length += l;
assert(length >= l); // no overflow
}
void setIndex(cpindex* ix_);
void setIndexByTag(byte tag);
// Parse the band and its meta-coding header.
void readData(int expectedLength = 0);
// Reset the band for another pass (Cf. Java Band.resetForSecondPass.)
void rewind() {
cm.reset(&vs[0]);
}
byte* &curRP() { return vs[0].rp; }
byte* minRP() { return cm.vs0.rp; }
byte* maxRP() { return rplimit; }
size_t size() { return maxRP() - minRP(); }
int getByte() { assert(ix == null); return vs[0].getByte(); }
int getInt() { assert(ix == null); return vs[0].getInt(); }
entry* getRefN() { return getRefCommon(ix, true); }
entry* getRef() { return getRefCommon(ix, false); }
entry* getRefUsing(cpindex* ix2)
{ assert(ix == null); return getRefCommon(ix2, true); }
entry* getRefCommon(cpindex* ix, bool nullOK);
jlong getLong(band& lo_band, bool have_hi);
static jlong makeLong(uint hi, uint lo) {
return ((julong)hi << 32) + (((julong)lo << 32) >> 32);
}
int getIntTotal();
int getIntCount(int tag);
static band* makeBands(unpacker* u);
static void initIndexes(unpacker* u);
#ifndef PRODUCT
void dump();
#endif
void abort(const char* msg = null); //{ u->abort(msg); }
bool aborting(); //{ return u->aborting(); }
};
extern band all_bands[];
#define BAND_LOCAL /* \
band* band_temp = all_bands; \
band* all_bands = band_temp */
// Band schema:
enum band_number {
//e_archive_magic,
//e_archive_header,
//e_band_headers,
// constant pool contents
e_cp_Utf8_prefix,
e_cp_Utf8_suffix,
e_cp_Utf8_chars,
e_cp_Utf8_big_suffix,
e_cp_Utf8_big_chars,
e_cp_Int,
e_cp_Float,
e_cp_Long_hi,
e_cp_Long_lo,
e_cp_Double_hi,
e_cp_Double_lo,
e_cp_String,
e_cp_Class,
e_cp_Signature_form,
e_cp_Signature_classes,
e_cp_Descr_name,
e_cp_Descr_type,
e_cp_Field_class,
e_cp_Field_desc,
e_cp_Method_class,
e_cp_Method_desc,
e_cp_Imethod_class,
e_cp_Imethod_desc,
e_cp_MethodHandle_refkind,
e_cp_MethodHandle_member,
e_cp_MethodType,
e_cp_BootstrapMethod_ref,
e_cp_BootstrapMethod_arg_count,
e_cp_BootstrapMethod_arg,
e_cp_InvokeDynamic_spec,
e_cp_InvokeDynamic_desc,
// bands which define transmission of attributes
e_attr_definition_headers,
e_attr_definition_name,
e_attr_definition_layout,
// band for hardwired InnerClasses attribute (shared across the package)
e_ic_this_class,
e_ic_flags,
// These bands contain data only where flags sets ACC_IC_LONG_FORM:
e_ic_outer_class,
e_ic_name,
// bands for carrying class schema information:
e_class_this,
e_class_super,
e_class_interface_count,
e_class_interface,
// bands for class members
e_class_field_count,
e_class_method_count,
e_field_descr,
e_field_flags_hi,
e_field_flags_lo,
e_field_attr_count,
e_field_attr_indexes,
e_field_attr_calls,
e_field_ConstantValue_KQ,
e_field_Signature_RS,
e_field_metadata_bands,
e_field_attr_bands,
e_method_descr,
e_method_flags_hi,
e_method_flags_lo,
e_method_attr_count,
e_method_attr_indexes,
e_method_attr_calls,
e_method_Exceptions_N,
e_method_Exceptions_RC,
e_method_Signature_RS,
e_method_metadata_bands,
e_method_MethodParameters_NB,
e_method_MethodParameters_name_RUN,
e_method_MethodParameters_flag_FH,
e_method_attr_bands,
e_class_flags_hi,
e_class_flags_lo,
e_class_attr_count,
e_class_attr_indexes,
e_class_attr_calls,
e_class_SourceFile_RUN,
e_class_EnclosingMethod_RC,
e_class_EnclosingMethod_RDN,
e_class_Signature_RS,
e_class_metadata_bands,
e_class_InnerClasses_N,
e_class_InnerClasses_RC,
e_class_InnerClasses_F,
e_class_InnerClasses_outer_RCN,
e_class_InnerClasses_name_RUN,
e_class_ClassFile_version_minor_H,
e_class_ClassFile_version_major_H,
e_class_attr_bands,
e_code_headers,
e_code_max_stack,
e_code_max_na_locals,
e_code_handler_count,
e_code_handler_start_P,
e_code_handler_end_PO,
e_code_handler_catch_PO,
e_code_handler_class_RCN,
// code attributes
e_code_flags_hi,
e_code_flags_lo,
e_code_attr_count,
e_code_attr_indexes,
e_code_attr_calls,
e_code_StackMapTable_N,
e_code_StackMapTable_frame_T,
e_code_StackMapTable_local_N,
e_code_StackMapTable_stack_N,
e_code_StackMapTable_offset,
e_code_StackMapTable_T,
e_code_StackMapTable_RC,
e_code_StackMapTable_P,
e_code_LineNumberTable_N,
e_code_LineNumberTable_bci_P,
e_code_LineNumberTable_line,
e_code_LocalVariableTable_N,
e_code_LocalVariableTable_bci_P,
e_code_LocalVariableTable_span_O,
e_code_LocalVariableTable_name_RU,
e_code_LocalVariableTable_type_RS,
e_code_LocalVariableTable_slot,
e_code_LocalVariableTypeTable_N,
e_code_LocalVariableTypeTable_bci_P,
e_code_LocalVariableTypeTable_span_O,
e_code_LocalVariableTypeTable_name_RU,
e_code_LocalVariableTypeTable_type_RS,
e_code_LocalVariableTypeTable_slot,
e_code_attr_bands,
// bands for bytecodes
e_bc_codes,
// remaining bands provide typed opcode fields required by the bc_codes
e_bc_case_count,
e_bc_case_value,
e_bc_byte,
e_bc_short,
e_bc_local,
e_bc_label,
// ldc* operands:
e_bc_intref,
e_bc_floatref,
e_bc_longref,
e_bc_doubleref,
e_bc_stringref,
e_bc_loadablevalueref,
e_bc_classref,
e_bc_fieldref,
e_bc_methodref,
e_bc_imethodref,
e_bc_indyref,
// _self_linker_op family
e_bc_thisfield,
e_bc_superfield,
e_bc_thismethod,
e_bc_supermethod,
// bc_invokeinit family:
e_bc_initref,
// bytecode escape sequences
e_bc_escref,
e_bc_escrefsize,
e_bc_escsize,
e_bc_escbyte,
// file attributes and contents
e_file_name,
e_file_size_hi,
e_file_size_lo,
e_file_modtime,
e_file_options,
//e_file_bits, // handled specially as an appendix
BAND_LIMIT
};
// Symbolic names for bands, as if in a giant global struct:
//#define archive_magic all_bands[e_archive_magic]
//#define archive_header all_bands[e_archive_header]
//#define band_headers all_bands[e_band_headers]
#define cp_Utf8_prefix all_bands[e_cp_Utf8_prefix]
#define cp_Utf8_suffix all_bands[e_cp_Utf8_suffix]
#define cp_Utf8_chars all_bands[e_cp_Utf8_chars]
#define cp_Utf8_big_suffix all_bands[e_cp_Utf8_big_suffix]
#define cp_Utf8_big_chars all_bands[e_cp_Utf8_big_chars]
#define cp_Int all_bands[e_cp_Int]
#define cp_Float all_bands[e_cp_Float]
#define cp_Long_hi all_bands[e_cp_Long_hi]
#define cp_Long_lo all_bands[e_cp_Long_lo]
#define cp_Double_hi all_bands[e_cp_Double_hi]
#define cp_Double_lo all_bands[e_cp_Double_lo]
#define cp_String all_bands[e_cp_String]
#define cp_Class all_bands[e_cp_Class]
#define cp_Signature_form all_bands[e_cp_Signature_form]
#define cp_Signature_classes all_bands[e_cp_Signature_classes]
#define cp_Descr_name all_bands[e_cp_Descr_name]
#define cp_Descr_type all_bands[e_cp_Descr_type]
#define cp_Field_class all_bands[e_cp_Field_class]
#define cp_Field_desc all_bands[e_cp_Field_desc]
#define cp_Method_class all_bands[e_cp_Method_class]
#define cp_Method_desc all_bands[e_cp_Method_desc]
#define cp_Imethod_class all_bands[e_cp_Imethod_class]
#define cp_Imethod_desc all_bands[e_cp_Imethod_desc]
#define cp_MethodHandle_refkind all_bands[e_cp_MethodHandle_refkind]
#define cp_MethodHandle_member all_bands[e_cp_MethodHandle_member]
#define cp_MethodType all_bands[e_cp_MethodType]
#define cp_BootstrapMethod_ref all_bands[e_cp_BootstrapMethod_ref]
#define cp_BootstrapMethod_arg_count all_bands[e_cp_BootstrapMethod_arg_count]
#define cp_BootstrapMethod_arg all_bands[e_cp_BootstrapMethod_arg]
#define cp_InvokeDynamic_spec all_bands[e_cp_InvokeDynamic_spec]
#define cp_InvokeDynamic_desc all_bands[e_cp_InvokeDynamic_desc]
#define attr_definition_headers all_bands[e_attr_definition_headers]
#define attr_definition_name all_bands[e_attr_definition_name]
#define attr_definition_layout all_bands[e_attr_definition_layout]
#define ic_this_class all_bands[e_ic_this_class]
#define ic_flags all_bands[e_ic_flags]
#define ic_outer_class all_bands[e_ic_outer_class]
#define ic_name all_bands[e_ic_name]
#define class_this all_bands[e_class_this]
#define class_super all_bands[e_class_super]
#define class_interface_count all_bands[e_class_interface_count]
#define class_interface all_bands[e_class_interface]
#define class_field_count all_bands[e_class_field_count]
#define class_method_count all_bands[e_class_method_count]
#define field_descr all_bands[e_field_descr]
#define field_flags_hi all_bands[e_field_flags_hi]
#define field_flags_lo all_bands[e_field_flags_lo]
#define field_attr_count all_bands[e_field_attr_count]
#define field_attr_indexes all_bands[e_field_attr_indexes]
#define field_ConstantValue_KQ all_bands[e_field_ConstantValue_KQ]
#define field_Signature_RS all_bands[e_field_Signature_RS]
#define field_attr_bands all_bands[e_field_attr_bands]
#define method_descr all_bands[e_method_descr]
#define method_flags_hi all_bands[e_method_flags_hi]
#define method_flags_lo all_bands[e_method_flags_lo]
#define method_attr_count all_bands[e_method_attr_count]
#define method_attr_indexes all_bands[e_method_attr_indexes]
#define method_Exceptions_N all_bands[e_method_Exceptions_N]
#define method_Exceptions_RC all_bands[e_method_Exceptions_RC]
#define method_Signature_RS all_bands[e_method_Signature_RS]
#define method_MethodParameters_NB all_bands[e_method_MethodParameters_NB]
#define method_MethodParameters_name_RUN all_bands[e_method_MethodParameters_name_RUN]
#define method_MethodParameters_flag_FH all_bands[e_method_MethodParameters_flag_FH]
#define method_attr_bands all_bands[e_method_attr_bands]
#define class_flags_hi all_bands[e_class_flags_hi]
#define class_flags_lo all_bands[e_class_flags_lo]
#define class_attr_count all_bands[e_class_attr_count]
#define class_attr_indexes all_bands[e_class_attr_indexes]
#define class_SourceFile_RUN all_bands[e_class_SourceFile_RUN]
#define class_EnclosingMethod_RC all_bands[e_class_EnclosingMethod_RC]
#define class_EnclosingMethod_RDN all_bands[e_class_EnclosingMethod_RDN]
#define class_Signature_RS all_bands[e_class_Signature_RS]
#define class_InnerClasses_N all_bands[e_class_InnerClasses_N]
#define class_InnerClasses_RC all_bands[e_class_InnerClasses_RC]
#define class_InnerClasses_F all_bands[e_class_InnerClasses_F]
#define class_InnerClasses_outer_RCN all_bands[e_class_InnerClasses_outer_RCN]
#define class_InnerClasses_name_RUN all_bands[e_class_InnerClasses_name_RUN]
#define class_ClassFile_version_minor_H all_bands[e_class_ClassFile_version_minor_H]
#define class_ClassFile_version_major_H all_bands[e_class_ClassFile_version_major_H]
#define class_attr_bands all_bands[e_class_attr_bands]
#define code_headers all_bands[e_code_headers]
#define code_max_stack all_bands[e_code_max_stack]
#define code_max_na_locals all_bands[e_code_max_na_locals]
#define code_handler_count all_bands[e_code_handler_count]
#define code_handler_start_P all_bands[e_code_handler_start_P]
#define code_handler_end_PO all_bands[e_code_handler_end_PO]
#define code_handler_catch_PO all_bands[e_code_handler_catch_PO]
#define code_handler_class_RCN all_bands[e_code_handler_class_RCN]
#define code_flags_hi all_bands[e_code_flags_hi]
#define code_flags_lo all_bands[e_code_flags_lo]
#define code_attr_count all_bands[e_code_attr_count]
#define code_attr_indexes all_bands[e_code_attr_indexes]
#define code_StackMapTable_N all_bands[e_code_StackMapTable_N]
#define code_StackMapTable_frame_T all_bands[e_code_StackMapTable_frame_T]
#define code_StackMapTable_local_N all_bands[e_code_StackMapTable_local_N]
#define code_StackMapTable_stack_N all_bands[e_code_StackMapTable_stack_N]
#define code_StackMapTable_offset all_bands[e_code_StackMapTable_offset]
#define code_StackMapTable_T all_bands[e_code_StackMapTable_T]
#define code_StackMapTable_RC all_bands[e_code_StackMapTable_RC]
#define code_StackMapTable_P all_bands[e_code_StackMapTable_P]
#define code_LineNumberTable_N all_bands[e_code_LineNumberTable_N]
#define code_LineNumberTable_bci_P all_bands[e_code_LineNumberTable_bci_P]
#define code_LineNumberTable_line all_bands[e_code_LineNumberTable_line]
#define code_LocalVariableTable_N all_bands[e_code_LocalVariableTable_N]
#define code_LocalVariableTable_bci_P all_bands[e_code_LocalVariableTable_bci_P]
#define code_LocalVariableTable_span_O all_bands[e_code_LocalVariableTable_span_O]
#define code_LocalVariableTable_name_RU all_bands[e_code_LocalVariableTable_name_RU]
#define code_LocalVariableTable_type_RS all_bands[e_code_LocalVariableTable_type_RS]
#define code_LocalVariableTable_slot all_bands[e_code_LocalVariableTable_slot]
#define code_LocalVariableTypeTable_N all_bands[e_code_LocalVariableTypeTable_N]
#define code_LocalVariableTypeTable_bci_P all_bands[e_code_LocalVariableTypeTable_bci_P]
#define code_LocalVariableTypeTable_span_O all_bands[e_code_LocalVariableTypeTable_span_O]
#define code_LocalVariableTypeTable_name_RU all_bands[e_code_LocalVariableTypeTable_name_RU]
#define code_LocalVariableTypeTable_type_RS all_bands[e_code_LocalVariableTypeTable_type_RS]
#define code_LocalVariableTypeTable_slot all_bands[e_code_LocalVariableTypeTable_slot]
#define code_attr_bands all_bands[e_code_attr_bands]
#define bc_codes all_bands[e_bc_codes]
#define bc_case_count all_bands[e_bc_case_count]
#define bc_case_value all_bands[e_bc_case_value]
#define bc_byte all_bands[e_bc_byte]
#define bc_short all_bands[e_bc_short]
#define bc_local all_bands[e_bc_local]
#define bc_label all_bands[e_bc_label]
#define bc_intref all_bands[e_bc_intref]
#define bc_floatref all_bands[e_bc_floatref]
#define bc_longref all_bands[e_bc_longref]
#define bc_doubleref all_bands[e_bc_doubleref]
#define bc_stringref all_bands[e_bc_stringref]
#define bc_loadablevalueref all_bands[e_bc_loadablevalueref]
#define bc_classref all_bands[e_bc_classref]
#define bc_fieldref all_bands[e_bc_fieldref]
#define bc_methodref all_bands[e_bc_methodref]
#define bc_imethodref all_bands[e_bc_imethodref]
#define bc_indyref all_bands[e_bc_indyref]
#define bc_thisfield all_bands[e_bc_thisfield]
#define bc_superfield all_bands[e_bc_superfield]
#define bc_thismethod all_bands[e_bc_thismethod]
#define bc_supermethod all_bands[e_bc_supermethod]
#define bc_initref all_bands[e_bc_initref]
#define bc_escref all_bands[e_bc_escref]
#define bc_escrefsize all_bands[e_bc_escrefsize]
#define bc_escsize all_bands[e_bc_escsize]
#define bc_escbyte all_bands[e_bc_escbyte]
#define file_name all_bands[e_file_name]
#define file_size_hi all_bands[e_file_size_hi]
#define file_size_lo all_bands[e_file_size_lo]
#define file_modtime all_bands[e_file_modtime]
#define file_options all_bands[e_file_options]

View file

@ -1,193 +0,0 @@
/*
* Copyright (c) 2001, 2010, 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.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "defines.h"
#include "bytes.h"
#include "utils.h"
static byte dummy[1 << 10];
bool bytes::inBounds(const void* p) {
return p >= ptr && p < limit();
}
void bytes::malloc(size_t len_) {
len = len_;
ptr = NEW(byte, add_size(len_, 1)); // add trailing zero byte always
if (ptr == null) {
// set ptr to some victim memory, to ease escape
set(dummy, sizeof(dummy)-1);
unpack_abort(ERROR_ENOMEM);
}
}
void bytes::realloc(size_t len_) {
if (len == len_) return; // nothing to do
if (ptr == dummy) return; // escaping from an error
if (ptr == null) {
malloc(len_);
return;
}
byte* oldptr = ptr;
ptr = (len_ >= PSIZE_MAX) ? null : (byte*)::realloc(ptr, add_size(len_, 1));
if (ptr != null) {
mtrace('r', oldptr, 0);
mtrace('m', ptr, len_+1);
if (len < len_) memset(ptr+len, 0, len_-len);
ptr[len_] = 0;
len = len_;
} else {
ptr = oldptr; // ease our escape
unpack_abort(ERROR_ENOMEM);
}
}
void bytes::free() {
if (ptr == dummy) return; // escaping from an error
if (ptr != null) {
mtrace('f', ptr, 0);
::free(ptr);
}
len = 0;
ptr = 0;
}
int bytes::indexOf(byte c) {
byte* p = (byte*) memchr(ptr, c, len);
return (p == 0) ? -1 : (int)(p - ptr);
}
byte* bytes::writeTo(byte* bp) {
memcpy(bp, ptr, len);
return bp+len;
}
int bytes::compareTo(bytes& other) {
size_t l1 = len;
size_t l2 = other.len;
int cmp = memcmp(ptr, other.ptr, (l1 < l2) ? l1 : l2);
if (cmp != 0) return cmp;
return (l1 < l2) ? -1 : (l1 > l2) ? 1 : 0;
}
void bytes::saveFrom(const void* ptr_, size_t len_) {
malloc(len_);
// Save as much as possible. (Helps unpacker::abort.)
if (len_ > len) {
assert(ptr == dummy); // error recovery
len_ = len;
}
copyFrom(ptr_, len_);
}
//#TODO: Need to fix for exception handling
void bytes::copyFrom(const void* ptr_, size_t len_, size_t offset) {
assert(len_ == 0 || inBounds(ptr + offset));
assert(len_ == 0 || inBounds(ptr + offset+len_-1));
memcpy(ptr+offset, ptr_, len_);
}
#ifndef PRODUCT
const char* bytes::string() {
if (len == 0) return "";
if (ptr[len] == 0 && strlen((char*)ptr) == len) return (const char*) ptr;
bytes junk;
junk.saveFrom(*this);
return (char*) junk.ptr;
}
#endif
// Make sure there are 'o' bytes beyond the fill pointer,
// advance the fill pointer, and return the old fill pointer.
byte* fillbytes::grow(size_t s) {
size_t nlen = add_size(b.len, s);
if (nlen <= allocated) {
b.len = nlen;
return limit()-s;
}
size_t maxlen = nlen;
if (maxlen < 128) maxlen = 128;
if (maxlen < allocated*2) maxlen = allocated*2;
if (allocated == 0) {
// Initial buffer was not malloced. Do not reallocate it.
bytes old = b;
b.malloc(maxlen);
if (b.len == maxlen)
old.writeTo(b.ptr);
} else {
b.realloc(maxlen);
}
allocated = b.len;
if (allocated != maxlen) {
assert(unpack_aborting());
b.len = nlen-s; // back up
return dummy; // scribble during error recov.
}
// after realloc, recompute pointers
b.len = nlen;
assert(b.len <= allocated);
return limit()-s;
}
void fillbytes::ensureSize(size_t s) {
if (allocated >= s) return;
size_t len0 = b.len;
grow(s - size());
b.len = len0; // put it back
}
int ptrlist::indexOf(const void* x) {
int len = length();
for (int i = 0; i < len; i++) {
if (get(i) == x) return i;
}
return -1;
}
void ptrlist::freeAll() {
int len = length();
for (int i = 0; i < len; i++) {
void* p = (void*) get(i);
if (p != null) {
mtrace('f', p, 0);
::free(p);
}
}
free();
}
int intlist::indexOf(int x) {
int len = length();
for (int i = 0; i < len; i++) {
if (get(i) == x) return i;
}
return -1;
}

View file

@ -1,144 +0,0 @@
/*
* Copyright (c) 2001, 2008, 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.
*/
#ifdef WIN32_LEAN_AND_MEAN
typedef signed char byte ;
#endif
struct bytes {
byte* ptr;
size_t len;
byte* limit() { return ptr+len; }
void set(byte* ptr_, size_t len_) { ptr = ptr_; len = len_; }
void set(const char* str) { ptr = (byte*)str; len = strlen(str); }
bool inBounds(const void* p); // p in [ptr, limit)
void malloc(size_t len_);
void realloc(size_t len_);
void free();
void copyFrom(const void* ptr_, size_t len_, size_t offset = 0);
void saveFrom(const void* ptr_, size_t len_);
void saveFrom(const char* str) { saveFrom(str, strlen(str)); }
void copyFrom(bytes& other, size_t offset = 0) {
copyFrom(other.ptr, other.len, offset);
}
void saveFrom(bytes& other) {
saveFrom(other.ptr, other.len);
}
void clear(int fill_byte = 0) { memset(ptr, fill_byte, len); }
byte* writeTo(byte* bp);
bool equals(bytes& other) { return 0 == compareTo(other); }
int compareTo(bytes& other);
bool contains(byte c) { return indexOf(c) >= 0; }
int indexOf(byte c);
// substrings:
static bytes of(byte* ptr, size_t len) {
bytes res;
res.set(ptr, len);
return res;
}
bytes slice(size_t beg, size_t end) {
bytes res;
res.ptr = ptr + beg;
res.len = end - beg;
assert(res.len == 0 || (inBounds(res.ptr) && inBounds(res.limit()-1)));
return res;
}
// building C strings inside byte buffers:
bytes& strcat(const char* str) { ::strcat((char*)ptr, str); return *this; }
bytes& strcat(bytes& other) { ::strncat((char*)ptr, (char*)other.ptr, other.len); return *this; }
char* strval() { assert(strlen((char*)ptr) == len); return (char*) ptr; }
#ifdef PRODUCT
const char* string() { return 0; }
#else
const char* string();
#endif
};
#define BYTES_OF(var) (bytes::of((byte*)&(var), sizeof(var)))
struct fillbytes {
bytes b;
size_t allocated;
byte* base() { return b.ptr; }
size_t size() { return b.len; }
byte* limit() { return b.limit(); } // logical limit
void setLimit(byte* lp) { assert(isAllocated(lp)); b.len = lp - b.ptr; }
byte* end() { return b.ptr + allocated; } // physical limit
byte* loc(size_t o) { assert(o < b.len); return b.ptr + o; }
void init() { allocated = 0; b.set(null, 0); }
void init(size_t s) { init(); ensureSize(s); }
void free() { if (allocated != 0) b.free(); allocated = 0; }
void empty() { b.len = 0; }
byte* grow(size_t s); // grow so that limit() += s
int getByte(uint i) { return *loc(i) & 0xFF; }
void addByte(byte x) { *grow(1) = x; }
void ensureSize(size_t s); // make sure allocated >= s
void trimToSize() { if (allocated > size()) b.realloc(allocated = size()); }
bool canAppend(size_t s) { return allocated > b.len+s; }
bool isAllocated(byte* p) { return p >= base() && p <= end(); } //asserts
void set(bytes& src) { set(src.ptr, src.len); }
void set(byte* ptr, size_t len) {
b.set(ptr, len);
allocated = 0; // mark as not reallocatable
}
// block operations on resizing byte buffer:
fillbytes& append(const void* ptr_, size_t len_)
{ memcpy(grow(len_), ptr_, len_); return (*this); }
fillbytes& append(bytes& other)
{ return append(other.ptr, other.len); }
fillbytes& append(const char* str)
{ return append(str, strlen(str)); }
};
struct ptrlist : fillbytes {
typedef const void* cvptr;
int length() { return (int)(size() / sizeof(cvptr)); }
cvptr* base() { return (cvptr*) fillbytes::base(); }
cvptr& get(int i) { return *(cvptr*)loc(i * sizeof(cvptr)); }
cvptr* limit() { return (cvptr*) fillbytes::limit(); }
void add(cvptr x) { *(cvptr*)grow(sizeof(x)) = x; }
void popTo(int l) { assert(l <= length()); b.len = l * sizeof(cvptr); }
int indexOf(cvptr x);
bool contains(cvptr x) { return indexOf(x) >= 0; }
void freeAll(); // frees every ptr on the list, plus the list itself
};
// Use a macro rather than mess with subtle mismatches
// between member and non-member function pointers.
#define PTRLIST_QSORT(ptrls, fn) \
::qsort((ptrls).base(), (ptrls).length(), sizeof(void*), fn)
struct intlist : fillbytes {
int length() { return (int)(size() / sizeof(int)); }
int* base() { return (int*) fillbytes::base(); }
int& get(int i) { return *(int*)loc(i * sizeof(int)); }
int* limit() { return (int*) fillbytes::limit(); }
void add(int x) { *(int*)grow(sizeof(x)) = x; }
void popTo(int l) { assert(l <= length()); b.len = l * sizeof(int); }
int indexOf(int x);
bool contains(int x) { return indexOf(x) >= 0; }
};

View file

@ -1,989 +0,0 @@
/*
* Copyright (c) 2002, 2009, 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.
*/
// -*- C++ -*-
// Small program for unpacking specially compressed Java packages.
// John R. Rose
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include "jni_util.h"
#include "defines.h"
#include "bytes.h"
#include "utils.h"
#include "coding.h"
#include "constants.h"
#include "unpack.h"
extern coding basic_codings[];
#define CODING_PRIVATE(spec) \
int spec_ = spec; \
int B = CODING_B(spec_); \
int H = CODING_H(spec_); \
int L = 256 - H; \
int S = CODING_S(spec_); \
int D = CODING_D(spec_)
#define IS_NEG_CODE(S, codeVal) \
( (((int)(codeVal)+1) & ((1<<S)-1)) == 0 )
#define DECODE_SIGN_S1(ux) \
( ((uint)(ux) >> 1) ^ -((int)(ux) & 1) )
static maybe_inline
int decode_sign(int S, uint ux) { // == Coding.decodeSign32
assert(S > 0);
uint sigbits = (ux >> S);
if (IS_NEG_CODE(S, ux))
return (int)( ~sigbits);
else
return (int)(ux - sigbits);
// Note that (int)(ux-sigbits) can be negative, if ux is large enough.
}
coding* coding::init() {
if (umax > 0) return this; // already done
assert(spec != 0); // sanity
// fill in derived fields
CODING_PRIVATE(spec);
// Return null if 'arb(BHSD)' parameter constraints are not met:
if (B < 1 || B > B_MAX) return null;
if (H < 1 || H > 256) return null;
if (S < 0 || S > 2) return null;
if (D < 0 || D > 1) return null;
if (B == 1 && H != 256) return null; // 1-byte coding must be fixed-size
if (B >= 5 && H == 256) return null; // no 5-byte fixed-size coding
// first compute the range of the coding, in 64 bits
jlong range = 0;
{
jlong H_i = 1;
for (int i = 0; i < B; i++) {
range += H_i;
H_i *= H;
}
range *= L;
range += H_i;
}
assert(range > 0); // no useless codings, please
int this_umax;
// now, compute min and max
if (range >= ((jlong)1 << 32)) {
this_umax = INT_MAX_VALUE;
this->umin = INT_MIN_VALUE;
this->max = INT_MAX_VALUE;
this->min = INT_MIN_VALUE;
} else {
this_umax = (range > INT_MAX_VALUE) ? INT_MAX_VALUE : (int)range-1;
this->max = this_umax;
this->min = this->umin = 0;
if (S != 0 && range != 0) {
int Smask = (1<<S)-1;
jlong maxPosCode = range-1;
jlong maxNegCode = range-1;
while (IS_NEG_CODE(S, maxPosCode)) --maxPosCode;
while (!IS_NEG_CODE(S, maxNegCode)) --maxNegCode;
int maxPos = decode_sign(S, (uint)maxPosCode);
if (maxPos < 0)
this->max = INT_MAX_VALUE; // 32-bit wraparound
else
this->max = maxPos;
if (maxNegCode < 0)
this->min = 0; // No negative codings at all.
else
this->min = decode_sign(S, (uint)maxNegCode);
}
}
assert(!(isFullRange | isSigned | isSubrange)); // init
if (min < 0)
this->isSigned = true;
if (max < INT_MAX_VALUE && range <= INT_MAX_VALUE)
this->isSubrange = true;
if (max == INT_MAX_VALUE && min == INT_MIN_VALUE)
this->isFullRange = true;
// do this last, to reduce MT exposure (should have a membar too)
this->umax = this_umax;
return this;
}
coding* coding::findBySpec(int spec) {
for (coding* scan = &basic_codings[0]; ; scan++) {
if (scan->spec == spec)
return scan->init();
if (scan->spec == 0)
break;
}
coding* ptr = NEW(coding, 1);
CHECK_NULL_RETURN(ptr, 0);
coding* c = ptr->initFrom(spec);
if (c == null) {
mtrace('f', ptr, 0);
::free(ptr);
} else
// else caller should free it...
c->isMalloc = true;
return c;
}
coding* coding::findBySpec(int B, int H, int S, int D) {
if (B < 1 || B > B_MAX) return null;
if (H < 1 || H > 256) return null;
if (S < 0 || S > 2) return null;
if (D < 0 || D > 1) return null;
return findBySpec(CODING_SPEC(B, H, S, D));
}
void coding::free() {
if (isMalloc) {
mtrace('f', this, 0);
::free(this);
}
}
void coding_method::reset(value_stream* state) {
assert(state->rp == state->rplimit); // not in mid-stream, please
//assert(this == vs0.cm);
state[0] = vs0;
if (uValues != null) {
uValues->reset(state->helper());
}
}
maybe_inline
uint coding::parse(byte* &rp, int B, int H) {
int L = 256-H;
byte* ptr = rp;
// hand peel the i==0 part of the loop:
uint b_i = *ptr++ & 0xFF;
if (B == 1 || b_i < (uint)L)
{ rp = ptr; return b_i; }
uint sum = b_i;
uint H_i = H;
assert(B <= B_MAX);
for (int i = 2; i <= B_MAX; i++) { // easy for compilers to unroll if desired
b_i = *ptr++ & 0xFF;
sum += b_i * H_i;
if (i == B || b_i < (uint)L)
{ rp = ptr; return sum; }
H_i *= H;
}
assert(false);
return 0;
}
maybe_inline
uint coding::parse_lgH(byte* &rp, int B, int H, int lgH) {
assert(H == (1<<lgH));
int L = 256-(1<<lgH);
byte* ptr = rp;
// hand peel the i==0 part of the loop:
uint b_i = *ptr++ & 0xFF;
if (B == 1 || b_i < (uint)L)
{ rp = ptr; return b_i; }
uint sum = b_i;
uint lg_H_i = lgH;
assert(B <= B_MAX);
for (int i = 2; i <= B_MAX; i++) { // easy for compilers to unroll if desired
b_i = *ptr++ & 0xFF;
sum += b_i << lg_H_i;
if (i == B || b_i < (uint)L)
{ rp = ptr; return sum; }
lg_H_i += lgH;
}
assert(false);
return 0;
}
static const char ERB[] = "EOF reading band";
maybe_inline
void coding::parseMultiple(byte* &rp, int N, byte* limit, int B, int H) {
if (N < 0) {
abort("bad value count");
return;
}
byte* ptr = rp;
if (B == 1 || H == 256) {
size_t len = (size_t)N*B;
if (len / B != (size_t)N || ptr+len > limit) {
abort(ERB);
return;
}
rp = ptr+len;
return;
}
// Note: We assume rp has enough zero-padding.
int L = 256-H;
int n = B;
while (N > 0) {
ptr += 1;
if (--n == 0) {
// end of encoding at B bytes, regardless of byte value
} else {
int b = (ptr[-1] & 0xFF);
if (b >= L) {
// keep going, unless we find a byte < L
continue;
}
}
// found the last byte
N -= 1;
n = B; // reset length counter
// do an error check here
if (ptr > limit) {
abort(ERB);
return;
}
}
rp = ptr;
return;
}
bool value_stream::hasHelper() {
// If my coding method is a pop-style method,
// then I need a second value stream to transmit
// unfavored values.
// This can be determined by examining fValues.
return cm->fValues != null;
}
void value_stream::init(byte* rp_, byte* rplimit_, coding* defc) {
rp = rp_;
rplimit = rplimit_;
sum = 0;
cm = null; // no need in the simple case
setCoding(defc);
}
void value_stream::setCoding(coding* defc) {
if (defc == null) {
unpack_abort("bad coding");
defc = coding::findByIndex(_meta_canon_min); // random pick for recovery
}
c = (*defc);
// choose cmk
cmk = cmk_ERROR;
switch (c.spec) {
case BYTE1_spec: cmk = cmk_BYTE1; break;
case CHAR3_spec: cmk = cmk_CHAR3; break;
case UNSIGNED5_spec: cmk = cmk_UNSIGNED5; break;
case DELTA5_spec: cmk = cmk_DELTA5; break;
case BCI5_spec: cmk = cmk_BCI5; break;
case BRANCH5_spec: cmk = cmk_BRANCH5; break;
default:
if (c.D() == 0) {
switch (c.S()) {
case 0: cmk = cmk_BHS0; break;
case 1: cmk = cmk_BHS1; break;
default: cmk = cmk_BHS; break;
}
} else {
if (c.S() == 1) {
if (c.isFullRange) cmk = cmk_BHS1D1full;
if (c.isSubrange) cmk = cmk_BHS1D1sub;
}
if (cmk == cmk_ERROR) cmk = cmk_BHSD1;
}
}
}
static maybe_inline
int getPopValue(value_stream* self, uint uval) {
if (uval > 0) {
// note that the initial parse performed a range check
assert(uval <= (uint)self->cm->fVlength);
return self->cm->fValues[uval-1];
} else {
// take an unfavored value
return self->helper()->getInt();
}
}
maybe_inline
int coding::sumInUnsignedRange(int x, int y) {
assert(isSubrange);
int range = (int)(umax+1);
assert(range > 0);
x += y;
if (x != (int)((jlong)(x-y) + (jlong)y)) {
// 32-bit overflow interferes with range reduction.
// Back off from the overflow by adding a multiple of range:
if (x < 0) {
x -= range;
assert(x >= 0);
} else {
x += range;
assert(x < 0);
}
}
if (x < 0) {
x += range;
if (x >= 0) return x;
} else if (x >= range) {
x -= range;
if (x < range) return x;
} else {
// in range
return x;
}
// do it the hard way
x %= range;
if (x < 0) x += range;
return x;
}
static maybe_inline
int getDeltaValue(value_stream* self, uint uval, bool isSubrange) {
assert((uint)(self->c.isSubrange) == (uint)isSubrange);
assert(self->c.isSubrange | self->c.isFullRange);
if (isSubrange)
return self->sum = self->c.sumInUnsignedRange(self->sum, (int)uval);
else
return self->sum += (int) uval;
}
bool value_stream::hasValue() {
if (rp < rplimit) return true;
if (cm == null) return false;
if (cm->next == null) return false;
cm->next->reset(this);
return hasValue();
}
int value_stream::getInt() {
if (rp >= rplimit) {
// Advance to next coding segment.
if (rp > rplimit || cm == null || cm->next == null) {
// Must perform this check and throw an exception on bad input.
unpack_abort(ERB);
return 0;
}
cm->next->reset(this);
return getInt();
}
CODING_PRIVATE(c.spec);
uint uval;
enum {
B5 = 5,
B3 = 3,
H128 = 128,
H64 = 64,
H4 = 4
};
switch (cmk) {
case cmk_BHS:
assert(D == 0);
uval = coding::parse(rp, B, H);
if (S == 0)
return (int) uval;
return decode_sign(S, uval);
case cmk_BHS0:
assert(S == 0 && D == 0);
uval = coding::parse(rp, B, H);
return (int) uval;
case cmk_BHS1:
assert(S == 1 && D == 0);
uval = coding::parse(rp, B, H);
return DECODE_SIGN_S1(uval);
case cmk_BYTE1:
assert(c.spec == BYTE1_spec);
assert(B == 1 && H == 256 && S == 0 && D == 0);
return *rp++ & 0xFF;
case cmk_CHAR3:
assert(c.spec == CHAR3_spec);
assert(B == B3 && H == H128 && S == 0 && D == 0);
return coding::parse_lgH(rp, B3, H128, 7);
case cmk_UNSIGNED5:
assert(c.spec == UNSIGNED5_spec);
assert(B == B5 && H == H64 && S == 0 && D == 0);
return coding::parse_lgH(rp, B5, H64, 6);
case cmk_BHSD1:
assert(D == 1);
uval = coding::parse(rp, B, H);
if (S != 0)
uval = (uint) decode_sign(S, uval);
return getDeltaValue(this, uval, (bool)c.isSubrange);
case cmk_BHS1D1full:
assert(S == 1 && D == 1 && c.isFullRange);
uval = coding::parse(rp, B, H);
uval = (uint) DECODE_SIGN_S1(uval);
return getDeltaValue(this, uval, false);
case cmk_BHS1D1sub:
assert(S == 1 && D == 1 && c.isSubrange);
uval = coding::parse(rp, B, H);
uval = (uint) DECODE_SIGN_S1(uval);
return getDeltaValue(this, uval, true);
case cmk_DELTA5:
assert(c.spec == DELTA5_spec);
assert(B == B5 && H == H64 && S == 1 && D == 1 && c.isFullRange);
uval = coding::parse_lgH(rp, B5, H64, 6);
sum += DECODE_SIGN_S1(uval);
return sum;
case cmk_BCI5:
assert(c.spec == BCI5_spec);
assert(B == B5 && H == H4 && S == 0 && D == 0);
return coding::parse_lgH(rp, B5, H4, 2);
case cmk_BRANCH5:
assert(c.spec == BRANCH5_spec);
assert(B == B5 && H == H4 && S == 2 && D == 0);
uval = coding::parse_lgH(rp, B5, H4, 2);
return decode_sign(S, uval);
case cmk_pop:
uval = coding::parse(rp, B, H);
if (S != 0) {
uval = (uint) decode_sign(S, uval);
}
if (D != 0) {
assert(c.isSubrange | c.isFullRange);
if (c.isSubrange)
sum = c.sumInUnsignedRange(sum, (int) uval);
else
sum += (int) uval;
uval = (uint) sum;
}
return getPopValue(this, uval);
case cmk_pop_BHS0:
assert(S == 0 && D == 0);
uval = coding::parse(rp, B, H);
return getPopValue(this, uval);
case cmk_pop_BYTE1:
assert(c.spec == BYTE1_spec);
assert(B == 1 && H == 256 && S == 0 && D == 0);
return getPopValue(this, *rp++ & 0xFF);
default:
break;
}
assert(false);
return 0;
}
static maybe_inline
int moreCentral(int x, int y) { // used to find end of Pop.{F}
// Suggested implementation from the Pack200 specification:
uint kx = (x >> 31) ^ (x << 1);
uint ky = (y >> 31) ^ (y << 1);
return (kx < ky? x: y);
}
//static maybe_inline
//int moreCentral2(int x, int y, int min) {
// // Strict implementation of buggy 150.7 specification.
// // The bug is that the spec. says absolute-value ties are broken
// // in favor of positive numbers, but the suggested implementation
// // (also mentioned in the spec.) breaks ties in favor of negative numbers.
// if ((x + y) != 0)
// return min;
// else
// // return the other value, which breaks a tie in the positive direction
// return (x > y)? x: y;
//}
static const byte* no_meta[] = {null};
#define NO_META (*(byte**)no_meta)
enum { POP_FAVORED_N = -2 };
// mode bits
#define DISABLE_RUN 1 // used immediately inside ACodee
#define DISABLE_POP 2 // used recursively in all pop sub-bands
// This function knows all about meta-coding.
void coding_method::init(byte* &band_rp, byte* band_limit,
byte* &meta_rp, int mode,
coding* defc, int N,
intlist* valueSink) {
assert(N != 0);
assert(u != null); // must be pre-initialized
//if (u == null) u = unpacker::current(); // expensive
int op = (meta_rp == null) ? _meta_default : (*meta_rp++ & 0xFF);
coding* foundc = null;
coding* to_free = null;
if (op == _meta_default) {
foundc = defc;
// and fall through
} else if (op >= _meta_canon_min && op <= _meta_canon_max) {
foundc = coding::findByIndex(op);
// and fall through
} else if (op == _meta_arb) {
int args = (*meta_rp++ & 0xFF);
// args = (D:[0..1] + 2*S[0..2] + 8*(B:[1..5]-1))
int D = ((args >> 0) & 1);
int S = ((args >> 1) & 3);
int B = ((args >> 3) & -1) + 1;
// & (H[1..256]-1)
int H = (*meta_rp++ & 0xFF) + 1;
foundc = coding::findBySpec(B, H, S, D);
to_free = foundc; // findBySpec may dynamically allocate
if (foundc == null) {
abort("illegal arb. coding");
return;
}
// and fall through
} else if (op >= _meta_run && op < _meta_pop) {
int args = (op - _meta_run);
// args: KX:[0..3] + 4*(KBFlag:[0..1]) + 8*(ABDef:[0..2])
int KX = ((args >> 0) & 3);
int KBFlag = ((args >> 2) & 1);
int ABDef = ((args >> 3) & -1);
assert(ABDef <= 2);
// & KB: one of [0..255] if KBFlag=1
int KB = (!KBFlag? 3: (*meta_rp++ & 0xFF));
int K = (KB+1) << (KX * 4);
int N2 = (N >= 0) ? N-K : N;
if (N == 0 || (N2 <= 0 && N2 != N)) {
abort("illegal run encoding");
return;
}
if ((mode & DISABLE_RUN) != 0) {
abort("illegal nested run encoding");
return;
}
// & Enc{ ACode } if ADef=0 (ABDef != 1)
// No direct nesting of 'run' in ACode, but in BCode it's OK.
int disRun = mode | DISABLE_RUN;
if (ABDef == 1) {
this->init(band_rp, band_limit, NO_META, disRun, defc, K, valueSink);
} else {
this->init(band_rp, band_limit, meta_rp, disRun, defc, K, valueSink);
}
CHECK;
// & Enc{ BCode } if BDef=0 (ABDef != 2)
coding_method* tail = U_NEW(coding_method, 1);
CHECK_NULL(tail);
tail->u = u;
// The 'run' codings may be nested indirectly via 'pop' codings.
// This means that this->next may already be filled in, if
// ACode was of type 'pop' with a 'run' token coding.
// No problem: Just chain the upcoming BCode onto the end.
for (coding_method* self = this; ; self = self->next) {
if (self->next == null) {
self->next = tail;
break;
}
}
if (ABDef == 2) {
tail->init(band_rp, band_limit, NO_META, mode, defc, N2, valueSink);
} else {
tail->init(band_rp, band_limit, meta_rp, mode, defc, N2, valueSink);
}
// Note: The preceding calls to init should be tail-recursive.
return; // done; no falling through
} else if (op >= _meta_pop && op < _meta_limit) {
int args = (op - _meta_pop);
// args: (FDef:[0..1]) + 2*UDef:[0..1] + 4*(TDefL:[0..11])
int FDef = ((args >> 0) & 1);
int UDef = ((args >> 1) & 1);
int TDefL = ((args >> 2) & -1);
assert(TDefL <= 11);
int TDef = (TDefL > 0);
int TL = (TDefL <= 6) ? (2 << TDefL) : (256 - (4 << (11-TDefL)));
int TH = (256-TL);
if (N <= 0) {
abort("illegal pop encoding");
return;
}
if ((mode & DISABLE_POP) != 0) {
abort("illegal nested pop encoding");
return;
}
// No indirect nesting of 'pop', but 'run' is OK.
int disPop = DISABLE_POP;
// & Enc{ FCode } if FDef=0
int FN = POP_FAVORED_N;
assert(valueSink == null);
intlist fValueSink; fValueSink.init();
coding_method fval;
BYTES_OF(fval).clear(); fval.u = u;
if (FDef != 0) {
fval.init(band_rp, band_limit, NO_META, disPop, defc, FN, &fValueSink);
} else {
fval.init(band_rp, band_limit, meta_rp, disPop, defc, FN, &fValueSink);
}
bytes fvbuf;
fValues = (u->saveTo(fvbuf, fValueSink.b), (int*) fvbuf.ptr);
fVlength = fValueSink.length(); // i.e., the parameter K
fValueSink.free();
CHECK;
// Skip the first {F} run in all subsequent passes.
// The next call to this->init(...) will set vs0.rp to point after the {F}.
// & Enc{ TCode } if TDef=0 (TDefL==0)
if (TDef != 0) {
coding* tcode = coding::findBySpec(1, 256); // BYTE1
// find the most narrowly sufficient code:
for (int B = 2; B <= B_MAX; B++) {
if (fVlength <= tcode->umax) break; // found it
tcode->free();
tcode = coding::findBySpec(B, TH);
CHECK_NULL(tcode);
}
if (!(fVlength <= tcode->umax)) {
abort("pop.L value too small");
return;
}
this->init(band_rp, band_limit, NO_META, disPop, tcode, N, null);
tcode->free();
} else {
this->init(band_rp, band_limit, meta_rp, disPop, defc, N, null);
}
CHECK;
// Count the number of zero tokens right now.
// Also verify that they are in bounds.
int UN = 0; // one {U} for each zero in {T}
value_stream vs = vs0;
for (int i = 0; i < N; i++) {
uint val = vs.getInt();
if (val == 0) UN += 1;
if (!(val <= (uint)fVlength)) {
abort("pop token out of range");
return;
}
}
vs.done();
// & Enc{ UCode } if UDef=0
if (UN != 0) {
uValues = U_NEW(coding_method, 1);
CHECK_NULL(uValues);
uValues->u = u;
if (UDef != 0) {
uValues->init(band_rp, band_limit, NO_META, disPop, defc, UN, null);
} else {
uValues->init(band_rp, band_limit, meta_rp, disPop, defc, UN, null);
}
} else {
if (UDef == 0) {
int uop = (*meta_rp++ & 0xFF);
if (uop > _meta_canon_max)
// %%% Spec. requires the more strict (uop != _meta_default).
abort("bad meta-coding for empty pop/U");
}
}
// Bug fix for 6259542
// Last of all, adjust vs0.cmk to the 'pop' flavor
for (coding_method* self = this; self != null; self = self->next) {
coding_method_kind cmk2 = cmk_pop;
switch (self->vs0.cmk) {
case cmk_BHS0: cmk2 = cmk_pop_BHS0; break;
case cmk_BYTE1: cmk2 = cmk_pop_BYTE1; break;
default: break;
}
self->vs0.cmk = cmk2;
if (self != this) {
assert(self->fValues == null); // no double init
self->fValues = this->fValues;
self->fVlength = this->fVlength;
assert(self->uValues == null); // must stay null
}
}
return; // done; no falling through
} else {
abort("bad meta-coding");
return;
}
// Common code here skips a series of values with one coding.
assert(foundc != null);
assert(vs0.cmk == cmk_ERROR); // no garbage, please
assert(vs0.rp == null); // no garbage, please
assert(vs0.rplimit == null); // no garbage, please
assert(vs0.sum == 0); // no garbage, please
vs0.init(band_rp, band_limit, foundc);
// Done with foundc. Free if necessary.
if (to_free != null) {
to_free->free();
to_free = null;
}
foundc = null;
coding& c = vs0.c;
CODING_PRIVATE(c.spec);
// assert sane N
assert((uint)N < INT_MAX_VALUE || N == POP_FAVORED_N);
// Look at the values, or at least skip over them quickly.
if (valueSink == null) {
// Skip and ignore values in the first pass.
c.parseMultiple(band_rp, N, band_limit, B, H);
} else if (N >= 0) {
// Pop coding, {F} sequence, initial run of values...
assert((mode & DISABLE_POP) != 0);
value_stream vs = vs0;
for (int n = 0; n < N; n++) {
int val = vs.getInt();
valueSink->add(val);
}
band_rp = vs.rp;
} else {
// Pop coding, {F} sequence, final run of values...
assert((mode & DISABLE_POP) != 0);
assert(N == POP_FAVORED_N);
int min = INT_MIN_VALUE; // farthest from the center
// min2 is based on the buggy specification of centrality in version 150.7
// no known implementations transmit this value, but just in case...
//int min2 = INT_MIN_VALUE;
int last = 0;
// if there were initial runs, find the potential sentinels in them:
for (int i = 0; i < valueSink->length(); i++) {
last = valueSink->get(i);
min = moreCentral(min, last);
//min2 = moreCentral2(min2, last, min);
}
value_stream vs = vs0;
for (;;) {
int val = vs.getInt();
if (valueSink->length() > 0 &&
(val == last || val == min)) //|| val == min2
break;
valueSink->add(val);
CHECK;
last = val;
min = moreCentral(min, last);
//min2 = moreCentral2(min2, last, min);
}
band_rp = vs.rp;
}
CHECK;
// Get an accurate upper limit now.
vs0.rplimit = band_rp;
vs0.cm = this;
return; // success
}
coding basic_codings[] = {
// This one is not a usable irregular coding, but is used by cp_Utf8_chars.
CODING_INIT(3,128,0,0),
// Fixed-length codings:
CODING_INIT(1,256,0,0),
CODING_INIT(1,256,1,0),
CODING_INIT(1,256,0,1),
CODING_INIT(1,256,1,1),
CODING_INIT(2,256,0,0),
CODING_INIT(2,256,1,0),
CODING_INIT(2,256,0,1),
CODING_INIT(2,256,1,1),
CODING_INIT(3,256,0,0),
CODING_INIT(3,256,1,0),
CODING_INIT(3,256,0,1),
CODING_INIT(3,256,1,1),
CODING_INIT(4,256,0,0),
CODING_INIT(4,256,1,0),
CODING_INIT(4,256,0,1),
CODING_INIT(4,256,1,1),
// Full-range variable-length codings:
CODING_INIT(5, 4,0,0),
CODING_INIT(5, 4,1,0),
CODING_INIT(5, 4,2,0),
CODING_INIT(5, 16,0,0),
CODING_INIT(5, 16,1,0),
CODING_INIT(5, 16,2,0),
CODING_INIT(5, 32,0,0),
CODING_INIT(5, 32,1,0),
CODING_INIT(5, 32,2,0),
CODING_INIT(5, 64,0,0),
CODING_INIT(5, 64,1,0),
CODING_INIT(5, 64,2,0),
CODING_INIT(5,128,0,0),
CODING_INIT(5,128,1,0),
CODING_INIT(5,128,2,0),
CODING_INIT(5, 4,0,1),
CODING_INIT(5, 4,1,1),
CODING_INIT(5, 4,2,1),
CODING_INIT(5, 16,0,1),
CODING_INIT(5, 16,1,1),
CODING_INIT(5, 16,2,1),
CODING_INIT(5, 32,0,1),
CODING_INIT(5, 32,1,1),
CODING_INIT(5, 32,2,1),
CODING_INIT(5, 64,0,1),
CODING_INIT(5, 64,1,1),
CODING_INIT(5, 64,2,1),
CODING_INIT(5,128,0,1),
CODING_INIT(5,128,1,1),
CODING_INIT(5,128,2,1),
// Variable length subrange codings:
CODING_INIT(2,192,0,0),
CODING_INIT(2,224,0,0),
CODING_INIT(2,240,0,0),
CODING_INIT(2,248,0,0),
CODING_INIT(2,252,0,0),
CODING_INIT(2, 8,0,1),
CODING_INIT(2, 8,1,1),
CODING_INIT(2, 16,0,1),
CODING_INIT(2, 16,1,1),
CODING_INIT(2, 32,0,1),
CODING_INIT(2, 32,1,1),
CODING_INIT(2, 64,0,1),
CODING_INIT(2, 64,1,1),
CODING_INIT(2,128,0,1),
CODING_INIT(2,128,1,1),
CODING_INIT(2,192,0,1),
CODING_INIT(2,192,1,1),
CODING_INIT(2,224,0,1),
CODING_INIT(2,224,1,1),
CODING_INIT(2,240,0,1),
CODING_INIT(2,240,1,1),
CODING_INIT(2,248,0,1),
CODING_INIT(2,248,1,1),
CODING_INIT(3,192,0,0),
CODING_INIT(3,224,0,0),
CODING_INIT(3,240,0,0),
CODING_INIT(3,248,0,0),
CODING_INIT(3,252,0,0),
CODING_INIT(3, 8,0,1),
CODING_INIT(3, 8,1,1),
CODING_INIT(3, 16,0,1),
CODING_INIT(3, 16,1,1),
CODING_INIT(3, 32,0,1),
CODING_INIT(3, 32,1,1),
CODING_INIT(3, 64,0,1),
CODING_INIT(3, 64,1,1),
CODING_INIT(3,128,0,1),
CODING_INIT(3,128,1,1),
CODING_INIT(3,192,0,1),
CODING_INIT(3,192,1,1),
CODING_INIT(3,224,0,1),
CODING_INIT(3,224,1,1),
CODING_INIT(3,240,0,1),
CODING_INIT(3,240,1,1),
CODING_INIT(3,248,0,1),
CODING_INIT(3,248,1,1),
CODING_INIT(4,192,0,0),
CODING_INIT(4,224,0,0),
CODING_INIT(4,240,0,0),
CODING_INIT(4,248,0,0),
CODING_INIT(4,252,0,0),
CODING_INIT(4, 8,0,1),
CODING_INIT(4, 8,1,1),
CODING_INIT(4, 16,0,1),
CODING_INIT(4, 16,1,1),
CODING_INIT(4, 32,0,1),
CODING_INIT(4, 32,1,1),
CODING_INIT(4, 64,0,1),
CODING_INIT(4, 64,1,1),
CODING_INIT(4,128,0,1),
CODING_INIT(4,128,1,1),
CODING_INIT(4,192,0,1),
CODING_INIT(4,192,1,1),
CODING_INIT(4,224,0,1),
CODING_INIT(4,224,1,1),
CODING_INIT(4,240,0,1),
CODING_INIT(4,240,1,1),
CODING_INIT(4,248,0,1),
CODING_INIT(4,248,1,1),
CODING_INIT(0,0,0,0)
};
#define BASIC_INDEX_LIMIT \
(int)(sizeof(basic_codings)/sizeof(basic_codings[0])-1)
coding* coding::findByIndex(int idx) {
#ifndef PRODUCT
/* Tricky assert here, constants and gcc complains about it without local. */
int index_limit = BASIC_INDEX_LIMIT;
assert(_meta_canon_min == 1 && _meta_canon_max+1 == index_limit);
#endif
if (idx >= _meta_canon_min && idx <= _meta_canon_max)
return basic_codings[idx].init();
else
return null;
}
#ifndef PRODUCT
const char* coding::string() {
CODING_PRIVATE(spec);
bytes buf;
buf.malloc(100);
char maxS[20], minS[20];
sprintf(maxS, "%d", max);
sprintf(minS, "%d", min);
if (max == INT_MAX_VALUE) strcpy(maxS, "max");
if (min == INT_MIN_VALUE) strcpy(minS, "min");
sprintf((char*)buf.ptr, "(%d,%d,%d,%d) L=%d r=[%s,%s]",
B,H,S,D,L,minS,maxS);
return (const char*) buf.ptr;
}
#endif

View file

@ -1,226 +0,0 @@
/*
* Copyright (c) 2002, 2008, 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.
*/
struct unpacker;
#define INT_MAX_VALUE ((int)0x7FFFFFFF)
#define INT_MIN_VALUE ((int)0x80000000)
#define CODING_SPEC(B, H, S, D) ((B)<<20|(H)<<8|(S)<<4|(D)<<0)
#define CODING_B(x) ((x)>>20 & 0xF)
#define CODING_H(x) ((x)>>8 & 0xFFF)
#define CODING_S(x) ((x)>>4 & 0xF)
#define CODING_D(x) ((x)>>0 & 0xF)
#define CODING_INIT(B, H, S, D) \
{ CODING_SPEC(B, H, S, D) , 0, 0, 0, 0, 0, 0, 0, 0}
// For debugging purposes, some compilers do not like this and will complain.
// #define long do_not_use_C_long_types_use_jlong_or_int
// Use of the type "long" is problematic, do not use it.
struct coding {
int spec; // B,H,S,D
// Handy values derived from the spec:
int B() { return CODING_B(spec); }
int H() { return CODING_H(spec); }
int S() { return CODING_S(spec); }
int D() { return CODING_D(spec); }
int L() { return 256-CODING_H(spec); }
int min, max;
int umin, umax;
char isSigned, isSubrange, isFullRange, isMalloc;
coding* init(); // returns self or null if error
coding* initFrom(int spec_) {
assert(this->spec == 0);
this->spec = spec_;
return init();
}
static coding* findBySpec(int spec);
static coding* findBySpec(int B, int H, int S=0, int D=0);
static coding* findByIndex(int irregularCodingIndex);
static uint parse(byte* &rp, int B, int H);
static uint parse_lgH(byte* &rp, int B, int H, int lgH);
static void parseMultiple(byte* &rp, int N, byte* limit, int B, int H);
uint parse(byte* &rp) {
return parse(rp, CODING_B(spec), CODING_H(spec));
}
void parseMultiple(byte* &rp, int N, byte* limit) {
parseMultiple(rp, N, limit, CODING_B(spec), CODING_H(spec));
}
bool canRepresent(int x) { return (x >= min && x <= max); }
bool canRepresentUnsigned(int x) { return (x >= umin && x <= umax); }
int sumInUnsignedRange(int x, int y);
int readFrom(byte* &rpVar, int* dbase);
void readArrayFrom(byte* &rpVar, int* dbase, int length, int* values);
void skipArrayFrom(byte* &rpVar, int length) {
readArrayFrom(rpVar, (int*)NULL, length, (int*)NULL);
}
#ifndef PRODUCT
const char* string();
#endif
void free(); // free self if isMalloc
// error handling
static void abort(const char* msg = null) { unpack_abort(msg); }
};
enum coding_method_kind {
cmk_ERROR,
cmk_BHS,
cmk_BHS0,
cmk_BHS1,
cmk_BHSD1,
cmk_BHS1D1full, // isFullRange
cmk_BHS1D1sub, // isSubRange
// special cases hand-optimized (~50% of all decoded values)
cmk_BYTE1, //(1,256) 6%
cmk_CHAR3, //(3,128) 7%
cmk_UNSIGNED5, //(5,64) 13%
cmk_DELTA5, //(5,64,1,1) 5%
cmk_BCI5, //(5,4) 18%
cmk_BRANCH5, //(5,4,2) 4%
//cmk_UNSIGNED5H16, //(5,16) 5%
//cmk_UNSIGNED2H4, //(2,4) 6%
//cmk_DELTA4H8, //(4,8,1,1) 10%
//cmk_DELTA3H16, //(3,16,1,1) 9%
cmk_BHS_LIMIT,
cmk_pop,
cmk_pop_BHS0,
cmk_pop_BYTE1,
cmk_pop_LIMIT,
cmk_LIMIT
};
enum {
BYTE1_spec = CODING_SPEC(1, 256, 0, 0),
CHAR3_spec = CODING_SPEC(3, 128, 0, 0),
UNSIGNED4_spec = CODING_SPEC(4, 256, 0, 0),
UNSIGNED5_spec = CODING_SPEC(5, 64, 0, 0),
SIGNED5_spec = CODING_SPEC(5, 64, 1, 0),
DELTA5_spec = CODING_SPEC(5, 64, 1, 1),
UDELTA5_spec = CODING_SPEC(5, 64, 0, 1),
MDELTA5_spec = CODING_SPEC(5, 64, 2, 1),
BCI5_spec = CODING_SPEC(5, 4, 0, 0),
BRANCH5_spec = CODING_SPEC(5, 4, 2, 0)
};
enum {
B_MAX = 5,
C_SLOP = B_MAX*10
};
struct coding_method;
// iterator under the control of a meta-coding
struct value_stream {
// current coding of values or values
coding c; // B,H,S,D,etc.
coding_method_kind cmk; // type of decoding needed
byte* rp; // read pointer
byte* rplimit; // final value of read pointer
int sum; // partial sum of all values so far (D=1 only)
coding_method* cm; // coding method that defines this stream
void init(byte* band_rp, byte* band_limit, coding* defc);
void init(byte* band_rp, byte* band_limit, int spec)
{ init(band_rp, band_limit, coding::findBySpec(spec)); }
void setCoding(coding* c);
void setCoding(int spec) { setCoding(coding::findBySpec(spec)); }
// Parse and decode a single value.
int getInt();
// Parse and decode a single byte, with no error checks.
int getByte() {
assert(cmk == cmk_BYTE1);
assert(rp < rplimit);
return *rp++ & 0xFF;
}
// Used only for asserts.
bool hasValue();
void done() { assert(!hasValue()); }
// Sometimes a value stream has an auxiliary (but there are never two).
value_stream* helper() {
assert(hasHelper());
return this+1;
}
bool hasHelper();
// error handling
// inline void abort(const char* msg);
// inline void aborting();
};
struct coding_method {
value_stream vs0; // initial state snapshot (vs.meta==this)
coding_method* next; // what to do when we run out of bytes
// these fields are used for pop codes only:
int* fValues; // favored value array
int fVlength; // maximum favored value token
coding_method* uValues; // unfavored value stream
// pointer to outer unpacker, for error checks etc.
unpacker* u;
// Initialize a value stream.
void reset(value_stream* state);
// Parse a band header, size a band, and initialize for further action.
// band_rp advances (but not past band_limit), and meta_rp advances.
// The mode gives context, such as "inside a pop".
// The defc and N are the incoming parameters to a meta-coding.
// The value sink is used to collect output values, when desired.
void init(byte* &band_rp, byte* band_limit,
byte* &meta_rp, int mode,
coding* defc, int N,
intlist* valueSink);
// error handling
void abort(const char* msg) { unpack_abort(msg, u); }
bool aborting() { return unpack_aborting(u); }
};
//inline void value_stream::abort(const char* msg) { cm->abort(msg); }
//inline void value_stream::aborting() { cm->aborting(); }

View file

@ -1,497 +0,0 @@
/*
* Copyright (c) 2001, 2016, 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.
*/
// classfile constants
#define JAVA_MAGIC 0xCAFEBABE
// Class version history, refer to Constants.java
// package file constants
#define JAVA_PACKAGE_MAGIC 0xCAFED00D
#define JAVA5_PACKAGE_MAJOR_VERSION 150
#define JAVA5_PACKAGE_MINOR_VERSION 7
#define JAVA6_PACKAGE_MAJOR_VERSION 160
#define JAVA6_PACKAGE_MINOR_VERSION 1
#define JAVA7_PACKAGE_MAJOR_VERSION 170
#define JAVA7_PACKAGE_MINOR_VERSION 1
#define JAVA8_PACKAGE_MAJOR_VERSION 171
#define JAVA8_PACKAGE_MINOR_VERSION 0
// magic number for gzip streams (for processing pack200-gzip data)
#define GZIP_MAGIC 0x1F8B0800
#define GZIP_MAGIC_MASK 0xFFFFFF00 // last byte is variable "flg" field
enum {
CONSTANT_None = 0,
CONSTANT_Utf8 = 1,
CONSTANT_unused = 2, /* unused, was Unicode */
CONSTANT_Integer = 3,
CONSTANT_Float = 4,
CONSTANT_Long = 5,
CONSTANT_Double = 6,
CONSTANT_Class = 7,
CONSTANT_String = 8,
CONSTANT_Fieldref = 9,
CONSTANT_Methodref = 10,
CONSTANT_InterfaceMethodref = 11,
CONSTANT_NameandType = 12,
CONSTANT_unused13 = 13,
CONSTANT_unused14 = 14,
CONSTANT_MethodHandle = 15,
CONSTANT_MethodType = 16,
CONSTANT_unused17 = 17,
CONSTANT_InvokeDynamic = 18,
CONSTANT_Limit = 19,
CONSTANT_Signature = CONSTANT_unused13,
CONSTANT_BootstrapMethod = CONSTANT_unused17, // used only for InvokeDynamic
CONSTANT_All = 50, // combined global map
CONSTANT_LoadableValue = 51, // used for 'KL' and qldc operands
CONSTANT_AnyMember = 52, // union of refs to field or (interface) method
CONSTANT_FieldSpecific = 53, // used only for 'KQ' ConstantValue attrs
CONSTANT_GroupFirst = CONSTANT_All, // start group marker
CONSTANT_GroupLimit = 54, // end group marker
// CONSTANT_MethodHandle reference kinds
REF_getField = 1,
REF_getStatic = 2,
REF_putField = 3,
REF_putStatic = 4,
REF_invokeVirtual = 5,
REF_invokeStatic = 6,
REF_invokeSpecial = 7,
REF_newInvokeSpecial = 8,
REF_invokeInterface = 9,
SUBINDEX_BIT = 64, // combined with CONSTANT_xxx for ixTag
ACC_STATIC = 0x0008,
ACC_IC_LONG_FORM = (1<<16), //for ic_flags
CLASS_ATTR_SourceFile = 17,
CLASS_ATTR_EnclosingMethod = 18,
CLASS_ATTR_InnerClasses = 23,
CLASS_ATTR_ClassFile_version = 24,
CLASS_ATTR_BootstrapMethods = 25,
FIELD_ATTR_ConstantValue = 17,
METHOD_ATTR_Code = 17,
METHOD_ATTR_Exceptions = 18,
METHOD_ATTR_RuntimeVisibleParameterAnnotations = 23,
METHOD_ATTR_RuntimeInvisibleParameterAnnotations = 24,
METHOD_ATTR_AnnotationDefault = 25,
METHOD_ATTR_MethodParameters = 26,
CODE_ATTR_StackMapTable = 0,
CODE_ATTR_LineNumberTable = 1,
CODE_ATTR_LocalVariableTable = 2,
CODE_ATTR_LocalVariableTypeTable = 3,
//X_ATTR_Synthetic = 12, // ACC_SYNTHETIC; not predefined
X_ATTR_Signature = 19,
X_ATTR_Deprecated = 20,
X_ATTR_RuntimeVisibleAnnotations = 21,
X_ATTR_RuntimeInvisibleAnnotations = 22,
X_ATTR_RuntimeVisibleTypeAnnotations = 27,
X_ATTR_RuntimeInvisibleTypeAnnotations = 28,
X_ATTR_OVERFLOW = 16,
X_ATTR_LIMIT_NO_FLAGS_HI = 32,
X_ATTR_LIMIT_FLAGS_HI = 63,
#define O_ATTR_DO(F) \
F(X_ATTR_OVERFLOW,01) \
/*(end)*/
#define X_ATTR_DO(F) \
O_ATTR_DO(F) \
F(X_ATTR_Signature,Signature) \
F(X_ATTR_Deprecated,Deprecated) \
F(X_ATTR_RuntimeVisibleAnnotations,RuntimeVisibleAnnotations) \
F(X_ATTR_RuntimeInvisibleAnnotations,RuntimeInvisibleAnnotations) \
F(X_ATTR_RuntimeVisibleTypeAnnotations,RuntimeVisibleTypeAnnotations) \
F(X_ATTR_RuntimeInvisibleTypeAnnotations,RuntimeInvisibleTypeAnnotations) \
/*F(X_ATTR_Synthetic,Synthetic)*/ \
/*(end)*/
#define CLASS_ATTR_DO(F) \
F(CLASS_ATTR_SourceFile,SourceFile) \
F(CLASS_ATTR_InnerClasses,InnerClasses) \
F(CLASS_ATTR_EnclosingMethod,EnclosingMethod) \
F(CLASS_ATTR_ClassFile_version,02) \
F(CLASS_ATTR_BootstrapMethods,BootstrapMethods) \
/*(end)*/
#define FIELD_ATTR_DO(F) \
F(FIELD_ATTR_ConstantValue,ConstantValue) \
/*(end)*/
#define METHOD_ATTR_DO(F) \
F(METHOD_ATTR_Code,Code) \
F(METHOD_ATTR_Exceptions,Exceptions) \
F(METHOD_ATTR_RuntimeVisibleParameterAnnotations,RuntimeVisibleParameterAnnotations) \
F(METHOD_ATTR_RuntimeInvisibleParameterAnnotations,RuntimeInvisibleParameterAnnotations) \
F(METHOD_ATTR_AnnotationDefault,AnnotationDefault) \
F(METHOD_ATTR_MethodParameters,MethodParameters) \
/*(end)*/
#define CODE_ATTR_DO(F) \
F(CODE_ATTR_StackMapTable,StackMapTable) \
F(CODE_ATTR_LineNumberTable,LineNumberTable) \
F(CODE_ATTR_LocalVariableTable,LocalVariableTable) \
F(CODE_ATTR_LocalVariableTypeTable,LocalVariableTypeTable) \
/*(end)*/
#define ALL_ATTR_DO(F) \
X_ATTR_DO(F) \
CLASS_ATTR_DO(F) \
FIELD_ATTR_DO(F) \
METHOD_ATTR_DO(F) \
CODE_ATTR_DO(F) \
/*(end)*/
// attribute "context types"
ATTR_CONTEXT_CLASS = 0,
ATTR_CONTEXT_FIELD = 1,
ATTR_CONTEXT_METHOD = 2,
ATTR_CONTEXT_CODE = 3,
ATTR_CONTEXT_LIMIT = 4,
// constants for parsed layouts (stored in band::le_kind)
EK_NONE = 0, // not a layout element
EK_INT = 'I', // B H I SH etc., also FH etc.
EK_BCI = 'P', // PH etc.
EK_BCID = 'Q', // POH etc.
EK_BCO = 'O', // OH etc.
EK_REPL = 'N', // NH[...] etc.
EK_REF = 'R', // RUH, RUNH, KQH, etc.
EK_UN = 'T', // TB(...)[...] etc.
EK_CASE = 'K', // (...)[...] etc.
EK_CALL = '(', // (0), (1), etc.
EK_CBLE = '[', // [...][...] etc.
NO_BAND_INDEX = -1,
// File option bits, from LSB in ascending bit position.
FO_DEFLATE_HINT = 1<<0,
FO_IS_CLASS_STUB = 1<<1,
// Archive option bits, from LSB in ascending bit position:
AO_HAVE_SPECIAL_FORMATS = 1<<0,
AO_HAVE_CP_NUMBERS = 1<<1,
AO_HAVE_ALL_CODE_FLAGS = 1<<2,
AO_HAVE_CP_EXTRAS = 1<<3,
AO_HAVE_FILE_HEADERS = 1<<4,
AO_DEFLATE_HINT = 1<<5,
AO_HAVE_FILE_MODTIME = 1<<6,
AO_HAVE_FILE_OPTIONS = 1<<7,
AO_HAVE_FILE_SIZE_HI = 1<<8,
AO_HAVE_CLASS_FLAGS_HI = 1<<9,
AO_HAVE_FIELD_FLAGS_HI = 1<<10,
AO_HAVE_METHOD_FLAGS_HI = 1<<11,
AO_HAVE_CODE_FLAGS_HI = 1<<12,
AO_UNUSED_MBZ = (int)((~0U)<<13), // options bits reserved for future use.
#define ARCHIVE_BIT_DO(F) \
F(AO_HAVE_SPECIAL_FORMATS) \
F(AO_HAVE_CP_NUMBERS) \
F(AO_HAVE_ALL_CODE_FLAGS) \
F(AO_HAVE_CP_EXTRAS) \
F(AO_HAVE_FILE_HEADERS) \
F(AO_DEFLATE_HINT) \
F(AO_HAVE_FILE_MODTIME) \
F(AO_HAVE_FILE_OPTIONS) \
F(AO_HAVE_FILE_SIZE_HI) \
F(AO_HAVE_CLASS_FLAGS_HI) \
F(AO_HAVE_FIELD_FLAGS_HI) \
F(AO_HAVE_METHOD_FLAGS_HI) \
F(AO_HAVE_CODE_FLAGS_HI) \
/*(end)*/
// Constants for decoding attribute definition header bytes.
ADH_CONTEXT_MASK = 0x3, // (hdr & ADH_CONTEXT_MASK)
ADH_BIT_SHIFT = 0x2, // (hdr >> ADH_BIT_SHIFT)
ADH_BIT_IS_LSB = 1, // (hdr >> ADH_BIT_SHIFT) - ADH_BIT_IS_LSB
#define ADH_BYTE(context, index) \
((((index) + ADH_BIT_IS_LSB)<<ADH_BIT_SHIFT) + (context))
#define ADH_BYTE_CONTEXT(adhb) \
((adhb) & ADH_CONTEXT_MASK)
#define ADH_BYTE_INDEX(adhb) \
(((adhb) >> ADH_BIT_SHIFT) - ADH_BIT_IS_LSB)
NO_MODTIME = 0, // null modtime value
// meta-coding
_meta_default = 0,
_meta_canon_min = 1,
_meta_canon_max = 115,
_meta_arb = 116,
_meta_run = 117,
_meta_pop = 141,
_meta_limit = 189,
_meta_error = 255,
_xxx_1_end
};
// Bytecodes.
enum {
bc_nop = 0, // 0x00
bc_aconst_null = 1, // 0x01
bc_iconst_m1 = 2, // 0x02
bc_iconst_0 = 3, // 0x03
bc_iconst_1 = 4, // 0x04
bc_iconst_2 = 5, // 0x05
bc_iconst_3 = 6, // 0x06
bc_iconst_4 = 7, // 0x07
bc_iconst_5 = 8, // 0x08
bc_lconst_0 = 9, // 0x09
bc_lconst_1 = 10, // 0x0a
bc_fconst_0 = 11, // 0x0b
bc_fconst_1 = 12, // 0x0c
bc_fconst_2 = 13, // 0x0d
bc_dconst_0 = 14, // 0x0e
bc_dconst_1 = 15, // 0x0f
bc_bipush = 16, // 0x10
bc_sipush = 17, // 0x11
bc_ldc = 18, // 0x12
bc_ldc_w = 19, // 0x13
bc_ldc2_w = 20, // 0x14
bc_iload = 21, // 0x15
bc_lload = 22, // 0x16
bc_fload = 23, // 0x17
bc_dload = 24, // 0x18
bc_aload = 25, // 0x19
bc_iload_0 = 26, // 0x1a
bc_iload_1 = 27, // 0x1b
bc_iload_2 = 28, // 0x1c
bc_iload_3 = 29, // 0x1d
bc_lload_0 = 30, // 0x1e
bc_lload_1 = 31, // 0x1f
bc_lload_2 = 32, // 0x20
bc_lload_3 = 33, // 0x21
bc_fload_0 = 34, // 0x22
bc_fload_1 = 35, // 0x23
bc_fload_2 = 36, // 0x24
bc_fload_3 = 37, // 0x25
bc_dload_0 = 38, // 0x26
bc_dload_1 = 39, // 0x27
bc_dload_2 = 40, // 0x28
bc_dload_3 = 41, // 0x29
bc_aload_0 = 42, // 0x2a
bc_aload_1 = 43, // 0x2b
bc_aload_2 = 44, // 0x2c
bc_aload_3 = 45, // 0x2d
bc_iaload = 46, // 0x2e
bc_laload = 47, // 0x2f
bc_faload = 48, // 0x30
bc_daload = 49, // 0x31
bc_aaload = 50, // 0x32
bc_baload = 51, // 0x33
bc_caload = 52, // 0x34
bc_saload = 53, // 0x35
bc_istore = 54, // 0x36
bc_lstore = 55, // 0x37
bc_fstore = 56, // 0x38
bc_dstore = 57, // 0x39
bc_astore = 58, // 0x3a
bc_istore_0 = 59, // 0x3b
bc_istore_1 = 60, // 0x3c
bc_istore_2 = 61, // 0x3d
bc_istore_3 = 62, // 0x3e
bc_lstore_0 = 63, // 0x3f
bc_lstore_1 = 64, // 0x40
bc_lstore_2 = 65, // 0x41
bc_lstore_3 = 66, // 0x42
bc_fstore_0 = 67, // 0x43
bc_fstore_1 = 68, // 0x44
bc_fstore_2 = 69, // 0x45
bc_fstore_3 = 70, // 0x46
bc_dstore_0 = 71, // 0x47
bc_dstore_1 = 72, // 0x48
bc_dstore_2 = 73, // 0x49
bc_dstore_3 = 74, // 0x4a
bc_astore_0 = 75, // 0x4b
bc_astore_1 = 76, // 0x4c
bc_astore_2 = 77, // 0x4d
bc_astore_3 = 78, // 0x4e
bc_iastore = 79, // 0x4f
bc_lastore = 80, // 0x50
bc_fastore = 81, // 0x51
bc_dastore = 82, // 0x52
bc_aastore = 83, // 0x53
bc_bastore = 84, // 0x54
bc_castore = 85, // 0x55
bc_sastore = 86, // 0x56
bc_pop = 87, // 0x57
bc_pop2 = 88, // 0x58
bc_dup = 89, // 0x59
bc_dup_x1 = 90, // 0x5a
bc_dup_x2 = 91, // 0x5b
bc_dup2 = 92, // 0x5c
bc_dup2_x1 = 93, // 0x5d
bc_dup2_x2 = 94, // 0x5e
bc_swap = 95, // 0x5f
bc_iadd = 96, // 0x60
bc_ladd = 97, // 0x61
bc_fadd = 98, // 0x62
bc_dadd = 99, // 0x63
bc_isub = 100, // 0x64
bc_lsub = 101, // 0x65
bc_fsub = 102, // 0x66
bc_dsub = 103, // 0x67
bc_imul = 104, // 0x68
bc_lmul = 105, // 0x69
bc_fmul = 106, // 0x6a
bc_dmul = 107, // 0x6b
bc_idiv = 108, // 0x6c
bc_ldiv = 109, // 0x6d
bc_fdiv = 110, // 0x6e
bc_ddiv = 111, // 0x6f
bc_irem = 112, // 0x70
bc_lrem = 113, // 0x71
bc_frem = 114, // 0x72
bc_drem = 115, // 0x73
bc_ineg = 116, // 0x74
bc_lneg = 117, // 0x75
bc_fneg = 118, // 0x76
bc_dneg = 119, // 0x77
bc_ishl = 120, // 0x78
bc_lshl = 121, // 0x79
bc_ishr = 122, // 0x7a
bc_lshr = 123, // 0x7b
bc_iushr = 124, // 0x7c
bc_lushr = 125, // 0x7d
bc_iand = 126, // 0x7e
bc_land = 127, // 0x7f
bc_ior = 128, // 0x80
bc_lor = 129, // 0x81
bc_ixor = 130, // 0x82
bc_lxor = 131, // 0x83
bc_iinc = 132, // 0x84
bc_i2l = 133, // 0x85
bc_i2f = 134, // 0x86
bc_i2d = 135, // 0x87
bc_l2i = 136, // 0x88
bc_l2f = 137, // 0x89
bc_l2d = 138, // 0x8a
bc_f2i = 139, // 0x8b
bc_f2l = 140, // 0x8c
bc_f2d = 141, // 0x8d
bc_d2i = 142, // 0x8e
bc_d2l = 143, // 0x8f
bc_d2f = 144, // 0x90
bc_i2b = 145, // 0x91
bc_i2c = 146, // 0x92
bc_i2s = 147, // 0x93
bc_lcmp = 148, // 0x94
bc_fcmpl = 149, // 0x95
bc_fcmpg = 150, // 0x96
bc_dcmpl = 151, // 0x97
bc_dcmpg = 152, // 0x98
bc_ifeq = 153, // 0x99
bc_ifne = 154, // 0x9a
bc_iflt = 155, // 0x9b
bc_ifge = 156, // 0x9c
bc_ifgt = 157, // 0x9d
bc_ifle = 158, // 0x9e
bc_if_icmpeq = 159, // 0x9f
bc_if_icmpne = 160, // 0xa0
bc_if_icmplt = 161, // 0xa1
bc_if_icmpge = 162, // 0xa2
bc_if_icmpgt = 163, // 0xa3
bc_if_icmple = 164, // 0xa4
bc_if_acmpeq = 165, // 0xa5
bc_if_acmpne = 166, // 0xa6
bc_goto = 167, // 0xa7
bc_jsr = 168, // 0xa8
bc_ret = 169, // 0xa9
bc_tableswitch = 170, // 0xaa
bc_lookupswitch = 171, // 0xab
bc_ireturn = 172, // 0xac
bc_lreturn = 173, // 0xad
bc_freturn = 174, // 0xae
bc_dreturn = 175, // 0xaf
bc_areturn = 176, // 0xb0
bc_return = 177, // 0xb1
bc_getstatic = 178, // 0xb2
bc_putstatic = 179, // 0xb3
bc_getfield = 180, // 0xb4
bc_putfield = 181, // 0xb5
bc_invokevirtual = 182, // 0xb6
bc_invokespecial = 183, // 0xb7
bc_invokestatic = 184, // 0xb8
bc_invokeinterface = 185, // 0xb9
bc_invokedynamic = 186, // 0xba
bc_new = 187, // 0xbb
bc_newarray = 188, // 0xbc
bc_anewarray = 189, // 0xbd
bc_arraylength = 190, // 0xbe
bc_athrow = 191, // 0xbf
bc_checkcast = 192, // 0xc0
bc_instanceof = 193, // 0xc1
bc_monitorenter = 194, // 0xc2
bc_monitorexit = 195, // 0xc3
bc_wide = 196, // 0xc4
bc_multianewarray = 197, // 0xc5
bc_ifnull = 198, // 0xc6
bc_ifnonnull = 199, // 0xc7
bc_goto_w = 200, // 0xc8
bc_jsr_w = 201, // 0xc9
bc_bytecode_limit = 202 // 0xca
};
enum {
bc_end_marker = 255,
bc_byte_escape = 254,
bc_ref_escape = 253,
_first_linker_op = bc_getstatic,
_last_linker_op = bc_invokestatic,
_num_linker_ops = (_last_linker_op - _first_linker_op) + 1,
_self_linker_op = bc_bytecode_limit,
_self_linker_aload_flag = 1*_num_linker_ops,
_self_linker_super_flag = 2*_num_linker_ops,
_self_linker_limit = _self_linker_op + 4*_num_linker_ops,
_invokeinit_op = _self_linker_limit,
_invokeinit_self_option = 0,
_invokeinit_super_option = 1,
_invokeinit_new_option = 2,
_invokeinit_limit = _invokeinit_op+3,
_xldc_op = _invokeinit_limit,
bc_sldc = bc_ldc, // previously named bc_aldc
bc_cldc = _xldc_op+0,
bc_ildc = _xldc_op+1,
bc_fldc = _xldc_op+2,
bc_sldc_w = bc_ldc_w, // previously named bc_aldc_w
bc_cldc_w = _xldc_op+3,
bc_ildc_w = _xldc_op+4,
bc_fldc_w = _xldc_op+5,
bc_lldc2_w = bc_ldc2_w,
bc_dldc2_w = _xldc_op+6,
// anything other primitive, string, or class must be handled with qldc:
bc_qldc = _xldc_op+7,
bc_qldc_w = _xldc_op+8,
_xldc_limit = _xldc_op+9,
_invoke_int_op = _xldc_limit,
_invokespecial_int = _invoke_int_op+0,
_invokestatic_int = _invoke_int_op+1,
_invoke_int_limit = _invoke_int_op+2,
_xxx_3_end
};

View file

@ -1,178 +0,0 @@
/*
* Copyright (c) 2001, 2016, 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.
*/
// random definitions
#ifdef _MSC_VER
#include <windows.h>
#include <winuser.h>
#else
#include <unistd.h>
#endif
#ifndef NO_ZLIB
#include <zconf.h>
#endif
#ifndef FULL
#define FULL 1 /* Adds <500 bytes to the zipped final product. */
#endif
#if FULL // define this if you want debugging and/or compile-time attributes
#define IF_FULL(x) x
#else
#define IF_FULL(x) /*x*/
#endif
#ifdef PRODUCT
#define IF_PRODUCT(xxx) xxx
#define NOT_PRODUCT(xxx)
#define assert(p)
#define PRINTCR(args)
#define VERSION_STRING "%s version %s\n"
#else
#define IF_PRODUCT(xxx)
#define NOT_PRODUCT(xxx) xxx
#define assert(p) ((p) || assert_failed(#p))
#define PRINTCR(args) u->verbose && u->printcr_if_verbose args
#define VERSION_STRING "%s version non-product %s\n"
extern "C" void breakpoint();
extern int assert_failed(const char*);
#define BREAK (breakpoint())
#endif
// Build-time control of some C++ inlining.
// To make a slightly faster smaller binary, say "CC -Dmaybe_inline=inline"
#ifndef maybe_inline
#define maybe_inline /*inline*/
#endif
// By marking larger member functions inline, we remove external linkage.
#ifndef local_inline
#define local_inline inline
#endif
// Error messages that we have
#define ERROR_ENOMEM "Native allocation failed"
#define ERROR_FORMAT "Corrupted pack file"
#define ERROR_RESOURCE "Cannot extract resource file"
#define ERROR_OVERFLOW "Internal buffer overflow"
#define ERROR_INTERNAL "Internal error"
#define ERROR_INIT "cannot init class members"
#define LOGFILE_STDOUT "-"
#define LOGFILE_STDERR ""
#define lengthof(array) (sizeof(array)/sizeof(array[0]))
#define NEW(T, n) (T*) must_malloc((int)(scale_size(n, sizeof(T))))
#define U_NEW(T, n) (T*) u->alloc(scale_size(n, sizeof(T)))
#define T_NEW(T, n) (T*) u->temp_alloc(scale_size(n, sizeof(T)))
// Dealing with big-endian arch
#ifdef _BIG_ENDIAN
#define SWAP_INT(a) (((a>>24)&0xff) | ((a<<8)&0xff0000) | ((a>>8)&0xff00) | ((a<<24)&0xff000000))
#else
#define SWAP_INT(a) (a)
#endif
// bytes and byte arrays
typedef unsigned int uint;
#if defined(NO_ZLIB)
#ifdef _LP64
typedef unsigned int uLong; // Historical zlib, should be 32-bit.
#else
typedef unsigned long uLong;
#endif
#endif
#ifdef _MSC_VER
typedef LONGLONG jlong;
typedef DWORDLONG julong;
#define MKDIR(dir) mkdir(dir)
#define getpid() _getpid()
#define PATH_MAX MAX_PATH
#define dup2(a,b) _dup2(a,b)
#define strcasecmp(s1, s2) _stricmp(s1,s2)
#define tempname _tempname
#define sleep Sleep
#define snprintf _snprintf
#define PATH_SEPARATOR '\\'
#else
typedef signed char byte;
#ifdef _LP64
typedef long jlong;
typedef long unsigned julong;
#else
typedef long long jlong;
typedef long long unsigned julong;
#endif
#define MKDIR(dir) mkdir(dir, 0777);
#define PATH_SEPARATOR '/'
#endif
#ifdef OLDCC
typedef int bool;
enum { false, true };
#endif
#define null (0)
/* Must cast to void *, then size_t, then int. */
#define ptrlowbits(x) ((int)(size_t)(void*)(x))
/* Back and forth from jlong to pointer */
#define ptr2jlong(x) ((jlong)(size_t)(void*)(x))
#define jlong2ptr(x) ((void*)(size_t)(x))
// Keys used by Java:
#define UNPACK_DEFLATE_HINT "unpack.deflate.hint"
#define COM_PREFIX "com.sun.java.util.jar.pack."
#define UNPACK_MODIFICATION_TIME COM_PREFIX"unpack.modification.time"
#define DEBUG_VERBOSE COM_PREFIX"verbose"
#define ZIP_ARCHIVE_MARKER_COMMENT "PACK200"
// The following are not known to the Java classes:
#define UNPACK_LOG_FILE COM_PREFIX"unpack.log.file"
#define UNPACK_REMOVE_PACKFILE COM_PREFIX"unpack.remove.packfile"
// Called from unpacker layers
#define _CHECK_DO(t,x) { if (t) {x;} }
#define CHECK _CHECK_DO(aborting(), return)
#define CHECK_(y) _CHECK_DO(aborting(), return y)
#define CHECK_0 _CHECK_DO(aborting(), return 0)
#define CHECK_COUNT(t) if (t < 0){abort("bad value count");} CHECK
#define STR_TRUE "true"
#define STR_FALSE "false"
#define STR_TF(x) ((x) ? STR_TRUE : STR_FALSE)
#define BOOL_TF(x) (((x) != null && strcmp((x),STR_TRUE) == 0) ? true : false)
#define DEFAULT_ARCHIVE_MODTIME 1060000000 // Aug 04, 2003 5:26 PM PDT

File diff suppressed because it is too large Load diff

View file

@ -1,509 +0,0 @@
/*
* Copyright (c) 2002, 2016, 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.
*/
// Global Structures
struct jar;
struct gunzip;
struct band;
struct cpool;
struct entry;
struct cpindex;
struct inner_class;
struct value_stream;
struct cpindex {
uint len;
entry* base1; // base of primary index
entry** base2; // base of secondary index
byte ixTag; // type of entries (!= CONSTANT_None), plus 64 if sub-index
enum { SUB_TAG = 64 };
entry* get(uint i);
void init(int len_, entry* base1_, int ixTag_) {
len = len_;
base1 = base1_;
base2 = null;
ixTag = ixTag_;
}
void init(int len_, entry** base2_, int ixTag_) {
len = len_;
base1 = null;
base2 = base2_;
ixTag = ixTag_;
}
};
struct cpool {
uint nentries;
entry* entries;
entry* first_extra_entry;
uint maxentries; // total allocated size of entries
// Position and size of each homogeneous subrange:
int tag_count[CONSTANT_Limit];
int tag_base[CONSTANT_Limit];
cpindex tag_index[CONSTANT_Limit];
ptrlist tag_extras[CONSTANT_Limit];
int tag_group_count[CONSTANT_GroupLimit - CONSTANT_GroupFirst];
cpindex tag_group_index[CONSTANT_GroupLimit - CONSTANT_GroupFirst];
cpindex* member_indexes; // indexed by 2*CONSTANT_Class.inord
cpindex* getFieldIndex(entry* classRef);
cpindex* getMethodIndex(entry* classRef);
inner_class** ic_index;
inner_class** ic_child_index;
inner_class* getIC(entry* inner);
inner_class* getFirstChildIC(entry* outer);
inner_class* getNextChildIC(inner_class* child);
int outputIndexLimit; // index limit after renumbering
ptrlist outputEntries; // list of entry* needing output idx assigned
ptrlist requested_bsms; // which bsms need output?
entry** hashTab;
uint hashTabLength;
entry*& hashTabRef(byte tag, bytes& b);
entry* ensureUtf8(bytes& b);
entry* ensureClass(bytes& b);
// Well-known Utf8 symbols.
enum {
#define SNAME(n,s) s_##s,
ALL_ATTR_DO(SNAME)
#undef SNAME
s_lt_init_gt, // <init>
s_LIMIT
};
entry* sym[s_LIMIT];
// read counts from hdr, allocate main arrays
void init(unpacker* u, int counts[CONSTANT_Limit]);
// pointer to outer unpacker, for error checks etc.
unpacker* u;
int getCount(byte tag) {
if ((uint)tag >= CONSTANT_GroupFirst) {
assert((uint)tag < CONSTANT_GroupLimit);
return tag_group_count[(uint)tag - CONSTANT_GroupFirst];
} else {
assert((uint)tag < CONSTANT_Limit);
return tag_count[(uint)tag];
}
}
cpindex* getIndex(byte tag) {
if ((uint)tag >= CONSTANT_GroupFirst) {
assert((uint)tag < CONSTANT_GroupLimit);
return &tag_group_index[(uint)tag - CONSTANT_GroupFirst];
} else {
assert((uint)tag < CONSTANT_Limit);
return &tag_index[(uint)tag];
}
}
cpindex* getKQIndex(); // uses cur_descr
void expandSignatures();
void initGroupIndexes();
void initMemberIndexes();
int initLoadableValues(entry** loadable_entries);
void computeOutputOrder();
void computeOutputIndexes();
void resetOutputIndexes();
// error handling
inline void abort(const char* msg);
inline bool aborting();
};
/*
* The unpacker provides the entry points to the unpack engine,
* as well as maintains the state of the engine.
*/
struct unpacker {
// One element of the resulting JAR.
struct file {
const char* name;
julong size;
int modtime;
int options;
bytes data[2];
// Note: If Sum(data[*].len) < size,
// remaining bytes must be read directly from the input stream.
bool deflate_hint() { return ((options & FO_DEFLATE_HINT) != 0); }
};
// back pointer to NativeUnpacker obj and Java environment
void* jniobj;
void* jnienv;
// global pointer to self, if not running under JNI (not multi-thread safe)
static unpacker* non_mt_current;
// if running Unix-style, here are the inputs and outputs
FILE* infileptr; // buffered
int infileno; // unbuffered
bytes inbytes; // direct
gunzip* gzin; // gunzip filter, if any
jar* jarout; // output JAR file
#ifndef PRODUCT
int nowrite;
int skipfiles;
int verbose_bands;
#endif
// pointer to self, for U_NEW macro
unpacker* u;
// private abort message string, allocated to PATH_MAX*2
const char* abort_message;
ptrlist mallocs; // list of guys to free when we are all done
ptrlist tmallocs; // list of guys to free on next client request
fillbytes smallbuf; // supplies small alloc requests
fillbytes tsmallbuf; // supplies temporary small alloc requests
// option management members
int verbose; // verbose level, 0 means no output
bool strip_compile;
bool strip_debug;
bool strip_jcov;
bool remove_packfile;
int deflate_hint_or_zero; // ==0 means not set, otherwise -1 or 1
int modification_time_or_zero;
FILE* errstrm;
const char* errstrm_name;
const char* log_file;
// input stream
fillbytes input; // the whole block (size is predicted, has slop too)
bool live_input; // is the data in this block live?
bool free_input; // must the input buffer be freed?
byte* rp; // read pointer (< rplimit <= input.limit())
byte* rplimit; // how much of the input block has been read?
julong bytes_read;
size_t unsized_bytes_read;
// callback to read at least one byte, up to available input
typedef jlong (*read_input_fn_t)(unpacker* self, void* buf, jlong minlen, jlong maxlen);
read_input_fn_t read_input_fn;
// archive header fields
int magic, minver, majver;
size_t archive_size;
int archive_next_count, archive_options, archive_modtime;
int band_headers_size;
int file_count, attr_definition_count, ic_count, class_count;
int default_class_minver, default_class_majver;
int default_file_options, suppress_file_options; // not header fields
int default_archive_modtime, default_file_modtime; // not header fields
int code_count; // not a header field
int files_remaining; // not a header field
// engine state
band* all_bands; // indexed by band_number
byte* meta_rp; // read-pointer into (copy of) band_headers
cpool cp; // all constant pool information
inner_class* ics; // InnerClasses
// output stream
bytes output; // output block (either classfile head or tail)
byte* wp; // write pointer (< wplimit == output.limit())
byte* wpbase; // write pointer starting address (<= wp)
byte* wplimit; // how much of the output block has been written?
// output state
file cur_file;
entry* cur_class; // CONSTANT_Class entry
entry* cur_super; // CONSTANT_Class entry or null
entry* cur_descr; // CONSTANT_NameandType entry
int cur_descr_flags; // flags corresponding to cur_descr
int cur_class_minver, cur_class_majver;
bool cur_class_has_local_ics;
int cur_class_local_bsm_count;
fillbytes cur_classfile_head;
fillbytes cur_classfile_tail;
int files_written; // also tells which file we're working on
int classes_written; // also tells which class we're working on
julong bytes_written;
intlist bcimap;
fillbytes class_fixup_type;
intlist class_fixup_offset;
ptrlist class_fixup_ref;
fillbytes code_fixup_type; // which format of branch operand?
intlist code_fixup_offset; // location of operand needing fixup
intlist code_fixup_source; // encoded ID of branch insn
ptrlist requested_ics; // which ics need output?
// stats pertaining to multiple segments (updated on reset)
julong bytes_read_before_reset;
julong bytes_written_before_reset;
int files_written_before_reset;
int classes_written_before_reset;
int segments_read_before_reset;
// attribute state
struct layout_definition {
uint idx; // index (0..31...) which identifies this layout
const char* name; // name of layout
entry* nameEntry;
const char* layout; // string of layout (not yet parsed)
band** elems; // array of top-level layout elems (or callables)
bool hasCallables() { return layout[0] == '['; }
band** bands() { assert(elems != null); return elems; }
};
struct attr_definitions {
unpacker* u; // pointer to self, for U_NEW macro
int xxx_flags_hi_bn;// locator for flags, count, indexes, calls bands
int attrc; // ATTR_CONTEXT_CLASS, etc.
uint flag_limit; // 32 or 63, depending on archive_options bit
julong predef; // mask of built-in definitions
julong redef; // mask of local flag definitions or redefinitions
ptrlist layouts; // local (compressor-defined) defs, in index order
int flag_count[X_ATTR_LIMIT_FLAGS_HI];
intlist overflow_count;
ptrlist strip_names; // what attribute names are being stripped?
ptrlist band_stack; // Temp., used during layout parsing.
ptrlist calls_to_link; // (ditto)
int bands_made; // (ditto)
void free() {
layouts.free();
overflow_count.free();
strip_names.free();
band_stack.free();
calls_to_link.free();
}
// Locate the five fixed bands.
band& xxx_flags_hi();
band& xxx_flags_lo();
band& xxx_attr_count();
band& xxx_attr_indexes();
band& xxx_attr_calls();
band& fixed_band(int e_class_xxx);
// Register a new layout, and make bands for it.
layout_definition* defineLayout(int idx, const char* name, const char* layout);
layout_definition* defineLayout(int idx, entry* nameEntry, const char* layout);
band** buildBands(layout_definition* lo);
// Parse a layout string or part of one, recursively if necessary.
const char* parseLayout(const char* lp, band** &res, int curCble);
const char* parseNumeral(const char* lp, int &res);
const char* parseIntLayout(const char* lp, band* &res, byte le_kind,
bool can_be_signed = false);
band** popBody(int band_stack_base); // pops a body off band_stack
// Read data into the bands of the idx-th layout.
void readBandData(int idx); // parse layout, make bands, read data
void readBandData(band** body, uint count); // recursive helper
layout_definition* getLayout(uint idx) {
if (idx >= (uint)layouts.length()) return null;
return (layout_definition*) layouts.get(idx);
}
void setHaveLongFlags(bool z) {
assert(flag_limit == 0); // not set up yet
flag_limit = (z? X_ATTR_LIMIT_FLAGS_HI: X_ATTR_LIMIT_NO_FLAGS_HI);
}
bool haveLongFlags() {
assert(flag_limit == X_ATTR_LIMIT_NO_FLAGS_HI ||
flag_limit == X_ATTR_LIMIT_FLAGS_HI);
return flag_limit == X_ATTR_LIMIT_FLAGS_HI;
}
// Return flag_count if idx is predef and not redef, else zero.
int predefCount(uint idx);
bool isRedefined(uint idx) {
if (idx >= flag_limit) return false;
return (bool)((redef >> idx) & 1);
}
bool isPredefined(uint idx) {
if (idx >= flag_limit) return false;
return (bool)(((predef & ~redef) >> idx) & 1);
}
julong flagIndexMask() {
return (predef | redef);
}
bool isIndex(uint idx) {
assert(flag_limit != 0); // must be set up already
if (idx < flag_limit)
return (bool)(((predef | redef) >> idx) & 1);
else
return (idx - flag_limit < (uint)overflow_count.length());
}
int& getCount(uint idx) {
assert(isIndex(idx));
if (idx < flag_limit)
return flag_count[idx];
else
return overflow_count.get(idx - flag_limit);
}
bool aborting() { return u->aborting(); }
void abort(const char* msg) { u->abort(msg); }
};
attr_definitions attr_defs[ATTR_CONTEXT_LIMIT];
// Initialization
void init(read_input_fn_t input_fn = null);
// Resets to a known sane state
void reset();
// Deallocates all storage.
void free();
// Deallocates temporary storage (volatile after next client call).
void free_temps() { tsmallbuf.init(); tmallocs.freeAll(); }
// Option management methods
bool set_option(const char* option, const char* value);
const char* get_option(const char* option);
void dump_options();
// Fetching input.
bool ensure_input(jlong more);
byte* input_scan() { return rp; }
size_t input_remaining() { return rplimit - rp; }
size_t input_consumed() { return rp - input.base(); }
// Entry points to the unpack engine
static int run(int argc, char **argv); // Unix-style entry point.
void check_options();
void start(void* packptr = null, size_t len = 0);
void redirect_stdio();
void write_file_to_jar(file* f);
void finish();
// Public post unpack methods
int get_files_remaining() { return files_remaining; }
int get_segments_remaining() { return archive_next_count; }
file* get_next_file(); // returns null on last file
// General purpose methods
void* alloc(size_t size) { return alloc_heap(size, true); }
void* temp_alloc(size_t size) { return alloc_heap(size, true, true); }
void* alloc_heap(size_t size, bool smallOK = false, bool temp = false);
void saveTo(bytes& b, const char* str) { saveTo(b, (byte*)str, strlen(str)); }
void saveTo(bytes& b, bytes& data) { saveTo(b, data.ptr, data.len); }
void saveTo(bytes& b, byte* ptr, size_t len); //{ b.ptr = U_NEW...}
const char* saveStr(const char* str) { bytes buf; saveTo(buf, str); return buf.strval(); }
const char* saveIntStr(int num) { char buf[30]; sprintf(buf, "%d", num); return saveStr(buf); }
#ifndef PRODUCT
int printcr_if_verbose(int level, const char* fmt,...);
#endif
const char* get_abort_message();
void abort(const char* s = null);
bool aborting() { return abort_message != null; }
static unpacker* current(); // find current instance
void checkLegacy(const char* name);
// Output management
void set_output(fillbytes* which) {
assert(wp == null);
which->ensureSize(1 << 12); // covers the average classfile
wpbase = which->base();
wp = which->limit();
wplimit = which->end();
}
fillbytes* close_output(fillbytes* which = null); // inverse of set_output
// These take an implicit parameter of wp/wplimit, and resize as necessary:
byte* put_space(size_t len); // allocates space at wp, returns pointer
size_t put_empty(size_t s) { byte* p = put_space(s); return p - wpbase; }
void ensure_put_space(size_t len);
void put_bytes(bytes& b) { b.writeTo(put_space(b.len)); }
void putu1(int n) { putu1_at(put_space(1), n); }
void putu1_fast(int n) { putu1_at(wp++, n); }
void putu2(int n); // { putu2_at(put_space(2), n); }
void putu4(int n); // { putu4_at(put_space(4), n); }
void putu8(jlong n); // { putu8_at(put_space(8), n); }
void putref(entry* e); // { putu2_at(put_space(2), putref_index(e, 2)); }
void putu1ref(entry* e); // { putu1_at(put_space(1), putref_index(e, 1)); }
int putref_index(entry* e, int size); // size in [1..2]
void put_label(int curIP, int size); // size in {2,4}
void putlayout(band** body);
void put_stackmap_type();
size_t wpoffset() { return (size_t)(wp - wpbase); } // (unvariant across overflow)
byte* wp_at(size_t offset) { return wpbase + offset; }
uint to_bci(uint bii);
void get_code_header(int& max_stack,
int& max_na_locals,
int& handler_count,
int& cflags);
band* ref_band_for_self_op(int bc, bool& isAloadVar, int& origBCVar);
band* ref_band_for_op(int bc);
// Definitions of standard classfile int formats:
static void putu1_at(byte* wp, int n) { assert(n == (n & 0xFF)); wp[0] = n; }
static void putu2_at(byte* wp, int n);
static void putu4_at(byte* wp, int n);
static void putu8_at(byte* wp, jlong n);
// Private stuff
void reset_cur_classfile();
void write_classfile_tail();
void write_classfile_head();
void write_code();
void write_bc_ops();
void write_members(int num, int attrc); // attrc=ATTR_CONTEXT_FIELD/METHOD
int write_attrs(int attrc, julong indexBits);
int write_ics(int naOffset, int na);
int write_bsms(int naOffset, int na);
// The readers
void read_bands();
void read_file_header();
void read_cp();
void read_cp_counts(value_stream& hdr);
void read_attr_defs();
void read_ics();
void read_attrs(int attrc, int obj_count);
void read_classes();
void read_code_headers();
void read_bcs();
void read_bc_ops();
void read_files();
void read_Utf8_values(entry* cpMap, int len);
void read_single_words(band& cp_band, entry* cpMap, int len);
void read_double_words(band& cp_bands, entry* cpMap, int len);
void read_single_refs(band& cp_band, byte refTag, entry* cpMap, int len);
void read_double_refs(band& cp_band, byte ref1Tag, byte ref2Tag, entry* cpMap, int len);
void read_signature_values(entry* cpMap, int len);
void read_method_handle(entry* cpMap, int len);
void read_method_type(entry* cpMap, int len);
void read_bootstrap_methods(entry* cpMap, int len);
};
inline void cpool::abort(const char* msg) { u->abort(msg); }
inline bool cpool::aborting() { return u->aborting(); }

View file

@ -1,183 +0,0 @@
/*
* Copyright (c) 2001, 2015, 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.
*/
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <sys/stat.h>
#ifdef _MSC_VER
#include <direct.h>
#include <io.h>
#include <process.h>
#else
#include <unistd.h>
#endif
#include "constants.h"
#include "defines.h"
#include "bytes.h"
#include "utils.h"
#include "unpack.h"
void* must_malloc(size_t size) {
size_t msize = size;
#ifdef USE_MTRACE
if (msize >= 0 && msize < sizeof(int))
msize = sizeof(int); // see 0xbaadf00d below
#endif
void* ptr = (msize > PSIZE_MAX || msize <= 0) ? null : malloc(msize);
if (ptr != null) {
memset(ptr, 0, size);
} else {
unpack_abort(ERROR_ENOMEM);
}
mtrace('m', ptr, size);
return ptr;
}
void mkdirs(int oklen, char* path) {
if (strlen(path) <= (size_t)oklen) return;
char dir[PATH_MAX];
strcpy(dir, path);
char* slash = strrchr(dir, '/');
if (slash == 0) return;
*slash = 0;
mkdirs(oklen, dir);
MKDIR(dir);
}
#ifndef PRODUCT
#ifndef STATIC_BUILD
// use the definition in libjvm when building statically
void breakpoint() { } // hook for debugger
int assert_failed(const char* p) {
char message[1<<12];
sprintf(message, "@assert failed: %s\n", p);
fprintf(stdout, "%s", 1+message);
breakpoint();
unpack_abort(message);
return 0;
}
#endif
#endif
void unpack_abort(const char* msg, unpacker* u) {
if (msg == null) msg = "corrupt pack file or internal error";
if (u == null)
u = unpacker::current();
if (u == null) {
fprintf(stderr, "Error: unpacker: %s\n", msg);
::abort();
return;
}
u->abort(msg);
}
bool unpack_aborting(unpacker* u) {
if (u == null)
u = unpacker::current();
if (u == null) {
fprintf(stderr, "Error: unpacker: no current instance\n");
::abort();
return true;
}
return u->aborting();
}
#ifdef USE_MTRACE
// Use this occasionally for detecting storage leaks in unpack.
void mtrace(char c, void* ptr, size_t size) {
if (c == 'f') *(int*)ptr = 0xbaadf00d;
static FILE* mtfp;
if (mtfp == (FILE*)-1) return;
if (mtfp == null) {
if (getenv("USE_MTRACE") == null) {
mtfp = (FILE*)-1;
return;
}
char fname[1024];
sprintf(fname, "mtr%d.txt", getpid());
mtfp = fopen(fname, "w");
if (mtfp == null)
mtfp = stdout;
}
fprintf(mtfp, "%c %p %p\n", c, ptr, (void*)size);
}
/* # Script for processing memory traces.
# It should report only a limited number (2) of "suspended" blocks,
# even if a large number of archive segments are processed.
# It should report no "leaked" blocks at all.
nawk < mtr*.txt '
function checkleaks(what) {
nd = 0
for (ptr in allocated) {
if (allocated[ptr] == 1) {
print NR ": " what " " ptr
#allocated[ptr] = 0 # stop the dangle
nd++
}
}
if (nd > 0) print NR ": count " what " " nd
}
/^[mfr]/ {
ptr = $2
a1 = ($1 == "m")? 1: 0
a0 = 0+allocated[ptr]
allocated[ptr] = a1
if (a0 + a1 != 1) {
if (a0 == 0 && a1 == 0)
print NR ": double free " ptr
else if (a0 == 1 && a1 == 1)
print NR ": double malloc " ptr
else
print NR ": oddity " $0
}
next
}
/^s/ {
checkleaks("suspended")
next
}
{
print NR ": unrecognized " $0
}
END {
checkleaks("leaked")
}
'
*/
#endif // USE_MTRACE

View file

@ -1,67 +0,0 @@
/*
* Copyright (c) 2001, 2018, 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.
*/
//Definitions of our util functions
void* must_malloc(size_t size);
#ifndef USE_MTRACE
#define mtrace(c, ptr, size)
#else
void mtrace(char c, void* ptr, size_t size);
#endif
// overflow management
#define POVERFLOW ((uint)-1)
#define PSIZE_MAX (POVERFLOW/2) /* normal size limit */
inline size_t scale_size(size_t size, size_t scale) {
return (size > PSIZE_MAX / scale) ? POVERFLOW : size * scale;
}
inline size_t add_size(size_t size1, size_t size2) {
return ((size1 | size2 | (size1 + size2)) > PSIZE_MAX)
? POVERFLOW
: size1 + size2;
}
inline size_t add_size(size_t size1, size_t size2, int size3) {
return add_size(add_size(size1, size2), size3);
}
// These may be expensive, because they have to go via Java TSD,
// if the optional u argument is missing.
struct unpacker;
extern void unpack_abort(const char* msg, unpacker* u = null);
extern bool unpack_aborting(unpacker* u = null);
#ifndef PRODUCT
inline bool endsWith(const char* str, const char* suf) {
size_t len1 = strlen(str);
size_t len2 = strlen(suf);
return (len1 > len2 && 0 == strcmp(str + (len1-len2), suf));
}
#endif
void mkdirs(int oklen, char* path);

View file

@ -1,708 +0,0 @@
/*
* Copyright (c) 2001, 2016, 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.
*/
/**
* Note: Lifted from uncrunch.c from jdk sources
*/
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <stdlib.h>
#ifndef _MSC_VER
#include <strings.h>
#endif
#include "defines.h"
#include "bytes.h"
#include "utils.h"
#include "constants.h"
#include "unpack.h"
#include "zip.h"
#ifdef NO_ZLIB
inline bool jar::deflate_bytes(bytes& head, bytes& tail) {
return false;
}
inline uint jar::get_crc32(uint c, uchar *ptr, uint len) { return 0; }
#define Z_NULL NULL
#else // Have ZLIB
#include <zlib.h>
inline uint jar::get_crc32(uint c, uchar *ptr, uint len) { return crc32(c, ptr, len); }
#endif // End of ZLIB
#ifdef _BIG_ENDIAN
#define SWAP_BYTES(a) \
((((a) << 8) & 0xff00) | 0x00ff) & (((a) >> 8) | 0xff00)
#else
#define SWAP_BYTES(a) (a)
#endif
#define GET_INT_LO(a) \
SWAP_BYTES(a & 0xFFFF)
#define GET_INT_HI(a) \
SWAP_BYTES((a >> 16) & 0xFFFF)
static const ushort jarmagic[2] = { SWAP_BYTES(0xCAFE), 0 };
void jar::init(unpacker* u_) {
BYTES_OF(*this).clear();
u = u_;
u->jarout = this;
}
// Write data to the ZIP output stream.
void jar::write_data(void* buff, size_t len) {
while (len > 0) {
int rc = (int)fwrite(buff, 1, len, jarfp);
if (rc <= 0) {
fprintf(u->errstrm, "Error: write on output file failed err=%d\n",errno);
exit(1); // Called only from the native standalone unpacker
}
output_file_offset += rc;
buff = ((char *)buff) + rc;
len -= rc;
}
}
void jar::add_to_jar_directory(const char* fname, bool store, int modtime,
int len, int clen, uLong crc) {
uint fname_length = (uint)strlen(fname);
ushort header[23];
if (modtime == 0) modtime = default_modtime;
uLong dostime = get_dostime(modtime);
header[0] = (ushort)SWAP_BYTES(0x4B50);
header[1] = (ushort)SWAP_BYTES(0x0201);
header[2] = (ushort)SWAP_BYTES(( store ) ? 0x0A : 0x14);
// required version
header[3] = (ushort)SWAP_BYTES(( store ) ? 0x0A : 0x14);
// Flags - UTF-8 compression and separating crc and sizes
// into separate headers for deflated file
header[4] = ( store ) ? SWAP_BYTES(0x0800) : 0x0808;
// Compression method 8=deflate.
header[5] = ( store ) ? 0x0 : SWAP_BYTES(0x08);
// Last modified date and time.
header[6] = (ushort)GET_INT_LO(dostime);
header[7] = (ushort)GET_INT_HI(dostime);
// CRC
header[8] = (ushort)GET_INT_LO(crc);
header[9] = (ushort)GET_INT_HI(crc);
// Compressed length:
header[10] = (ushort)GET_INT_LO(clen);
header[11] = (ushort)GET_INT_HI(clen);
// Uncompressed length.
header[12] = (ushort)GET_INT_LO(len);
header[13] = (ushort)GET_INT_HI(len);
// Filename length
header[14] = (ushort)SWAP_BYTES(fname_length);
// So called "extra field" length.
// If it's the first record we must add JAR magic sequence
header[15] = ( central_directory_count ) ? 0 : (ushort)SWAP_BYTES(4);
// So called "comment" length.
header[16] = 0;
// Disk number start
header[17] = 0;
// File flags => binary
header[18] = 0;
// More file flags
header[19] = 0;
header[20] = 0;
// Offset within ZIP file.
header[21] = (ushort)GET_INT_LO(output_file_offset);
header[22] = (ushort)GET_INT_HI(output_file_offset);
// Copy the whole thing into the central directory.
central_directory.append(header, sizeof(header));
// Copy the fname to the header.
central_directory.append(fname, fname_length);
// Add jar magic for the first record
if (central_directory_count == 0) {
central_directory.append((void *)jarmagic, sizeof(jarmagic));
}
central_directory_count++;
}
void jar::write_jar_header(const char* fname, bool store, int modtime,
int len, int clen, uint crc) {
uint fname_length = (uint)strlen(fname);
ushort header[15];
if (modtime == 0) modtime = default_modtime;
uLong dostime = get_dostime(modtime);
// ZIP LOC magic.
header[0] = (ushort)SWAP_BYTES(0x4B50);
header[1] = (ushort)SWAP_BYTES(0x0403);
// Version
header[2] = (ushort)SWAP_BYTES(( store ) ? 0x0A : 0x14);
// General purpose flags - same as in the Central Directory
header[3] = ( store ) ? SWAP_BYTES(0x0800) : 0x0808;
// Compression method = deflate
header[4] = ( store ) ? 0x0 : SWAP_BYTES(0x08);
// Last modified date and time.
header[5] = (ushort)GET_INT_LO(dostime);
header[6] = (ushort)GET_INT_HI(dostime);
// CRC, 0 if deflated, will come separately in extra header
header[7] = ( store ) ? (ushort)GET_INT_LO(crc) : 0;
header[8] = ( store ) ? (ushort)GET_INT_HI(crc) : 0;
// Compressed length, 0 if deflated
header[9] = ( store ) ? (ushort)GET_INT_LO(clen) : 0;
header[10] = ( store ) ? (ushort)GET_INT_HI(clen) : 0;
// Uncompressed length, 0 if deflated
header[11] = ( store ) ? (ushort)GET_INT_LO(len) : 0;
header[12] = ( store ) ? (ushort)GET_INT_HI(len) : 0;
// Filename length
header[13] = (ushort)SWAP_BYTES(fname_length);
// So called "extra field" length.
header[14] = ( central_directory_count - 1 ) ? 0 : (ushort)SWAP_BYTES(4);
// Write the LOC header to the output file.
write_data(header, (int)sizeof(header));
// Copy the fname to the header.
write_data((char*)fname, (int)fname_length);
if (central_directory_count == 1) {
// Write JAR magic sequence
write_data((void *)jarmagic, (int)sizeof(jarmagic));
}
}
void jar::write_jar_extra(int len, int clen, uint crc) {
ushort header[8];
// Extra field signature
header[0] = (ushort)SWAP_BYTES(0x4B50);
header[1] = (ushort)SWAP_BYTES(0x0807);
// CRC
header[2] = (ushort)GET_INT_LO(crc);
header[3] = (ushort)GET_INT_HI(crc);
// Compressed length
header[4] = (ushort)GET_INT_LO(clen);
header[5] = (ushort)GET_INT_HI(clen);
// Uncompressed length
header[6] = (ushort)GET_INT_LO(len);
header[7] = (ushort)GET_INT_HI(len);
write_data(header, sizeof(header));
}
static const char marker_comment[] = ZIP_ARCHIVE_MARKER_COMMENT;
void jar::write_central_directory() {
bytes mc; mc.set(marker_comment);
ushort header[11];
ushort header64[38];
// Create the End of Central Directory structure.
header[0] = (ushort)SWAP_BYTES(0x4B50);
header[1] = (ushort)SWAP_BYTES(0x0605);
// disk numbers
header[2] = 0;
header[3] = 0;
// Number of entries in central directory.
header[4] = ( central_directory_count >= 0xffff ) ? 0xffff : (ushort)SWAP_BYTES(central_directory_count);
header[5] = ( central_directory_count >= 0xffff ) ? 0xffff : (ushort)SWAP_BYTES(central_directory_count);
// Size of the central directory}
header[6] = (ushort)GET_INT_LO((int)central_directory.size());
header[7] = (ushort)GET_INT_HI((int)central_directory.size());
// Offset of central directory within disk.
header[8] = (ushort)GET_INT_LO(output_file_offset);
header[9] = (ushort)GET_INT_HI(output_file_offset);
// zipfile comment length;
header[10] = (ushort)SWAP_BYTES((int)mc.len);
// Write the central directory.
PRINTCR((2, "Central directory at %d\n", output_file_offset));
write_data(central_directory.b);
// If number of records exceeds the 0xFFFF we need to prepend extended
// Zip64 End of Central Directory record and its locator to the old
// style ECD record
if (central_directory_count > 0xFFFF) {
// Zip64 END signature
header64[0] = (ushort)SWAP_BYTES(0x4B50);
header64[1] = (ushort)0x0606;
// Size of header (long)
header64[2] = (ushort)SWAP_BYTES(44);;
header64[3] = 0;
header64[4] = 0;
header64[5] = 0;
// Version produced and required (short)
header64[6] = (ushort)SWAP_BYTES(45);
header64[7] = (ushort)SWAP_BYTES(45);
// Current disk number (int)
header64[8] = 0;
header64[9] = 0;
// Central directory start disk (int)
header64[10] = 0;
header64[11] = 0;
// Count of records on disk (long)
header64[12] = (ushort)GET_INT_LO(central_directory_count);
header64[13] = (ushort)GET_INT_HI(central_directory_count);
header64[14] = 0;
header64[15] = 0;
// Count of records totally (long)
header64[16] = (ushort)GET_INT_LO(central_directory_count);
header64[17] = (ushort)GET_INT_HI(central_directory_count);
header64[18] = 0;
header64[19] = 0;
// Length of the central directory (long)
header64[20] = header[6];
header64[21] = header[7];
header64[22] = 0;
header64[23] = 0;
// Offset of central directory (long)
header64[24] = header[8];
header64[25] = header[9];
header64[26] = 0;
header64[27] = 0;
// Zip64 end of central directory locator
// Locator signature
header64[28] = (ushort)SWAP_BYTES(0x4B50);
header64[29] = (ushort)SWAP_BYTES(0x0706);
// Start disk number (int)
header64[30] = 0;
header64[31] = 0;
// Offset of zip64 END record (long)
header64[32] = (ushort)GET_INT_LO(output_file_offset);
header64[33] = (ushort)GET_INT_HI(output_file_offset);
header64[34] = 0;
header64[35] = 0;
// Total number of disks (int)
header64[36] = (ushort)SWAP_BYTES(1);
header64[37] = 0;
write_data(header64, sizeof(header64));
}
// Write the End of Central Directory structure.
PRINTCR((2, "end-of-directory at %d\n", output_file_offset));
write_data(header, sizeof(header));
PRINTCR((2, "writing zip comment\n"));
// Write the comment.
write_data(mc);
}
// Public API
// Open a Jar file and initialize.
void jar::openJarFile(const char* fname) {
if (!jarfp) {
PRINTCR((1, "jar::openJarFile: opening %s\n",fname));
jarname = fname;
jarfp = fopen(fname, "wb");
if (!jarfp) {
fprintf(u->errstrm, "Error: Could not open jar file: %s\n",fname);
exit(3); // Called only from the native standalone unpacker
}
}
}
// Add a ZIP entry and copy the file data
void jar::addJarEntry(const char* fname,
bool deflate_hint, int modtime,
bytes& head, bytes& tail) {
int len = (int)(head.len + tail.len);
int clen = 0;
uint crc = get_crc32(0,Z_NULL,0);
if (head.len != 0)
crc = get_crc32(crc, (uchar *)head.ptr, (uint)head.len);
if (tail.len != 0)
crc = get_crc32(crc, (uchar *)tail.ptr, (uint)tail.len);
bool deflate = (deflate_hint && len > 0);
if (deflate) {
if (deflate_bytes(head, tail) == false) {
PRINTCR((2, "Reverting to store fn=%s\t%d -> %d\n",
fname, len, deflated.size()));
deflate = false;
}
}
clen = (int)((deflate) ? deflated.size() : len);
add_to_jar_directory(fname, !deflate, modtime, len, clen, crc);
write_jar_header( fname, !deflate, modtime, len, clen, crc);
if (deflate) {
write_data(deflated.b);
// Write deflated information in extra header
write_jar_extra(len, clen, crc);
} else {
write_data(head);
write_data(tail);
}
}
// Add a ZIP entry for a directory name no data
void jar::addDirectoryToJarFile(const char* dir_name) {
bool store = true;
add_to_jar_directory((const char*)dir_name, store, default_modtime, 0, 0, 0);
write_jar_header( (const char*)dir_name, store, default_modtime, 0, 0, 0);
}
// Write out the central directory and close the jar file.
void jar::closeJarFile(bool central) {
if (jarfp) {
fflush(jarfp);
if (central) write_central_directory();
fflush(jarfp);
fclose(jarfp);
PRINTCR((2, "jar::closeJarFile:closed jar-file\n"));
}
reset();
}
/* Convert the date y/n/d and time h:m:s to a four byte DOS date and
* time (date in high two bytes, time in low two bytes allowing magnitude
* comparison).
*/
inline
uLong jar::dostime(int y, int n, int d, int h, int m, int s) {
return y < 1980 ? dostime(1980, 1, 1, 0, 0, 0) :
(((uLong)y - 1980) << 25) | ((uLong)n << 21) | ((uLong)d << 16) |
((uLong)h << 11) | ((uLong)m << 5) | ((uLong)s >> 1);
}
/*
* For thread-safe reasons, non-Windows platforms need gmtime_r
* while Windows can directly use gmtime that is already thread-safe.
*/
#ifdef _MSC_VER
#define gmtime_r(t, s) gmtime(t)
#endif
/*
* Return the Unix time in DOS format
*/
uLong jar::get_dostime(int modtime) {
// see defines.h
if (modtime != 0 && modtime == modtime_cache)
return dostime_cache;
if (modtime != 0 && default_modtime == 0)
default_modtime = modtime; // catch a reasonable default
time_t t = modtime;
struct tm sbuf;
(void)memset((void*)&sbuf,0, sizeof(sbuf));
struct tm* s = gmtime_r(&t, &sbuf);
if (s == NULL) {
fprintf(u->errstrm, "Error: gmtime failure, invalid input archive\n");
exit(-1);
}
modtime_cache = modtime;
dostime_cache = dostime(s->tm_year + 1900, s->tm_mon + 1, s->tm_mday,
s->tm_hour, s->tm_min, s->tm_sec);
//printf("modtime %d => %d\n", modtime_cache, dostime_cache);
return dostime_cache;
}
#ifndef NO_ZLIB
/* Returns true on success, and will set the clen to the compressed
length, the caller should verify if true and clen less than the
input data
*/
bool jar::deflate_bytes(bytes& head, bytes& tail) {
int len = (int)(head.len + tail.len);
z_stream zs;
BYTES_OF(zs).clear();
// NOTE: the window size should always be -MAX_WBITS normally -15.
// unzip/zipup.c and java/Deflater.c
int error = deflateInit2(&zs, Z_DEFAULT_COMPRESSION, Z_DEFLATED,
-MAX_WBITS, 8, Z_DEFAULT_STRATEGY);
if (error != Z_OK) {
switch (error) {
case Z_MEM_ERROR:
PRINTCR((2, "Error: deflate error : Out of memory \n"));
break;
case Z_STREAM_ERROR:
PRINTCR((2,"Error: deflate error : Invalid compression level \n"));
break;
case Z_VERSION_ERROR:
PRINTCR((2,"Error: deflate error : Invalid version\n"));
break;
default:
PRINTCR((2,"Error: Internal deflate error error = %d\n", error));
}
return false;
}
deflated.empty();
zs.next_out = (uchar*) deflated.grow(add_size(len, (len/2)));
zs.avail_out = (int)deflated.size();
zs.next_in = (uchar*)head.ptr;
zs.avail_in = (int)head.len;
bytes* first = &head;
bytes* last = &tail;
if (last->len == 0) {
first = null;
last = &head;
} else if (first->len == 0) {
first = null;
}
if (first != null && error == Z_OK) {
zs.next_in = (uchar*) first->ptr;
zs.avail_in = (int)first->len;
error = deflate(&zs, Z_NO_FLUSH);
}
if (error == Z_OK) {
zs.next_in = (uchar*) last->ptr;
zs.avail_in = (int)last->len;
error = deflate(&zs, Z_FINISH);
}
if (error == Z_STREAM_END) {
if ((int)zs.total_out > 0) {
// Even if compressed size is bigger than uncompressed, write it
PRINTCR((2, "deflate compressed data %d -> %d\n", len, zs.total_out));
deflated.b.len = zs.total_out;
deflateEnd(&zs);
return true;
}
PRINTCR((2, "deflate expanded data %d -> %d\n", len, zs.total_out));
deflateEnd(&zs);
return false;
}
deflateEnd(&zs);
PRINTCR((2, "Error: deflate error deflate did not finish error=%d\n",error));
return false;
}
// Callback for fetching data from a GZIP input stream
static jlong read_input_via_gzip(unpacker* u,
void* buf, jlong minlen, jlong maxlen) {
assert(minlen <= maxlen); // don't talk nonsense
jlong numread = 0;
char* bufptr = (char*) buf;
char* inbuf = u->gzin->inbuf;
size_t inbuflen = sizeof(u->gzin->inbuf);
unpacker::read_input_fn_t read_gzin_fn =
(unpacker::read_input_fn_t) u->gzin->read_input_fn;
z_stream& zs = *(z_stream*) u->gzin->zstream;
while (numread < minlen) {
int readlen = (1 << 16); // pretty arbitrary
if (readlen > (maxlen - numread))
readlen = (int)(maxlen - numread);
zs.next_out = (uchar*) bufptr;
zs.avail_out = readlen;
if (zs.avail_in == 0) {
zs.avail_in = (int) read_gzin_fn(u, inbuf, 1, inbuflen);
zs.next_in = (uchar*) inbuf;
}
int error = inflate(&zs, Z_NO_FLUSH);
if (error != Z_OK && error != Z_STREAM_END) {
u->abort("error inflating input");
break;
}
int nr = readlen - zs.avail_out;
u->gzin->gzlen += nr;
u->gzin->gzcrc = crc32(u->gzin->gzcrc, (const unsigned char *)bufptr, nr);
numread += nr;
bufptr += nr;
assert(numread <= maxlen);
if (error == Z_STREAM_END) {
enum { TRAILER_LEN = 8 };
// skip 8-byte trailer
if (zs.avail_in >= TRAILER_LEN) {
zs.avail_in -= TRAILER_LEN;
} else {
// Bug: 5023768,we read past the TRAILER_LEN to see if there is
// any extraneous data, as we don't support concatenated .gz files.
int extra = (int) read_gzin_fn(u, inbuf, 1, inbuflen);
zs.avail_in += extra - TRAILER_LEN;
}
// %%% should check for concatenated *.gz files here
if (zs.avail_in > 0)
u->abort("garbage after end of deflated input stream");
// at this point we know there are no trailing bytes,
// we are safe to get the crc and len.
if (u->gzin->gzcrc != 0) {
// Read the CRC information from the gzip container
fseek(u->infileptr, -TRAILER_LEN, SEEK_END);
uint filecrc;
uint filelen;
if (fread(&filecrc, sizeof(filecrc), 1, u->infileptr) != 1) {
fprintf(u->errstrm, "Error:reading CRC information on input file failed err=%d\n",errno);
exit(1);
}
if (fread(&filelen, sizeof(filelen), 1, u->infileptr) != 1) {
fprintf(u->errstrm, "Error:reading file length on input file failed err=%d\n",errno);
exit(1);
}
filecrc = SWAP_INT(filecrc);
filelen = SWAP_INT(filelen);
if (u->gzin->gzcrc != filecrc ||
// rfc1952; ISIZE is the input size modulo 2^32
u->gzin->gzlen != (filelen & 0xffffffff)) { // CRC error
PRINTCR((1, "crc: 0x%x 0x%x\n", u->gzin->gzcrc, filecrc));
PRINTCR((1, "len: 0x%x 0x%x\n", u->gzin->gzlen, filelen));
if (u->jarout != null) {
// save the file name first, if any
const char* outfile = u->jarout->jarname;
u->jarout->closeJarFile(false);
if (outfile != null) {
remove(outfile);
}
}
// Print out the error and exit with return code != 0
u->abort("CRC error, invalid compressed data.");
}
}
// pop this filter off:
u->gzin->free();
break;
}
}
//fprintf(u->errstrm, "readInputFn(%d,%d) => %d (gunzip)\n",
// (int)minlen, (int)maxlen, (int)numread);
return numread;
}
void gunzip::init(unpacker* u_) {
BYTES_OF(*this).clear();
u = u_;
assert(u->gzin == null); // once only, please
read_input_fn = (void*)u->read_input_fn;
zstream = NEW(z_stream, 1);
u->gzin = this;
u->read_input_fn = read_input_via_gzip;
u->gzin->gzcrc = crc32(0, Z_NULL, 0);
u->gzin->gzlen = 0;
}
void gunzip::start(int magic) {
assert((magic & GZIP_MAGIC_MASK) == GZIP_MAGIC);
int gz_flg = (magic & 0xFF); // keep "flg", discard other 3 bytes
enum {
FHCRC = (1<<1),
FEXTRA = (1<<2),
FNAME = (1<<3),
FCOMMENT = (1<<4)
};
char gz_mtime[4];
char gz_xfl[1];
char gz_os[1];
char gz_extra_len[2];
char gz_hcrc[2];
char gz_ignore;
// do not save extra, name, comment
read_fixed_field(gz_mtime, sizeof(gz_mtime));
read_fixed_field(gz_xfl, sizeof(gz_xfl));
read_fixed_field(gz_os, sizeof(gz_os));
if (gz_flg & FEXTRA) {
read_fixed_field(gz_extra_len, sizeof(gz_extra_len));
int extra_len = gz_extra_len[0] & 0xFF;
extra_len += (gz_extra_len[1] & 0xFF) << 8;
for (; extra_len > 0; extra_len--) {
read_fixed_field(&gz_ignore, 1);
}
}
int null_terms = 0;
if (gz_flg & FNAME) null_terms++;
if (gz_flg & FCOMMENT) null_terms++;
for (; null_terms; null_terms--) {
for (;;) {
gz_ignore = 0;
read_fixed_field(&gz_ignore, 1);
if (gz_ignore == 0) break;
}
}
if (gz_flg & FHCRC)
read_fixed_field(gz_hcrc, sizeof(gz_hcrc));
if (aborting()) return;
// now the input stream is ready to read into the inflater
int error = inflateInit2((z_stream*) zstream, -MAX_WBITS);
if (error != Z_OK) { abort("cannot create input"); return; }
}
void gunzip::free() {
assert(u->gzin == this);
u->gzin = null;
u->read_input_fn = (unpacker::read_input_fn_t) this->read_input_fn;
inflateEnd((z_stream*) zstream);
mtrace('f', zstream, 0);
::free(zstream);
zstream = null;
mtrace('f', this, 0);
::free(this);
}
void gunzip::read_fixed_field(char* buf, size_t buflen) {
if (aborting()) return;
jlong nr = ((unpacker::read_input_fn_t)read_input_fn)
(u, buf, buflen, buflen);
if ((size_t)nr != buflen)
u->abort("short stream header");
}
#else // NO_ZLIB
void gunzip::free() {
}
#endif // NO_ZLIB

View file

@ -1,118 +0,0 @@
/*
* Copyright (c) 2001, 2016, 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.
*/
#define ushort unsigned short
#define uint unsigned int
#define uchar unsigned char
struct unpacker;
struct jar {
// JAR file writer
FILE* jarfp;
int default_modtime;
const char* jarname;
// Used by unix2dostime:
int modtime_cache;
uLong dostime_cache;
// Private members
fillbytes central_directory;
uint central_directory_count;
uint output_file_offset;
fillbytes deflated; // temporary buffer
// pointer to outer unpacker, for error checks etc.
unpacker* u;
// Public Methods
void openJarFile(const char* fname);
void addJarEntry(const char* fname,
bool deflate_hint, int modtime,
bytes& head, bytes& tail);
void addDirectoryToJarFile(const char* dir_name);
void closeJarFile(bool central);
void init(unpacker* u_);
void free() {
central_directory.free();
deflated.free();
}
void reset() {
free();
init(u);
}
// Private Methods
void write_data(void* ptr, size_t len);
void write_data(bytes& b) { write_data(b.ptr, b.len); }
void add_to_jar_directory(const char* fname, bool store, int modtime,
int len, int clen, uLong crc);
void write_jar_header(const char* fname, bool store, int modtime,
int len, int clen, unsigned int crc);
void write_jar_extra(int len, int clen, unsigned int crc);
void write_central_directory();
uLong dostime(int y, int n, int d, int h, int m, int s);
uLong get_dostime(int modtime);
// The definitions of these depend on the NO_ZLIB option:
bool deflate_bytes(bytes& head, bytes& tail);
static uint get_crc32(uint c, unsigned char *ptr, uint len);
// error handling
void abort(const char* msg) { unpack_abort(msg, u); }
bool aborting() { return unpack_aborting(u); }
};
struct gunzip {
// optional gzip input stream control block
// pointer to outer unpacker, for error checks etc.
unpacker* u;
void* read_input_fn; // underlying byte stream
void* zstream; // inflater state
char inbuf[1 << 14]; // input buffer
uint gzcrc; // CRC gathered from gzip *container* content
uint gzlen; // CRC gathered length
void init(unpacker* u_); // pushes new value on u->read_input_fn
void free();
void start(int magic);
// private stuff
void read_fixed_field(char* buf, size_t buflen);
// error handling
void abort(const char* msg) { unpack_abort(msg, u); }
bool aborting() { return unpack_aborting(u); }
};

View file

@ -1,351 +0,0 @@
/*
* Copyright (c) 2003, 2015, 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.
*/
#include <sys/types.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <limits.h>
#include <com_sun_java_util_jar_pack_NativeUnpack.h>
#include "jni_util.h"
#include "defines.h"
#include "bytes.h"
#include "utils.h"
#include "coding.h"
#include "bands.h"
#include "constants.h"
#include "zip.h"
#include "unpack.h"
static jfieldID unpackerPtrFID;
static jmethodID currentInstMID;
static jmethodID readInputMID;
static jclass NIclazz;
static jmethodID getUnpackerPtrMID;
static char* dbg = null;
#define THROW_IOE(x) JNU_ThrowIOException(env,x)
#define CHECK_EXCEPTION_RETURN_VOID_THROW_IOE(CERVTI_exception, CERVTI_message) \
do { \
if ((env)->ExceptionOccurred()) { \
THROW_IOE(CERVTI_message); \
return; \
} \
if ((CERVTI_exception) == NULL) { \
THROW_IOE(CERVTI_message); \
return; \
} \
} while (JNI_FALSE)
#define CHECK_EXCEPTION_RETURN_VALUE(CERL_exception, CERL_return_value) \
do { \
if ((env)->ExceptionOccurred()) { \
return CERL_return_value; \
} \
if ((CERL_exception) == NULL) { \
return CERL_return_value; \
} \
} while (JNI_FALSE)
// If these useful macros aren't defined in jni_util.h then define them here
#ifndef CHECK_NULL_RETURN
#define CHECK_NULL_RETURN(x, y) \
do { \
if ((x) == NULL) return (y); \
} while (JNI_FALSE)
#endif
#ifndef CHECK_EXCEPTION_RETURN
#define CHECK_EXCEPTION_RETURN(env, y) \
do { \
if ((*env)->ExceptionCheck(env)) return (y); \
} while (JNI_FALSE)
#endif
/*
* Declare library specific JNI_Onload entry if static build
*/
DEF_STATIC_JNI_OnLoad
static jlong read_input_via_jni(unpacker* self,
void* buf, jlong minlen, jlong maxlen);
static unpacker* get_unpacker(JNIEnv *env, jobject pObj, bool noCreate=false) {
unpacker* uPtr;
jlong p = env->CallLongMethod(pObj, getUnpackerPtrMID);
uPtr = (unpacker*)jlong2ptr(p);
if (uPtr == null) {
if (noCreate) return null;
uPtr = new unpacker();
if (uPtr == null) {
THROW_IOE(ERROR_ENOMEM);
return null;
}
//fprintf(stderr, "get_unpacker(%p) uPtr=%p initializing\n", pObj, uPtr);
uPtr->init(read_input_via_jni);
uPtr->jniobj = (void*) env->NewGlobalRef(pObj);
env->SetLongField(pObj, unpackerPtrFID, ptr2jlong(uPtr));
}
uPtr->jnienv = env; // keep refreshing this in case of MT access
return uPtr;
}
// This is the harder trick: Pull the current state out of mid-air.
static unpacker* get_unpacker() {
//fprintf(stderr, "get_unpacker()\n");
JavaVM* vm = null;
jsize nVM = 0;
jint retval = JNI_GetCreatedJavaVMs(&vm, 1, &nVM);
// other VM implements may differ, thus for correctness, we need these checks
if (retval != JNI_OK || nVM != 1)
return null;
void* envRaw = null;
vm->GetEnv(&envRaw, JNI_VERSION_1_1);
JNIEnv* env = (JNIEnv*) envRaw;
//fprintf(stderr, "get_unpacker() env=%p\n", env);
CHECK_NULL_RETURN(env, NULL);
jobject pObj = env->CallStaticObjectMethod(NIclazz, currentInstMID);
// We should check upon the known non-null variable because here we want to check
// only for pending exceptions. If pObj is null we'll deal with it later.
CHECK_EXCEPTION_RETURN_VALUE(env, NULL);
//fprintf(stderr, "get_unpacker0() pObj=%p\n", pObj);
if (pObj != null) {
// Got pObj and env; now do it the easy way.
return get_unpacker(env, pObj);
}
// this should really not happen, if it does something is seriously
// wrong throw an exception
THROW_IOE(ERROR_INTERNAL);
return null;
}
static void free_unpacker(JNIEnv *env, jobject pObj, unpacker* uPtr) {
if (uPtr != null) {
//fprintf(stderr, "free_unpacker(%p) uPtr=%p\n", pObj, uPtr);
env->DeleteGlobalRef((jobject) uPtr->jniobj);
uPtr->jniobj = null;
uPtr->free();
delete uPtr;
env->SetLongField(pObj, unpackerPtrFID, (jlong)null);
}
}
unpacker* unpacker::current() {
return get_unpacker();
}
// Callback for fetching data, Java style. Calls NativeUnpack.readInputFn().
static jlong read_input_via_jni(unpacker* self,
void* buf, jlong minlen, jlong maxlen) {
JNIEnv* env = (JNIEnv*) self->jnienv;
jobject pbuf = env->NewDirectByteBuffer(buf, maxlen);
return env->CallLongMethod((jobject) self->jniobj, readInputMID,
pbuf, minlen);
}
JNIEXPORT void JNICALL
Java_com_sun_java_util_jar_pack_NativeUnpack_initIDs(JNIEnv *env, jclass clazz) {
#ifndef PRODUCT
dbg = getenv("DEBUG_ATTACH");
while( dbg != null) { sleep(10); }
#endif
NIclazz = (jclass) env->NewGlobalRef(clazz);
unpackerPtrFID = env->GetFieldID(clazz, "unpackerPtr", "J");
CHECK_EXCEPTION_RETURN_VOID_THROW_IOE(unpackerPtrFID, ERROR_INIT);
currentInstMID = env->GetStaticMethodID(clazz, "currentInstance",
"()Ljava/lang/Object;");
CHECK_EXCEPTION_RETURN_VOID_THROW_IOE(currentInstMID, ERROR_INIT);
readInputMID = env->GetMethodID(clazz, "readInputFn",
"(Ljava/nio/ByteBuffer;J)J");
CHECK_EXCEPTION_RETURN_VOID_THROW_IOE(readInputMID, ERROR_INIT);
getUnpackerPtrMID = env->GetMethodID(clazz, "getUnpackerPtr", "()J");
CHECK_EXCEPTION_RETURN_VOID_THROW_IOE(getUnpackerPtrMID, ERROR_INIT);
}
JNIEXPORT jlong JNICALL
Java_com_sun_java_util_jar_pack_NativeUnpack_start(JNIEnv *env, jobject pObj,
jobject pBuf, jlong offset) {
// try to get the unpacker pointer the hard way first, we do this to ensure
// valid object pointers and env is intact, if not now is good time to bail.
unpacker* uPtr = get_unpacker();
//fprintf(stderr, "start(%p) uPtr=%p initializing\n", pObj, uPtr);
CHECK_EXCEPTION_RETURN_VALUE(uPtr, -1);
// redirect our io to the default log file or whatever.
uPtr->redirect_stdio();
void* buf = null;
size_t buflen = 0;
if (pBuf != null) {
buf = env->GetDirectBufferAddress(pBuf);
buflen = (size_t)env->GetDirectBufferCapacity(pBuf);
if (buflen == 0) buf = null;
if (buf == null) { THROW_IOE(ERROR_INTERNAL); return 0; }
if ((size_t)offset >= buflen)
{ buf = null; buflen = 0; }
else
{ buf = (char*)buf + (size_t)offset; buflen -= (size_t)offset; }
}
// before we start off we make sure there is no other error by the time we
// get here
if (uPtr->aborting()) {
THROW_IOE(uPtr->get_abort_message());
return 0;
}
uPtr->start(buf, buflen);
if (uPtr->aborting()) {
THROW_IOE(uPtr->get_abort_message());
return 0;
}
return ((jlong)
uPtr->get_segments_remaining() << 32)
+ uPtr->get_files_remaining();
}
JNIEXPORT jboolean JNICALL
Java_com_sun_java_util_jar_pack_NativeUnpack_getNextFile(JNIEnv *env, jobject pObj,
jobjectArray pParts) {
unpacker* uPtr = get_unpacker(env, pObj);
CHECK_EXCEPTION_RETURN_VALUE(uPtr, false);
unpacker::file* filep = uPtr->get_next_file();
if (uPtr->aborting()) {
THROW_IOE(uPtr->get_abort_message());
return false;
}
CHECK_NULL_RETURN(filep, false);
assert(filep == &uPtr->cur_file);
int pidx = 0, iidx = 0;
jintArray pIntParts = (jintArray) env->GetObjectArrayElement(pParts, pidx++);
CHECK_EXCEPTION_RETURN_VALUE(pIntParts, false);
jint* intParts = env->GetIntArrayElements(pIntParts, null);
intParts[iidx++] = (jint)( (julong)filep->size >> 32 );
intParts[iidx++] = (jint)( (julong)filep->size >> 0 );
intParts[iidx++] = filep->modtime;
intParts[iidx++] = filep->deflate_hint() ? 1 : 0;
env->ReleaseIntArrayElements(pIntParts, intParts, JNI_COMMIT);
jstring filename = env->NewStringUTF(filep->name);
CHECK_EXCEPTION_RETURN_VALUE(filename, false);
env->SetObjectArrayElement(pParts, pidx++, filename);
CHECK_EXCEPTION_RETURN_VALUE(uPtr, false);
jobject pDataBuf = null;
if (filep->data[0].len > 0) {
pDataBuf = env->NewDirectByteBuffer(filep->data[0].ptr,
filep->data[0].len);
CHECK_EXCEPTION_RETURN_VALUE(pDataBuf, false);
}
env->SetObjectArrayElement(pParts, pidx++, pDataBuf);
CHECK_EXCEPTION_RETURN_VALUE(uPtr, false);
pDataBuf = null;
if (filep->data[1].len > 0) {
pDataBuf = env->NewDirectByteBuffer(filep->data[1].ptr,
filep->data[1].len);
CHECK_EXCEPTION_RETURN_VALUE(pDataBuf, false);
}
env->SetObjectArrayElement(pParts, pidx++, pDataBuf);
CHECK_EXCEPTION_RETURN_VALUE(uPtr, false);
return true;
}
JNIEXPORT jobject JNICALL
Java_com_sun_java_util_jar_pack_NativeUnpack_getUnusedInput(JNIEnv *env, jobject pObj) {
unpacker* uPtr = get_unpacker(env, pObj);
CHECK_EXCEPTION_RETURN_VALUE(uPtr, NULL);
unpacker::file* filep = &uPtr->cur_file;
if (uPtr->aborting()) {
THROW_IOE(uPtr->get_abort_message());
return null;
}
// We have fetched all the files.
// Now swallow up any remaining input.
if (uPtr->input_remaining() == 0) {
return null;
} else {
bytes remaining_bytes;
remaining_bytes.malloc(uPtr->input_remaining());
remaining_bytes.copyFrom(uPtr->input_scan(), uPtr->input_remaining());
return env->NewDirectByteBuffer(remaining_bytes.ptr, remaining_bytes.len);
}
}
JNIEXPORT jlong JNICALL
Java_com_sun_java_util_jar_pack_NativeUnpack_finish(JNIEnv *env, jobject pObj) {
unpacker* uPtr = get_unpacker(env, pObj, false);
CHECK_EXCEPTION_RETURN_VALUE(uPtr, 0);
size_t consumed = uPtr->input_consumed();
free_unpacker(env, pObj, uPtr);
return consumed;
}
JNIEXPORT jboolean JNICALL
Java_com_sun_java_util_jar_pack_NativeUnpack_setOption(JNIEnv *env, jobject pObj,
jstring pProp, jstring pValue) {
unpacker* uPtr = get_unpacker(env, pObj);
CHECK_EXCEPTION_RETURN_VALUE(uPtr, false);
const char* prop = env->GetStringUTFChars(pProp, JNI_FALSE);
CHECK_EXCEPTION_RETURN_VALUE(prop, false);
const char* value = env->GetStringUTFChars(pValue, JNI_FALSE);
CHECK_EXCEPTION_RETURN_VALUE(value, false);
jboolean retval = uPtr->set_option(prop, value);
env->ReleaseStringUTFChars(pProp, prop);
env->ReleaseStringUTFChars(pValue, value);
return retval;
}
JNIEXPORT jstring JNICALL
Java_com_sun_java_util_jar_pack_NativeUnpack_getOption(JNIEnv *env, jobject pObj,
jstring pProp) {
unpacker* uPtr = get_unpacker(env, pObj);
CHECK_EXCEPTION_RETURN_VALUE(uPtr, NULL);
const char* prop = env->GetStringUTFChars(pProp, JNI_FALSE);
CHECK_EXCEPTION_RETURN_VALUE(prop, NULL);
const char* value = uPtr->get_option(prop);
CHECK_EXCEPTION_RETURN_VALUE(value, NULL);
env->ReleaseStringUTFChars(pProp, prop);
return env->NewStringUTF(value);
}

View file

@ -1,469 +0,0 @@
/*
* Copyright (c) 2003, 2018, 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.
*/
#ifdef _ALLBSD_SOURCE
#include <stdint.h>
#define THRTYPE intptr_t
#else
#define THRTYPE int
#endif
#include <sys/types.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <errno.h>
#include <limits.h>
#include <time.h>
#if defined(unix) && !defined(PRODUCT)
#include "pthread.h"
#define THREAD_SELF ((THRTYPE)pthread_self())
#endif
#include "jni.h"
#include "defines.h"
#include "bytes.h"
#include "utils.h"
#include "coding.h"
#include "bands.h"
#include "constants.h"
#include "zip.h"
#include "unpack.h"
JNIEXPORT int
main(int argc, char **argv) {
return unpacker::run(argc, argv);
}
// Single-threaded, implementation, not reentrant.
// Includes a weak error check against MT access.
#ifndef THREAD_SELF
#define THREAD_SELF ((THRTYPE) 0)
#endif
NOT_PRODUCT(static THRTYPE uThread = -1;)
unpacker* unpacker::non_mt_current = null;
unpacker* unpacker::current() {
//assert(uThread == THREAD_SELF);
return non_mt_current;
}
static void set_current_unpacker(unpacker* u) {
unpacker::non_mt_current = u;
assert(((uThread = (u == null) ? (THRTYPE) -1 : THREAD_SELF),
true));
}
// Callback for fetching data, Unix style.
static jlong read_input_via_stdio(unpacker* u,
void* buf, jlong minlen, jlong maxlen) {
assert(minlen <= maxlen); // don't talk nonsense
jlong numread = 0;
char* bufptr = (char*) buf;
while (numread < minlen) {
// read available input, up to buf.length or maxlen
int readlen = (1<<16);
if (readlen > (maxlen - numread))
readlen = (int)(maxlen - numread);
int nr = 0;
if (u->infileptr != null) {
nr = (int)fread(bufptr, 1, readlen, u->infileptr);
} else {
#ifndef WIN32
// we prefer unbuffered inputs
nr = (int)read(u->infileno, bufptr, readlen);
#else
nr = (int)fread(bufptr, 1, readlen, stdin);
#endif
}
if (nr <= 0) {
if (errno != EINTR)
break;
nr = 0;
}
numread += nr;
bufptr += nr;
assert(numread <= maxlen);
}
//fprintf(u->errstrm, "readInputFn(%d,%d) => %d\n",
// (int)minlen, (int)maxlen, (int)numread);
return numread;
}
enum { EOF_MAGIC = 0, BAD_MAGIC = -1 };
static int read_magic(unpacker* u, char peek[], int peeklen) {
assert(peeklen == 4); // magic numbers are always 4 bytes
jlong nr = (u->read_input_fn)(u, peek, peeklen, peeklen);
if (nr != peeklen) {
return (nr == 0) ? EOF_MAGIC : BAD_MAGIC;
}
int magic = 0;
for (int i = 0; i < peeklen; i++) {
magic <<= 8;
magic += peek[i] & 0xFF;
}
return magic;
}
static void setup_gzin(unpacker* u) {
gunzip* gzin = NEW(gunzip, 1);
gzin->init(u);
}
static const char* nbasename(const char* progname) {
const char* slash = strrchr(progname, PATH_SEPARATOR);
if (slash != null) progname = ++slash;
return progname;
}
#define USAGE_HEADER "Usage: %s [-opt... | --option=value]... x.pack[.gz] y.jar\n"
#define USAGE_OPTIONS \
"\n" \
"Unpacking Options\n" \
" -H{h}, --deflate-hint={h} override transmitted deflate hint:\n" \
" true, false, or keep (default)\n" \
" -r, --remove-pack-file remove input file after unpacking\n" \
" -v, --verbose increase program verbosity\n" \
" -q, --quiet set verbosity to lowest level\n" \
" -l{F}, --log-file={F} output to the given log file,\n" \
" or '-' for standard output (default)\n" \
" -?, -h, --help print this help message\n" \
" -V, --version print program version\n" \
"\n" \
"Exit Status:\n" \
" 0 if successful, >0 if an error occurred\n"
#define DEPRECATE_WARNING \
"\nWarning: The %s tool is deprecated, and is planned for removal in a future JDK release.\n\n"
#define SUPPRESS_DEPRECATE_MSG "-XDsuppress-tool-removal-message"
static bool suppress_warning = false;
static void usage(unpacker* u, const char* progname, bool full = false) {
// WinMain does not set argv[0] to the progrname
progname = (progname != null) ? nbasename(progname) : "unpack200";
fprintf(u->errstrm, USAGE_HEADER, progname);
if (full) {
fprintf(u->errstrm, USAGE_OPTIONS);
} else {
fprintf(u->errstrm, "(For more information, run %s --help .)\n", progname);
}
}
// argument parsing
static char** init_args(int argc, char** argv, int &envargc) {
const char* env = getenv("UNPACK200_FLAGS");
ptrlist envargs;
envargs.init();
if (env != null) {
char* buf = (char*) strdup(env);
const char* delim = "\n\t ";
for (char* p = strtok(buf, delim); p != null; p = strtok(null, delim)) {
if (!strcmp(p, SUPPRESS_DEPRECATE_MSG)) {
suppress_warning = true;
} else {
envargs.add(p);
}
}
}
// allocate extra margin at both head and tail
char** argp = NEW(char*, envargs.length()+argc+1);
char** argp0 = argp;
int i;
for (i = 0; i < envargs.length(); i++) {
*argp++ = (char*) envargs.get(i);
}
for (i = 1; i < argc; i++) {
// note: skip argv[0] (program name)
if (!strcmp(argv[i], SUPPRESS_DEPRECATE_MSG)) {
suppress_warning = true;
} else {
*argp++ = (char*) strdup(argv[i]); // make a scratch copy
}
}
*argp = null; // sentinel
envargc = envargs.length(); // report this count to next_arg
envargs.free();
return argp0;
}
static int strpcmp(const char* str, const char* pfx) {
return strncmp(str, pfx, strlen(pfx));
}
static const char flag_opts[] = "vqrVh?";
static const char string_opts[] = "HlJ";
static int next_arg(char** &argp) {
char* arg = *argp;
if (arg == null || arg[0] != '-') { // end of option list
return 0;
}
//printf("opt: %s\n", arg);
char ach = arg[1];
if (ach == '\0') {
// ++argp; // do not pop this arg
return 0; // bare "-" is stdin/stdout
} else if (arg[1] == '-') { // --foo option
static const char* keys[] = {
"Hdeflate-hint=",
"vverbose",
"qquiet",
"rremove-pack-file",
"llog-file=",
"Vversion",
"hhelp",
null };
if (arg[2] == '\0') { // end of option list
++argp; // pop the "--"
return 0;
}
for (int i = 0; keys[i] != null; i++) {
const char* key = keys[i];
char kch = *key++;
if (strchr(key, '=') == null) {
if (!strcmp(arg+2, key)) {
++argp; // pop option arg
return kch;
}
} else {
if (!strpcmp(arg+2, key)) {
*argp += 2 + strlen(key); // remove "--"+key from arg
return kch;
}
}
}
} else if (strchr(flag_opts, ach) != null) { // plain option
if (arg[2] == '\0') {
++argp;
} else {
// in-place edit of "-vxyz" to "-xyz"
arg += 1; // skip original '-'
arg[0] = '-';
*argp = arg;
}
//printf(" key => %c\n", ach);
return ach;
} else if (strchr(string_opts, ach) != null) { // argument-bearing option
if (arg[2] == '\0') {
if (argp[1] == null) return -1; // no next arg
++argp; // leave the argument in place
} else {
// in-place edit of "-Hxyz" to "xyz"
arg += 2; // skip original '-H'
*argp = arg;
}
//printf(" key => %c\n", ach);
return ach;
}
return -1; // bad argument
}
static const char sccsver[] = "1.30, 07/05/05";
// Usage: unpackage input.pack output.jar
int unpacker::run(int argc, char **argv) {
unpacker u;
u.init(read_input_via_stdio);
set_current_unpacker(&u);
jar jarout;
jarout.init(&u);
int envargc = 0;
char** argbuf = init_args(argc, argv, envargc);
char** arg0 = argbuf+envargc;
char** argp = argbuf;
int verbose = 0;
char* logfile = null;
if (!suppress_warning) {
fprintf(u.errstrm, DEPRECATE_WARNING, nbasename(argv[0]));
}
for (;;) {
const char* arg = (*argp == null)? "": u.saveStr(*argp);
bool isenvarg = (argp < arg0);
int ach = next_arg(argp);
bool hasoptarg = (ach != 0 && strchr(string_opts, ach) != null);
if (ach == 0 && argp >= arg0) break;
if (isenvarg && argp == arg0 && hasoptarg) ach = 0; // don't pull from cmdline
switch (ach) {
case 'H': u.set_option(UNPACK_DEFLATE_HINT,*argp++); break;
case 'v': ++verbose; break;
case 'q': verbose = 0; break;
case 'r': u.set_option(UNPACK_REMOVE_PACKFILE,"1"); break;
case 'l': logfile = *argp++; break;
case 'J': argp += 1; break; // skip ignored -Jxxx parameter
case 'V':
fprintf(u.errstrm, VERSION_STRING, nbasename(argv[0]), sccsver);
exit(0);
case 'h':
case '?':
usage(&u, argv[0], true);
exit(0);
default:
const char* inenv = isenvarg? " in ${UNPACK200_FLAGS}": "";
if (hasoptarg)
fprintf(u.errstrm, "Missing option string%s: %s\n", inenv, arg);
else
fprintf(u.errstrm, "Unrecognized argument%s: %s\n", inenv, arg);
usage(&u, argv[0]);
exit(2);
}
}
if (verbose != 0) {
u.set_option(DEBUG_VERBOSE, u.saveIntStr(verbose));
}
if (logfile != null) {
u.set_option(UNPACK_LOG_FILE, logfile);
}
u.redirect_stdio();
const char* source_file = *argp++;
const char* destination_file = *argp++;
if (source_file == null || destination_file == null || *argp != null) {
usage(&u, argv[0]);
exit(2);
}
if (verbose != 0) {
fprintf(u.errstrm,
"Unpacking from %s to %s\n", source_file, destination_file);
}
bool& remove_source = u.remove_packfile;
if (strcmp(source_file, "-") == 0) {
remove_source = false;
u.infileno = fileno(stdin);
} else {
u.infileptr = fopen(source_file, "rb");
if (u.infileptr == null) {
fprintf(u.errstrm,
"Error: Could not open input file: %s\n", source_file);
exit(3); // Called only from the native standalone unpacker
}
}
if (strcmp(destination_file, "-") == 0) {
jarout.jarfp = stdout;
jarout.jarname = null;
if (u.errstrm == stdout) // do not mix output
u.set_option(UNPACK_LOG_FILE, LOGFILE_STDERR);
} else {
jarout.openJarFile(destination_file);
assert(jarout.jarfp != null);
}
if (verbose != 0)
u.dump_options();
char peek[4];
int magic;
// check for GZIP input
magic = read_magic(&u, peek, (int)sizeof(peek));
if ((magic & GZIP_MAGIC_MASK) == GZIP_MAGIC) {
// Oops; must slap an input filter on this data.
setup_gzin(&u);
u.gzin->start(magic);
u.gzin->gzcrc = 0;
u.gzin->gzlen = 0;
if (!u.aborting()) {
u.start();
}
} else {
u.start(peek, sizeof(peek));
}
// Note: The checks to u.aborting() are necessary to gracefully
// terminate processing when the first segment throws an error.
for (;;) {
if (u.aborting()) break;
// Each trip through this loop unpacks one segment
// and then resets the unpacker.
for (unpacker::file* filep; (filep = u.get_next_file()) != null; ) {
if (u.aborting()) break;
u.write_file_to_jar(filep);
}
if (u.aborting()) break;
// Peek ahead for more data.
magic = read_magic(&u, peek, (int)sizeof(peek));
if (magic != (int)JAVA_PACKAGE_MAGIC) {
if (magic != EOF_MAGIC)
u.abort("garbage after end of pack archive");
break; // all done
}
// Release all storage from parsing the old segment.
u.reset();
// Restart, beginning with the peek-ahead.
u.start(peek, sizeof(peek));
}
int status = 0;
if (u.aborting()) {
fprintf(u.errstrm, "Error: %s\n", u.get_abort_message());
status = 1;
}
if (u.infileptr != null) {
fclose(u.infileptr);
u.infileptr = null;
}
if (!u.aborting() && remove_source)
remove(source_file);
if (verbose != 0) {
fprintf(u.errstrm, "unpacker completed with status=%d\n", status);
}
u.finish();
u.free(); // tidy up malloc blocks
set_current_unpacker(null); // clean up global pointer
return status;
}

View file

@ -1,20 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity
name=""
version=""
processorArchitecture="X86"
type="win32"/>
<description>Java(TM) SE Runtime Environment unpack200 Process.</description>
<!-- Identify the application security requirements. -->
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<requestedExecutionLevel
level="asInvoker"
uiAccess="false"/>
</requestedPrivileges>
</security>
</trustInfo>
</assembly>

View file

@ -6,7 +6,6 @@ auxiliary.org-netbeans-modules-apisupport-installer.os-linux=false
auxiliary.org-netbeans-modules-apisupport-installer.os-macosx=true auxiliary.org-netbeans-modules-apisupport-installer.os-macosx=true
auxiliary.org-netbeans-modules-apisupport-installer.os-solaris=false auxiliary.org-netbeans-modules-apisupport-installer.os-solaris=false
auxiliary.org-netbeans-modules-apisupport-installer.os-windows=false auxiliary.org-netbeans-modules-apisupport-installer.os-windows=false
auxiliary.org-netbeans-modules-apisupport-installer.pack200-enabled=false
auxiliary.org-netbeans-spi-editor-hints-projects.perProjectHintSettingsFile=nbproject/cfg_hints.xml auxiliary.org-netbeans-spi-editor-hints-projects.perProjectHintSettingsFile=nbproject/cfg_hints.xml
modules=\ modules=\
${project.com.sun.hotspot.igv.graph}:\ ${project.com.sun.hotspot.igv.graph}:\

View file

@ -885,15 +885,6 @@ sanity/client/SwingSet/src/ScrollPaneDemoTest.java 8225013 linux-all
# core_tools # core_tools
tools/pack200/CommandLineTests.java 8059906 generic-all
tools/pack200/TestNormal.java 8234542 generic-all this test can be delisted as soon as pack200 is removed
tools/pack200/Pack200Test.java 8234542 generic-all this test can be delisted as soon as pack200 is removed
tools/pack200/MultiRelease.java 8234542 generic-all this test can be delisted as soon as pack200 is removed
tools/pack200/ModuleAttributes.java 8234542 generic-all this test can be delisted as soon as pack200 is removed
tools/pack200/InstructionTests.java 8234542 generic-all this test can be delisted as soon as pack200 is removed
tools/pack200/AttributeTests.java 8234542 generic-all this test can be delisted as soon as pack200 is removed
tools/pack200/typeannos/TestTypeAnnotations.java 8234542 generic-all this test can be delisted as soon as pack200 is removed
tools/jlink/JLinkReproducibleTest.java 8217166 windows-all tools/jlink/JLinkReproducibleTest.java 8217166 windows-all
############################################################################ ############################################################################

View file

@ -42,8 +42,7 @@ tier1_part3 = \
:jdk_svc_sanity \ :jdk_svc_sanity \
java/nio/Buffer \ java/nio/Buffer \
com/sun/crypto/provider/Cipher \ com/sun/crypto/provider/Cipher \
sun/nio/cs/ISO8859x.java \ sun/nio/cs/ISO8859x.java
tools/pack200
# When adding tests to tier2, make sure they end up in one of the tier2_partX groups # When adding tests to tier2, make sure they end up in one of the tier2_partX groups
tier2 = \ tier2 = \
@ -59,7 +58,6 @@ tier2_part1 = \
# sun/nio/cs/ISO8859x.java and java/nio/Buffer are in tier1 because of JDK-8132854 # sun/nio/cs/ISO8859x.java and java/nio/Buffer are in tier1 because of JDK-8132854
tier2_part2 = \ tier2_part2 = \
:core_tools \ :core_tools \
-tools/pack200 \
:jdk_io \ :jdk_io \
:jdk_nio \ :jdk_nio \
-java/nio/Buffer \ -java/nio/Buffer \

View file

@ -1,39 +0,0 @@
/*
* Copyright (c) 2017, 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.
*
* 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.
*/
/**
* @test
* @bug 8179645
* @run main/othervm SecurityTest
* @summary Verify Pack200 initialization with security manager
*/
import java.util.jar.Pack200;
public class SecurityTest {
public static void main(String... args) {
System.setSecurityManager(new SecurityManager());
Pack200.newPacker();
Pack200.newUnpacker();
}
}

View file

@ -1,96 +0,0 @@
/*
* Copyright (c) 2018, 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.
*
* 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.
*/
/**
* @test
* @bug 8199871
* @modules jdk.jartool
* @summary jar -n should print out deprecation warning
* @run testng DeprecateOptionN
*/
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.spi.ToolProvider;
import org.testng.annotations.Test;
import static org.testng.Assert.assertFalse;
import static org.testng.Assert.assertTrue;
public class DeprecateOptionN {
private static final ToolProvider JAR_TOOL = ToolProvider.findFirst("jar")
.orElseThrow(() ->
new RuntimeException("jar tool not found")
);
protected static String jar(String... options) {
StringWriter writer = new StringWriter();
PrintWriter pw = new PrintWriter(writer);
JAR_TOOL.run(pw, pw, options);
String output = writer.toString();
System.err.println(output);
return output;
}
@Test
public void helpCompatWithWarning() {
String output = jar("--help:compat");
assertTrue(output.contains("this option is deprecated, and is planned for removal in a future JDK release"));
}
@Test
public void helpExtraWithWarning() {
String output = jar("--help-extra");
assertTrue(output.contains("This option is deprecated, and is"));
assertTrue(output.contains("planned for removal in a future JDK release"));
}
@Test
public void normalizeWithWarning() throws IOException {
File tmp = File.createTempFile("test", null);
String output = jar("cnf", "test.jar", tmp.getAbsolutePath());
tmp.delete();
assertTrue(output.contains("Warning: The -n option is deprecated, and is planned for removal in a future JDK release"));
}
@Test
public void NoWarningWithoutN() throws IOException {
File tmp = File.createTempFile("test", null);
String output = jar("cf", "test.jar", tmp.getAbsolutePath());
tmp.delete();
assertFalse(output.contains("Warning: The -n option is deprecated, and is planned for removal in a future JDK release"));
}
@Test
public void SuppressWarning() throws IOException {
File tmp = File.createTempFile("test", null);
String output = jar("-c", "-n", "-XDsuppress-tool-removal-message",
"-f", "test.jar", tmp.getAbsolutePath());
tmp.delete();
assertFalse(output.contains("Warning: The -n option is deprecated, and is planned for removal in a future JDK release"));
}
}

View file

@ -155,12 +155,10 @@ public class HelpFlagsTest extends TestHelper {
new ToolHelpSpec("jstat", 1, 1, 1, 0, 1, 1, 1), // -?, -h, --help -help, Documents -help new ToolHelpSpec("jstat", 1, 1, 1, 0, 1, 1, 1), // -?, -h, --help -help, Documents -help
new ToolHelpSpec("jstatd", 1, 1, 1, 0, 0, 0, 1), // -?, -h, --help new ToolHelpSpec("jstatd", 1, 1, 1, 0, 0, 0, 1), // -?, -h, --help
new ToolHelpSpec("keytool", 1, 1, 1, 0, 1, 0, 1), // none, prints help message anyways. new ToolHelpSpec("keytool", 1, 1, 1, 0, 1, 0, 1), // none, prints help message anyways.
new ToolHelpSpec("pack200", 1, 1, 1, 0, 1, 0, 2), // -?, -h, --help, -help accepted but not documented.
new ToolHelpSpec("rmic", 0, 0, 0, 0, 0, 0, 1), // none, prints help message anyways. new ToolHelpSpec("rmic", 0, 0, 0, 0, 0, 0, 1), // none, prints help message anyways.
new ToolHelpSpec("rmid", 0, 0, 0, 0, 0, 0, 1), // none, prints help message anyways. new ToolHelpSpec("rmid", 0, 0, 0, 0, 0, 0, 1), // none, prints help message anyways.
new ToolHelpSpec("rmiregistry", 0, 0, 0, 0, 0, 0, 1), // none, prints help message anyways. new ToolHelpSpec("rmiregistry", 0, 0, 0, 0, 0, 0, 1), // none, prints help message anyways.
new ToolHelpSpec("serialver", 0, 0, 0, 0, 0, 0, 1), // none, prints help message anyways. new ToolHelpSpec("serialver", 0, 0, 0, 0, 0, 0, 1), // none, prints help message anyways.
new ToolHelpSpec("unpack200", 1, 1, 1, 0, 1, 0, 2), // -?, -h, --help, -help accepted but not documented.
new ToolHelpSpec("jpackage", 0, 1, 1, 0, 0, 1, 1), // -h, --help, new ToolHelpSpec("jpackage", 0, 1, 1, 0, 0, 1, 1), // -h, --help,
}; };

View file

@ -63,8 +63,7 @@ public class VersionCheck extends TestHelper {
"jmc.ini", "jmc.ini",
"jweblauncher", "jweblauncher",
"jpackage", "jpackage",
"ssvagent", "ssvagent"
"unpack200",
}; };
// tools that do not accept -version // tools that do not accept -version
@ -107,15 +106,13 @@ public class VersionCheck extends TestHelper {
"kinit", "kinit",
"klist", "klist",
"ktab", "ktab",
"pack200",
"jpackage", "jpackage",
"rmic", "rmic",
"rmid", "rmid",
"rmiregistry", "rmiregistry",
"serialver", "serialver",
"servertool", "servertool",
"ssvagent", "ssvagent"
"unpack200"
}; };
// expected reference strings // expected reference strings

View file

@ -1,126 +0,0 @@
/*
* Copyright (c) 2010, 2013, 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.
*
* 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.
*/
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/*
* @test
* @bug 6746111 8005252 8008262
* @summary tests various classfile format and attribute handling by pack200
* @compile -XDignore.symbol.file Utils.java AttributeTests.java
* @run main AttributeTests
* @author ksrini
*/
public class AttributeTests {
public static void main(String... args) throws Exception {
test6746111();
testMethodParameters();
Utils.cleanup();
}
/*
* this tests ensure that MethodParameters produces by javac is packed
* correctly. Usually this is not the case as new attributes are available
* in the sdk jars, since MethodParameters happens to be an optional
* attribute, thus this test.
*/
static void testMethodParameters() throws Exception {
List<String> scratch = new ArrayList<>();
final String fname = "MP";
String javaFileName = fname + Utils.JAVA_FILE_EXT;
String javaClassName = fname + Utils.CLASS_FILE_EXT;
scratch.add("class " + fname + " {");
scratch.add("void foo2(int j, final int k){}");
scratch.add("}");
File cwd = new File(".");
File javaFile = new File(cwd, javaFileName);
Utils.createFile(javaFile, scratch);
Utils.compiler(javaFile.getName(), "-parameters");
// jar the file up
File testjarFile = new File(cwd, "test" + Utils.JAR_FILE_EXT);
Utils.jar("cvf", testjarFile.getName(), javaClassName);
Utils.testWithRepack(testjarFile, "--unknown-attribute=error");
}
/*
* this test checks to see if we get the expected strings for output
*/
static void test6746111() throws Exception {
String pack200Cmd = Utils.getPack200Cmd();
File badAttrJar = new File(".", "badattr.jar");
Utils.copyFile(new File(Utils.TEST_SRC_DIR, "badattr.jar"), badAttrJar);
File testJar = new File(".", "test.jar");
List<String> cmds = new ArrayList<String>();
cmds.add(pack200Cmd);
cmds.add("--repack");
cmds.add("-v");
cmds.add(testJar.getAbsolutePath());
cmds.add(badAttrJar.getAbsolutePath());
List<String> output = Utils.runExec(cmds);
/*
* compare the repacked jar bit-wise, as all the files
* should be transmitted "as-is".
*/
Utils.doCompareBitWise(badAttrJar.getAbsoluteFile(), testJar.getAbsoluteFile());
String[] expectedStrings = {
"WARNING: Passing class file uncompressed due to unrecognized" +
" attribute: Foo.class",
"INFO: com.sun.java.util.jar.pack.Attribute$FormatException: " +
"class attribute \"XourceFile\": is unknown attribute " +
"in class Foo",
"INFO: com.sun.java.util.jar.pack.ClassReader$ClassFormatException: " +
"AnnotationDefault: attribute length cannot be zero, in Test.message()",
"WARNING: Passing class file uncompressed due to unknown class format: Test.class"
};
List<String> notfoundList = new ArrayList<String>();
notfoundList.addAll(Arrays.asList(expectedStrings));
// make sure the expected messages are emitted
for (String x : output) {
findString(x, notfoundList, expectedStrings);
}
if (!notfoundList.isEmpty()) {
System.out.println("Not found:");
for (String x : notfoundList) {
System.out.println(x);
}
throw new Exception("Test fails: " + notfoundList.size() +
" expected strings not found");
}
testJar.delete();
badAttrJar.delete();
}
private static void findString(String outputStr, List<String> notfoundList,
String[] expectedStrings) {
for (String y : expectedStrings) {
if (outputStr.contains(y)) {
notfoundList.remove(y);
return;
}
}
}
}

View file

@ -1,62 +0,0 @@
/*
* Copyright (c) 2013, 2018, 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.
*
* 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.
*/
/*
* @test 8187645
* @summary test ensures the proper sequencing of bands, dump bands as well.
* @compile -XDignore.symbol.file Utils.java BandIntegrity.java
* @run main BandIntegrity
* @author ksrini
*/
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/*
* This makes use of the optDebugBands to ensure the bands are read in the
* same sequence as it was written. The caveat is that this works only with
* the java unpacker, therefore it will work only with --repack such that
* the java packer and unpacker must be called in the same java instance.
*/
public class BandIntegrity {
public static void main(String... args) throws IOException {
File testFile = new File("test.jar");
Utils.jar("cvf", testFile.getName(),
"-C", Utils.TEST_CLS_DIR.getAbsolutePath(),
".");
List<String> scratch = new ArrayList<>();
// band debugging works only with java unpacker
scratch.add("com.sun.java.util.jar.pack.disable.native=true");
scratch.add("com.sun.java.util.jar.pack.debug.bands=true");
// while at it, might as well exercise this functionality
scratch.add("com.sun.java.util.jar.pack.dump.bands=true");
scratch.add("pack.unknown.attribute=error");
File configFile = new File("pack.conf");
Utils.createFile(configFile, scratch);
File outFile = new File("out.jar");
Utils.repack(testFile, outFile, true,
"-v", "--config-file=" + configFile.getName());
Utils.cleanup();
}
}

View file

@ -1,185 +0,0 @@
/*
* Copyright (c) 2007, 2014, 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.
*
* 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.
*/
/*
* @test CommandLineTests.sh
* @bug 6521334 6965836 6965836
* @ignore 8059906
* @compile -XDignore.symbol.file CommandLineTests.java Pack200Test.java
* @run main/timeout=1200 CommandLineTests
* @summary An ad hoc test to verify the behavior of pack200/unpack200 CLIs,
* and a simulation of pack/unpacking in the install repo.
* @author ksrini
*/
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;
/*
* We try a potpouri of things ie. we have pack.conf to setup some
* options as well as a couple of command line options. We also test
* the packing and unpacking mechanism using the Java APIs. This also
* simulates pack200 the install workspace, noting that this is a simulation
* and can only test jars that are guaranteed to be available, also the
* configuration may not be in sync with the installer workspace.
*/
public class CommandLineTests {
private static final File CWD = new File(".");
private static final File EXP_SDK = new File(CWD, "exp-sdk-image");
private static final File EXP_SDK_LIB_DIR = new File(EXP_SDK, "lib");
private static final File EXP_SDK_BIN_DIR = new File(EXP_SDK, "bin");
private static final File EXP_JRE_DIR = new File(EXP_SDK, "jre");
private static final File EXP_JRE_LIB_DIR = new File(EXP_JRE_DIR, "lib");
private static final File RtJar = new File(EXP_JRE_LIB_DIR, "rt.jar");
private static final File CharsetsJar = new File(EXP_JRE_LIB_DIR, "charsets.jar");
private static final File JsseJar = new File(EXP_JRE_LIB_DIR, "jsse.jar");
private static final File ToolsJar = new File(EXP_SDK_LIB_DIR, "tools.jar");
private static final File javaCmd;
private static final File javacCmd;
private static final File ConfigFile = new File("pack.conf");
private static final List<File> jarList;
static {
javaCmd = Utils.IsWindows
? new File(EXP_SDK_BIN_DIR, "java.exe")
: new File(EXP_SDK_BIN_DIR, "java");
javacCmd = Utils.IsWindows
? new File(EXP_SDK_BIN_DIR, "javac.exe")
: new File(EXP_SDK_BIN_DIR, "javac");
jarList = new ArrayList<File>();
jarList.add(RtJar);
jarList.add(CharsetsJar);
jarList.add(JsseJar);
jarList.add(ToolsJar);
}
// init test area with a copy of the sdk
static void init() throws IOException {
Utils.recursiveCopy(Utils.JavaSDK, EXP_SDK);
creatConfigFile();
}
// cleanup the test area
static void cleanup() throws IOException {
Utils.recursiveDelete(EXP_SDK);
Utils.cleanup();
}
// Hopefully, this should be kept in sync with what the installer does.
static void creatConfigFile() throws IOException {
FileOutputStream fos = null;
PrintStream ps = null;
try {
fos = new FileOutputStream(ConfigFile);
ps = new PrintStream(fos);
ps.println("com.sun.java.util.jar.pack.debug.verbose=0");
ps.println("pack.modification.time=keep");
ps.println("pack.keep.class.order=true");
ps.println("pack.deflate.hint=false");
// Fail the build, if new or unknown attributes are introduced.
ps.println("pack.unknown.attribute=error");
ps.println("pack.segment.limit=-1");
// BugId: 6328502, These files will be passed-through as-is.
ps.println("pack.pass.file.0=java/lang/Error.class");
ps.println("pack.pass.file.1=java/lang/LinkageError.class");
ps.println("pack.pass.file.2=java/lang/Object.class");
ps.println("pack.pass.file.3=java/lang/Throwable.class");
ps.println("pack.pass.file.4=java/lang/VerifyError.class");
} finally {
Utils.close(ps);
Utils.close(fos);
}
}
static void runPack200(boolean jre) throws IOException {
List<String> cmdsList = new ArrayList<String>();
for (File f : jarList) {
if (jre && f.getName().equals("tools.jar")) {
continue; // need not worry about tools.jar for JRE
}
// make a backup copy for re-use
File bakFile = new File(f.getName() + ".bak");
if (!bakFile.exists()) { // backup
Utils.copyFile(f, bakFile);
} else { // restore
Utils.copyFile(bakFile, f);
}
cmdsList.clear();
cmdsList.add(Utils.getPack200Cmd());
cmdsList.add("-J-esa");
cmdsList.add("-J-ea");
cmdsList.add(Utils.Is64Bit ? "-J-Xmx1g" : "-J-Xmx512m");
cmdsList.add("--repack");
cmdsList.add("--config-file=" + ConfigFile.getAbsolutePath());
if (jre) {
cmdsList.add("--strip-debug");
}
// NOTE: commented until 6965836 is fixed
// cmdsList.add("--code-attribute=StackMapTable=strip");
cmdsList.add(f.getAbsolutePath());
Utils.runExec(cmdsList);
}
}
static void testJRE() throws IOException {
runPack200(true);
// the speciment JRE
List<String> cmdsList = new ArrayList<String>();
cmdsList.add(javaCmd.getAbsolutePath());
cmdsList.add("-verify");
cmdsList.add("-version");
Utils.runExec(cmdsList);
}
static void testJDK() throws IOException {
runPack200(false);
// test the specimen JDK
List<String> cmdsList = new ArrayList<String>();
cmdsList.add(javaCmd.getAbsolutePath());
cmdsList.add("-verify");
cmdsList.add("-version");
Utils.runExec(cmdsList);
// invoke javac to test the tools.jar
cmdsList.clear();
cmdsList.add(javacCmd.getAbsolutePath());
cmdsList.add("-J-verify");
cmdsList.add("-help");
Utils.runExec(cmdsList);
}
public static void main(String... args) {
try {
init();
testJRE();
testJDK();
cleanup(); // cleanup only if we pass successfully
} catch (IOException ioe) {
throw new RuntimeException(ioe);
}
}
}

View file

@ -1,75 +0,0 @@
/*
* Copyright (c) 2018, 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.
*
* 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.
*/
/**
* @test
* @bug 8199871
* @summary pack200 and unpack200 should print out deprecate warning
* @modules jdk.pack
* @compile -XDignore.symbol.file Utils.java
* @run testng DeprecatePack200
*/
import java.util.List;
import java.util.function.Predicate;
import java.util.regex.Pattern;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import static org.testng.Assert.assertEquals;
public class DeprecatePack200 {
final static String PACK200_CMD = Utils.getPack200Cmd();
final static String UNPACK200_CMD = Utils.getUnpack200Cmd();
final static Predicate<String> PACK200_MSG = Pattern.compile(
"Warning: The pack200(\\.exe)?? tool is deprecated, and is planned for removal in a future JDK release.")
.asMatchPredicate();
final static Predicate<String> UNPACK200_MSG = Pattern.compile(
"Warning: The unpack200(\\.exe)?? tool is deprecated, and is planned for removal in a future JDK release.")
.asMatchPredicate();
@DataProvider(name="tools")
public static final Object[][] provide() { return cases; }
private static final Object[][] cases = {
{ PACK200_MSG, 1, List.of(PACK200_CMD) },
{ PACK200_MSG, 1, List.of(PACK200_CMD, "-V") },
{ PACK200_MSG, 2, List.of(PACK200_CMD, "--help") },
{ PACK200_MSG, 0, List.of(PACK200_CMD, "-XDsuppress-tool-removal-message") },
{ PACK200_MSG, 0, List.of(PACK200_CMD, "--version", "-XDsuppress-tool-removal-message") },
{ PACK200_MSG, 0, List.of(PACK200_CMD, "-h", "-XDsuppress-tool-removal-message") },
{ UNPACK200_MSG, 1, List.of(UNPACK200_CMD) },
{ UNPACK200_MSG, 1, List.of(UNPACK200_CMD, "-V") },
{ UNPACK200_MSG, 1, List.of(UNPACK200_CMD, "--help") },
{ UNPACK200_MSG, 0, List.of(UNPACK200_CMD, "-XDsuppress-tool-removal-message") },
{ UNPACK200_MSG, 0, List.of(UNPACK200_CMD, "--version", "-XDsuppress-tool-removal-message") },
{ UNPACK200_MSG, 0, List.of(UNPACK200_CMD, "-h", "-XDsuppress-tool-removal-message") }
};
@Test(dataProvider = "tools")
public void CheckWarnings(Predicate<String> msg, long count, List<String> cmd) {
List<String> output = Utils.runExec(cmd, null, true);
assertEquals(output.stream().filter(msg).count(), count);
}
}

View file

@ -1,76 +0,0 @@
/*
* Copyright (c) 2013, 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.
*
* 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.
*/
import java.io.File;
import java.util.ArrayList;
import java.util.List;
/*
* @test
* @bug 8003549 8007297
* @summary tests class files instruction formats introduced in JSR-335
* @compile -XDignore.symbol.file Utils.java InstructionTests.java
* @run main InstructionTests
* @author ksrini
*/
public class InstructionTests {
public static void main(String... args) throws Exception {
testInvokeOpCodes();
Utils.cleanup();
}
/*
* the following should produce invokestatic and invokespecial
* on InterfaceMethodRefs vs. MethodRefs, packer/unpacker should work
*/
static void testInvokeOpCodes() throws Exception {
List<String> scratch = new ArrayList<>();
final String fname = "A";
String javaFileName = fname + Utils.JAVA_FILE_EXT;
scratch.add("interface I {");
scratch.add(" default void forEach(){}");
scratch.add(" static void next() {}");
scratch.add("}");
scratch.add("class A implements I {");
scratch.add(" public void forEach(Object o){");
scratch.add(" I.super.forEach();");
scratch.add(" I.next();");
scratch.add(" }");
scratch.add("}");
File cwd = new File(".");
File javaFile = new File(cwd, javaFileName);
Utils.createFile(javaFile, scratch);
// -g to compare LVT and LNT entries
Utils.compiler("-g", javaFile.getName());
File propsFile = new File("pack.props");
scratch.clear();
scratch.add("com.sun.java.util.jar.pack.class.format.error=error");
scratch.add("pack.unknown.attribute=error");
Utils.createFile(propsFile, scratch);
// jar the file up
File testjarFile = new File(cwd, "test" + Utils.JAR_FILE_EXT);
Utils.jar("cvf", testjarFile.getName(), ".");
Utils.testWithRepack(testjarFile, "--config-file=" + propsFile.getName());
}
}

View file

@ -1,50 +0,0 @@
/*
* Copyright (c) 2014, 2018, 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.
*
* 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.
*/
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/*
* @test
* @bug 8048100
* @summary test the new Module attributes
* @modules jdk.compiler
* jdk.zipfs
* @compile -XDignore.symbol.file Utils.java ModuleAttributes.java
* @run main ModuleAttributes
*/
public class ModuleAttributes {
public static void main(String... args) throws Exception {
new ModuleAttributes().run();
}
public void run() throws Exception {
File file = Utils.createRtJar(".*module-info\\.class");
Utils.testWithRepack(file,
"--effort=1",
"--unknown-attribute=error");
Utils.cleanup();
}
}

View file

@ -1,258 +0,0 @@
/*
* Copyright (c) 2015, 2016, 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.
*
* 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.
*/
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/*
* @test
* @bug 8066272
* @summary tests a simple multi-versioned jar file
* @compile -XDignore.symbol.file Utils.java MultiRelease.java
* @run main MultiRelease
* @author ksrini
*/
public class MultiRelease {
private static final File cwd = new File(".");
private static int pass = 0;
private static int fail = 0;
// specify alternate name via arguments to verify
// if permanent fix works
private static final String PropKey = "pack200.MultiRelease.META-INF";
private static final String MetaInfName = System.getProperty(PropKey, "META-INF");
public static void main(String... args) throws Exception {
new MultiRelease().run();
}
void run() throws Exception {
List<TestCase> testCases = new ArrayList<>();
testCases.add(new TestCase1());
testCases.add(new TestCase2());
for (TestCase tc : testCases) {
tc.run();
}
if (fail > 0) {
throw new Exception(fail + "/" + testCases.size() + " tests fails");
} else {
System.out.println("All tests(" + pass + ") passes");
}
Utils.cleanup();
}
/*
* An abstract class to eliminate test boiler plating.
*/
static abstract class TestCase {
final File tcwd;
final File metaInfDir;
final File versionsDir;
final File manifestFile;
TestCase(String directory) throws IOException {
System.out.println("initializing directories");
tcwd = new File(cwd, directory);
metaInfDir = mkdir(new File(tcwd, MetaInfName));
versionsDir = mkdir(new File(metaInfDir, "versions"));
manifestFile = new File(tcwd, "manifest.tmp");
List<String> scratch = new ArrayList<>();
scratch.add("Multi-Release: true");
Utils.createFile(manifestFile, scratch);
}
File mkdir(File f) throws IOException {
if (f.exists() && f.isDirectory() && f.canRead() && f.canWrite()) {
return f;
}
if (!f.mkdirs()) {
throw new IOException("mkdirs failed: " + f.getAbsolutePath());
}
return f;
}
abstract void emitClassFiles() throws Exception;
void run() {
try {
emitClassFiles();
// jar the file up
File testFile = new File(tcwd, "test" + Utils.JAR_FILE_EXT);
Utils.jar("cvfm",
testFile.getAbsolutePath(),
manifestFile.getAbsolutePath(),
"-C",
tcwd.getAbsolutePath(),
".");
File outFile = new File(tcwd, "test-repacked" + Utils.JAR_FILE_EXT);
List<String> cmdsList = new ArrayList<>();
cmdsList.add(Utils.getPack200Cmd());
cmdsList.add("-J-ea");
cmdsList.add("-J-esa");
cmdsList.add("-v");
cmdsList.add("--repack");
cmdsList.add(outFile.getAbsolutePath());
cmdsList.add(testFile.getAbsolutePath());
List<String> output = Utils.runExec(cmdsList);
Utils.doCompareVerify(testFile.getAbsoluteFile(), outFile.getAbsoluteFile());
pass++;
} catch (Exception e) {
e.printStackTrace(System.err);
fail++;
}
}
}
static class TestCase1 extends TestCase {
private TestCase1(String directory) throws IOException {
super(directory);
}
public TestCase1() throws Exception {
this("case1");
}
@Override
void emitClassFiles() throws Exception {
emitClassFile("");
emitClassFile("7");
emitClassFile("8");
emitClassFile("9");
}
/*
* Adds different variants of types
*/
void emitClassFile(String version) throws IOException {
final File outDir = mkdir(version.isEmpty()
? tcwd
: new File(versionsDir, version));
final File srcDir = mkdir(version.isEmpty()
? new File(tcwd, "src")
: new File(new File(versionsDir, version), "src"));
final String fname = "Foo";
final File srcFile = new File(srcDir, fname + Utils.JAVA_FILE_EXT);
List<String> scratch = new ArrayList<>();
scratch.add("package pkg;");
switch (version) {
case "7":
scratch.add("public class Foo {");
scratch.add("public static final class Bar {}");
break;
case "8":
scratch.add("public abstract class Foo {");
scratch.add("public final class Bar {}");
break;
case "9":
scratch.add("public interface Foo {");
scratch.add("public final class Bar {}");
break;
default:
scratch.add("public class Foo {");
scratch.add("public final class Bar {}");
break;
}
scratch.add("}");
Utils.createFile(srcFile, scratch);
Utils.compiler("-d",
outDir.getAbsolutePath(),
srcFile.getAbsolutePath());
}
}
static class TestCase2 extends TestCase {
private TestCase2(String directory) throws IOException {
super(directory);
}
TestCase2() throws Exception {
this("case2");
}
@Override
void emitClassFiles() throws Exception {
emitClassFile("");
emitClassFile("8");
}
/*
* Adds different variants of types and tries to invoke an
* interface or concrete method defined by them.
*/
void emitClassFile(String version) throws IOException {
final File outDir = mkdir(version.isEmpty()
? tcwd
: new File(versionsDir, version));
final File srcDir = mkdir(version.isEmpty()
? new File(tcwd, "src")
: new File(new File(versionsDir, version), "src"));
List<String> scratch = new ArrayList<>();
final String fname1 = "Ab";
final File srcFile1 = new File(srcDir, fname1 + Utils.JAVA_FILE_EXT);
final String fname2 = "AbNormal";
final File srcFile2 = new File(srcDir, fname2 + Utils.JAVA_FILE_EXT);
switch (version) {
case "8":
scratch.clear();
scratch.add("import java.io.IOException;");
scratch.add("public interface " + fname1 + "{");
scratch.add(" public abstract void close() throws IOException ;");
scratch.add("}");
Utils.createFile(srcFile1, scratch);
break;
default:
scratch.clear();
scratch.add("import java.io.IOException;");
scratch.add("public abstract class " + fname1 + "{");
scratch.add(" public abstract void close() throws IOException ;");
scratch.add("}");
Utils.createFile(srcFile1, scratch);
}
scratch.clear();
scratch.add("import java.io.IOException;");
scratch.add("public class " + fname2 + "{");
scratch.add(" public void doSomething(Ab ab) throws IOException {");
scratch.add(" ab.close();");
scratch.add(" }");
scratch.add("}");
Utils.createFile(srcFile2, scratch);
Utils.compiler("-d",
outDir.getAbsolutePath(),
srcFile1.getAbsolutePath(),
srcFile2.getAbsolutePath());
}
}
}

View file

@ -1,139 +0,0 @@
/*
* Copyright (c) 2010, 2018, 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.
*
* 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.
*/
/*
* @test
* @bug 6575373 6969063
* @summary verify default properties of the packer/unpacker and segment limit
* @modules java.logging
* jdk.compiler
* jdk.zipfs
* @compile -XDignore.symbol.file Utils.java Pack200Props.java
* @run main Pack200Props
* @author ksrini
*/
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.jar.Pack200;
import java.util.jar.Pack200.Packer;
import java.util.logging.Logger;
/*
* Run this against a large jar file, by default the packer should generate only
* one segment, parse the output of the packer to verify if this is indeed true.
*/
public class Pack200Props {
final static Logger log = Logger.getLogger("Pack200Props");
public static void main(String... args) throws Exception {
verifyDefaults();
File out = new File("test" + Utils.PACK_FILE_EXT);
out.delete();
verifySegmentLimit(out);
log.info("cleanup");
Utils.cleanup();
}
static void verifySegmentLimit(File outFile) throws Exception {
log.info("creating jar");
File testJar = Utils.createRtJar();
log.info("using pack200: " + Utils.getPack200Cmd());
List<String> cmdsList = new ArrayList<>();
cmdsList.add(Utils.getPack200Cmd());
cmdsList.add("-J-Xshare:off");
cmdsList.add("-J-Xmx1280m");
cmdsList.add("--effort=1");
cmdsList.add("--verbose");
cmdsList.add("--no-gzip");
cmdsList.add(outFile.getName());
cmdsList.add(testJar.getAbsolutePath());
List<String> outList = Utils.runExec(cmdsList);
log.info("verifying");
int count = 0;
for (String line : outList) {
System.out.println(line);
if (line.matches(".*Transmitted.*files of.*input bytes in a segment of.*bytes")) {
count++;
}
}
log.info("fini");
if (count == 0) {
throw new RuntimeException("no segments or no output ????");
} else if (count > 1) {
throw new RuntimeException("multiple segments detected, expected 1");
}
}
private static void verifyDefaults() {
log.info("start");
Map<String, String> expectedDefaults = new HashMap<>();
Packer p = Pack200.newPacker();
expectedDefaults.put("com.sun.java.util.jar.pack.disable.native",
p.FALSE);
expectedDefaults.put("com.sun.java.util.jar.pack.verbose", "0");
expectedDefaults.put(p.CLASS_ATTRIBUTE_PFX + "CompilationID", "RUH");
expectedDefaults.put(p.CLASS_ATTRIBUTE_PFX + "SourceID", "RUH");
expectedDefaults.put(p.CODE_ATTRIBUTE_PFX + "CharacterRangeTable",
"NH[PHPOHIIH]");
expectedDefaults.put(p.CODE_ATTRIBUTE_PFX + "CoverageTable",
"NH[PHHII]");
expectedDefaults.put(p.DEFLATE_HINT, p.KEEP);
expectedDefaults.put(p.EFFORT, "5");
expectedDefaults.put(p.KEEP_FILE_ORDER, p.TRUE);
expectedDefaults.put(p.MODIFICATION_TIME, p.KEEP);
expectedDefaults.put(p.SEGMENT_LIMIT, "-1");
expectedDefaults.put(p.UNKNOWN_ATTRIBUTE, p.PASS);
Map<String, String> props = p.properties();
int errors = 0;
for (String key : expectedDefaults.keySet()) {
String def = expectedDefaults.get(key);
String x = props.get(key);
if (x == null) {
System.out.println("Error: key not found:" + key);
errors++;
} else {
if (!def.equals(x)) {
System.out.println("Error: key " + key
+ "\n value expected: " + def
+ "\n value obtained: " + x);
errors++;
}
}
}
log.info("fini");
if (errors > 0) {
throw new RuntimeException(errors +
" error(s) encountered in default properties verification");
}
}
}

View file

@ -1,142 +0,0 @@
/*
* Copyright (c) 2007, 2018, 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.
*
* 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.
*/
/*
* @test
* @bug 6521334 6712743 8007902 8151901
* @requires (sun.arch.data.model == "64" & os.maxMemory >= 4g)
* @summary test general packer/unpacker functionality
* using native and java unpackers
* @modules jdk.management
* jdk.zipfs
* @compile -XDignore.symbol.file Utils.java Pack200Test.java
* @run main/othervm/timeout=1200 -Xmx1280m -Xshare:off Pack200Test
*/
import java.util.*;
import java.io.*;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
import java.util.jar.*;
/**
* Tests the packing/unpacking via the APIs.
*/
public class Pack200Test {
private static ArrayList <File> jarList = new ArrayList<File>();
static final MemoryMXBean mmxbean = ManagementFactory.getMemoryMXBean();
static final long m0 = getUsedMemory();
static final int LEAK_TOLERANCE = 21000; // OS and GC related variations.
// enable leak checks only if required, GC charecteristics vary on
// platforms and this may not yield consistent results
static final boolean LEAK_CHECK = Boolean.getBoolean("Pack200Test.enableLeakCheck");
/** Creates a new instance of Pack200Test */
private Pack200Test() {}
static long getUsedMemory() {
mmxbean.gc();
mmxbean.gc();
mmxbean.gc();
return mmxbean.getHeapMemoryUsage().getUsed()/1024;
}
private static void leakCheck() throws Exception {
if (!LEAK_CHECK)
return;
long diff = getUsedMemory() - m0;
System.out.println(" Info: memory diff = " + diff + "K");
if (diff > LEAK_TOLERANCE) {
throw new Exception("memory leak detected " + diff);
}
}
private static void doPackUnpack() throws IOException {
for (File in : jarList) {
JarOutputStream javaUnpackerStream = null;
JarOutputStream nativeUnpackerStream = null;
JarFile jarFile = null;
try {
jarFile = new JarFile(in);
// Write out to a jtreg scratch area
File packFile = new File(in.getName() + Utils.PACK_FILE_EXT);
System.out.println("Packing [" + in.toString() + "]");
// Call the packer
Utils.pack(jarFile, packFile);
System.out.println("Done Packing [" + in.toString() + "]");
jarFile.close();
System.out.println("Start leak check");
leakCheck();
System.out.println(" Unpacking using java unpacker");
File javaUnpackedJar = new File("java-" + in.getName());
// Write out to current directory, jtreg will setup a scratch area
javaUnpackerStream = new JarOutputStream(
new FileOutputStream(javaUnpackedJar));
Utils.unpackj(packFile, javaUnpackerStream);
javaUnpackerStream.close();
System.out.println(" Testing...java unpacker");
leakCheck();
// Ok we have unpacked the file, lets test it.
Utils.doCompareVerify(in.getAbsoluteFile(), javaUnpackedJar);
System.out.println(" Unpacking using native unpacker");
// Write out to current directory
File nativeUnpackedJar = new File("native-" + in.getName());
nativeUnpackerStream = new JarOutputStream(
new FileOutputStream(nativeUnpackedJar));
Utils.unpackn(packFile, nativeUnpackerStream);
nativeUnpackerStream.close();
System.out.println(" Testing...native unpacker");
leakCheck();
// the unpackers (native and java) should produce identical bits
// so we use use bit wise compare, the verification compare is
// very expensive wrt. time.
Utils.doCompareBitWise(javaUnpackedJar, nativeUnpackedJar);
System.out.println("Done.");
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
Utils.close(nativeUnpackerStream);
Utils.close(javaUnpackerStream);
Utils.close((Closeable) jarFile);
}
}
Utils.cleanup(); // cleanup artifacts, if successful run
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) throws Exception {
// select the jars carefully, adding more jars will increase the
// testing time.
jarList.add(Utils.createRtJar());
jarList.add(Utils.getGoldenJar());
System.out.println(jarList);
doPackUnpack();
}
}

View file

@ -1,178 +0,0 @@
/*
* Copyright (c) 2014, 2016, 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.
*
* 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.
*/
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream;
/*
* @test
* @bug 8000650 8150469
* @summary unpack200.exe should check gzip crc
* @compile -XDignore.symbol.file Utils.java PackChecksum.java
* @run main PackChecksum
* @author kizune
*/
public class PackChecksum {
final int TRAILER_LEN = 8;
final List<String> cmdsList = new ArrayList<>();
static enum Case {
CRC32,
ISIZE,
BOTH;
};
public static void main(String... args) throws Exception {
new PackChecksum().run();
}
void run() throws Exception {
testBrokenTrailer(Case.CRC32); // negative
testBrokenTrailer(Case.ISIZE); // negative
testBrokenTrailer(Case.BOTH); // negative
testMultipleSegments();
}
void testMultipleSegments() throws Exception {
File inputJar = new File("input.jar");
Utils.copyFile(Utils.getGoldenJar(), inputJar);
cmdsList.clear();
File testPack = new File("out.jar.pack.gz");
cmdsList.clear();
cmdsList.add(Utils.getPack200Cmd());
// force multiple segments
cmdsList.add("--segment-limit=100");
cmdsList.add(testPack.getName());
cmdsList.add(inputJar.getName());
Utils.runExec(cmdsList);
File destFile = new File("dst.jar");
cmdsList.clear();
cmdsList.add(Utils.getUnpack200Cmd());
cmdsList.add(testPack.getName());
cmdsList.add(destFile.getName());
try {
Utils.runExec(cmdsList);
if (!destFile.exists()) {
throw new Exception("file not created: " + destFile);
}
} finally {
if (inputJar.exists())
inputJar.delete();
if (testPack.exists())
testPack.delete();
if (destFile.exists())
destFile.delete();
}
}
void testBrokenTrailer(Case type) throws Exception {
System.out.println("Testing: case " + type);
// Create a fresh .jar file
File testFile = new File("src_tools.jar");
File testPack = new File("src_tools.pack.gz");
generateJar(testFile);
cmdsList.clear();
// Create .pack file
cmdsList.add(Utils.getPack200Cmd());
cmdsList.add(testPack.getName());
cmdsList.add(testFile.getName());
Utils.runExec(cmdsList);
// mutate the checksum of the packed file
RandomAccessFile raf = new RandomAccessFile(testPack, "rw");
switch (type) {
case CRC32:
raf.seek(raf.length() - TRAILER_LEN);
raf.writeInt(0x0dea0a0d);
break;
case ISIZE:
raf.seek(raf.length() - (TRAILER_LEN/2));
raf.writeInt(0x0b0e0e0f);
break;
default:
raf.seek(raf.length() - (TRAILER_LEN));
raf.writeLong(0x0dea0a0d0b0e0e0fL);
break;
}
raf.close();
File dstFile = new File("dst_tools.jar");
if (dstFile.exists()) {
dstFile.delete();
}
cmdsList.clear();
cmdsList.add(Utils.getUnpack200Cmd());
cmdsList.add(testPack.getName());
cmdsList.add(dstFile.getName());
boolean processFailed = false;
try {
Utils.runExec(cmdsList);
} catch (RuntimeException re) {
// unpack200 should exit with non-zero exit code
processFailed = true;
} finally {
// tidy up
if (testFile.exists())
testFile.delete();
if (testPack.exists())
testPack.delete();
if (!processFailed) {
throw new Exception("case " + type +
": file with incorrect CRC, unpacked without the error.");
}
if (dstFile.exists()) {
dstFile.delete();
throw new Exception("case " + type +
": file exists: " + dstFile);
}
}
}
void generateJar(File result) throws IOException {
if (result.exists()) {
result.delete();
}
try (JarOutputStream output = new JarOutputStream(new FileOutputStream(result)); ) {
for (int i = 0 ; i < 100 ; i++) {
JarEntry e = new JarEntry("F-" + i + ".txt");
output.putNextEntry(e);
}
output.flush();
output.close();
}
}
}

View file

@ -1,160 +0,0 @@
/*
* Copyright (c) 2014, 2015, 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.
*
* 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.
*/
import java.io.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarInputStream;
import java.util.jar.JarOutputStream;
import java.util.zip.ZipEntry;
/*
* @test
* @bug 8029646
* @summary tests that native unpacker produces the same result as Java one
* @compile -XDignore.symbol.file Utils.java PackTestZip64.java
* @run main PackTestZip64
* @author kizune
*/
public class PackTestZip64 {
private static final boolean bigJarEnabled
= Boolean.getBoolean("PackTestZip64.enableBigJar");
public static void main(String... args) throws Exception {
testPacking();
Utils.cleanup();
}
// 1KB buffer is enough to copy jar content
private static final byte[] BUFFER = new byte[1024];
static void testPacking() throws IOException {
File testFile = new File("tools_java.jar");
if (bigJarEnabled) {
// Add a large number of small files to the golden jar
generateLargeJar(testFile, Utils.getGoldenJar());
} else {
// make a copy of the test specimen to local directory
Utils.copyFile(Utils.getGoldenJar(), testFile);
}
List<String> cmdsList = new ArrayList<>();
// Repack file to get the Java-based result
cmdsList.add(Utils.getPack200Cmd());
cmdsList.add("--repack");
cmdsList.add(testFile.getName());
Utils.runExec(cmdsList);
cmdsList.clear();
// Pack file with pack200 and unpack in with unpack200
File packedFile = new File("tools.pack.gz");
cmdsList.add(Utils.getPack200Cmd());
cmdsList.add(packedFile.getName());
cmdsList.add(testFile.getName());
Utils.runExec(cmdsList);
cmdsList.clear();
File unpackedFile = new File("tools_native.jar");
cmdsList.add(Utils.getUnpack200Cmd());
cmdsList.add(packedFile.getName());
cmdsList.add(unpackedFile.getName());
Utils.runExec(cmdsList);
// Compare files binary
compareTwoFiles(testFile, unpackedFile);
// Cleaning up generated files
testFile.delete();
packedFile.delete();
unpackedFile.delete();
}
static void compareTwoFiles(File src, File dst) throws IOException {
if (!src.exists()) {
throw new IOException("File " + src.getName() + " does not exist!");
}
if(!dst.exists()) {
throw new IOException("File " + dst.getName() + " does not exist!");
}
BufferedInputStream srcis, dstis;
srcis = new BufferedInputStream(new FileInputStream(src));
dstis = new BufferedInputStream(new FileInputStream(dst));
int s = 0, d, pos = 0;
while (s != -1) { // Checking of just one result for EOF is enough
s = srcis.read();
d = dstis.read();
if (s != d) {
throw new IOException("Files are differ starting at position: "
+ Integer.toHexString(pos));
}
pos++;
}
srcis.close();
dstis.close();
}
static void generateLargeJar(File result, File source) throws IOException {
if (result.exists()) {
result.delete();
}
try (JarOutputStream copyTo = new JarOutputStream(new FileOutputStream(result));
JarFile srcJar = new JarFile(source)) {
for (JarEntry je : Collections.list(srcJar.entries())) {
copyTo.putNextEntry(je);
if (!je.isDirectory()) {
copyStream(srcJar.getInputStream(je), copyTo);
}
copyTo.closeEntry();
}
int many = Short.MAX_VALUE * 2 + 2;
for (int i = 0 ; i < many ; i++) {
JarEntry e = new JarEntry("F-" + i + ".txt");
copyTo.putNextEntry(e);
}
copyTo.flush();
copyTo.close();
}
}
static void copyStream(InputStream in, OutputStream out) throws IOException {
int bytesRead;
while ((bytesRead = in.read(BUFFER))!= -1) {
out.write(BUFFER, 0, bytesRead);
}
}
}

View file

@ -1,33 +0,0 @@
/*
* Copyright (c) 2015, 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.
*
* 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.
*/
/*
* @test
* @bug 8029646
* @summary tests that native unpacker produces the same result as Java one
* @compile -XDignore.symbol.file Utils.java PackTestZip64.java
* @run main/manual/othervm -DPackTestZip64.enableBigJar=true PackTestZip64
*/
public class PackTestZip64Manual {
}

View file

@ -1,156 +0,0 @@
/*
* Copyright (c) 2010, 2018, 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.
*
* 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.
*/
/*
* @test
* @bug 6712743 6991164 7168401
* @summary verify package versions
* @compile -XDignore.symbol.file Utils.java PackageVersionTest.java
* @run main PackageVersionTest
* @author ksrini
*/
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.util.jar.JarFile;
import java.util.jar.Pack200;
import java.util.jar.Pack200.Packer;
import java.util.jar.Pack200.Unpacker;
public class PackageVersionTest {
private static final File javaHome = new File(System.getProperty("java.home"));
public final static int JAVA5_PACKAGE_MAJOR_VERSION = 150;
public final static int JAVA5_PACKAGE_MINOR_VERSION = 7;
public final static int JAVA6_PACKAGE_MAJOR_VERSION = 160;
public final static int JAVA6_PACKAGE_MINOR_VERSION = 1;
public final static int JAVA7_PACKAGE_MAJOR_VERSION = 170;
public final static int JAVA7_PACKAGE_MINOR_VERSION = 1;
public static void main(String... args) throws IOException {
File out = new File("test.pack");
createClassFile("Test6");
createClassFile("Test7");
verify6991164();
// a jar file devoid of indy classes must generate 160.1 package file
verifyPack("Test7.class", JAVA6_PACKAGE_MAJOR_VERSION,
JAVA6_PACKAGE_MINOR_VERSION);
// test for resource file, ie. no class files
verifyPack("Test6.java", JAVA5_PACKAGE_MAJOR_VERSION,
JAVA5_PACKAGE_MINOR_VERSION);
Utils.cleanup();
}
static void verify6991164() {
Unpacker unpacker = Pack200.newUnpacker();
String versionStr = unpacker.toString();
String expected = "Pack200, Vendor: " +
System.getProperty("java.vendor") + ", Version: " +
JAVA7_PACKAGE_MAJOR_VERSION + "." + JAVA7_PACKAGE_MINOR_VERSION;
if (!versionStr.equals(expected)) {
System.out.println("Expected: " + expected);
System.out.println("Obtained: " + versionStr);
throw new RuntimeException("did not get expected string " + expected);
}
}
static void createClassFile(String name) {
createJavaFile(name);
String target = name.substring(name.length() - 1);
String javacCmds[] = {
"-source",
"7",
"-target",
"7",
"-Xlint:-options",
name + ".java"
};
Utils.compiler(javacCmds);
}
static void createJavaFile(String name) {
PrintStream ps = null;
FileOutputStream fos = null;
File outputFile = new File(name + ".java");
outputFile.delete();
try {
fos = new FileOutputStream(outputFile);
ps = new PrintStream(fos);
ps.format("public class %s {}", name);
} catch (IOException ioe) {
throw new RuntimeException("creation of test file failed");
} finally {
Utils.close(ps);
Utils.close(fos);
}
}
static void verifyPack(String filename, int expected_major, int expected_minor) {
File jarFileName = new File("test.jar");
jarFileName.delete();
String jargs[] = {
"cvf",
jarFileName.getName(),
filename
};
Utils.jar(jargs);
JarFile jfin = null;
try {
jfin = new JarFile(jarFileName);
Packer packer = Pack200.newPacker();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
packer.pack(jfin, baos);
baos.flush();
baos.close();
byte[] buf = baos.toByteArray();
int minor = buf[4] & 0x000000ff;
int major = buf[5] & 0x000000ff;
if (major != expected_major || minor != expected_minor) {
String msg =
String.format("test fails: expected:%d.%d but got %d.%d\n",
expected_major, expected_minor,
major, minor);
throw new Error(msg);
}
System.out.println(filename + ": OK");
} catch (IOException ioe) {
throw new RuntimeException(ioe.getMessage());
} finally {
Utils.close((Closeable) jfin);
}
}
}

View file

@ -1,75 +0,0 @@
/*
* Copyright (c) 2012, 2014, 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.
*
* 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.
*/
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/*
* @test
* @bug 7184145
* @summary tests repacking of a simple named jarfile.
* @compile -XDignore.symbol.file Utils.java RepackTest.java
* @run main RepackTest
* @author ksrini
*/
public class RepackTest {
public static void main(String... args) throws Exception {
testRepack();
Utils.cleanup();
}
/*
* there are two cases we need to test, where the file in question is
* orpaned, ie. without a parent ie. not qualified by a parent path
* relative nor absolute
* case 1: src and dest are the same
* case 2: src and dest are different
*/
static void testRepack() throws IOException {
// make a copy of the test specimen to local directory
File testFile = new File("src_tools.jar");
Utils.copyFile(Utils.getGoldenJar(), testFile);
List<String> cmdsList = new ArrayList<>();
// case 1:
cmdsList.add(Utils.getPack200Cmd());
cmdsList.add("--repack");
cmdsList.add(testFile.getName());
Utils.runExec(cmdsList);
// case 2:
File dstFile = new File("dst_tools.jar");
cmdsList.clear();
cmdsList.add(Utils.getPack200Cmd());
cmdsList.add("--repack");
cmdsList.add(dstFile.getName());
cmdsList.add(testFile.getName());
Utils.runExec(cmdsList);
// tidy up
testFile.delete();
dstFile.delete();
}
}

View file

@ -1,69 +0,0 @@
/*
* Copyright (c) 2010, 2014, 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.
*
* 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.
*/
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Map;
import java.util.jar.JarFile;
import java.util.jar.Pack200;
/*
* @test
* @bug 7007157
* @summary make sure the strip command works on an attribute
* @compile -XDignore.symbol.file Utils.java T7007157.java
* @run main T7007157
* @author ksrini
*/
public class T7007157 {
public static void main(String... args) throws IOException {
File sdkHome = Utils.JavaSDK;
File testJar = new File("test.jar");
Utils.jar("cvf", testJar.getName(), Utils.TEST_CLS_DIR.getAbsolutePath());
JarFile jarFile = new JarFile(testJar);
File packFile = new File("foo.pack");
Pack200.Packer packer = Pack200.newPacker();
Map<String, String> p = packer.properties();
// Take the time optimization vs. space
p.put(packer.EFFORT, "1"); // CAUTION: do not use 0.
// Make the memory consumption as effective as possible
p.put(packer.SEGMENT_LIMIT, "10000");
// ignore all JAR deflation requests to save time
p.put(packer.DEFLATE_HINT, packer.FALSE);
// save the file ordering of the original JAR
p.put(packer.KEEP_FILE_ORDER, packer.TRUE);
// strip the StackMapTables
p.put(packer.CODE_ATTRIBUTE_PFX + "StackMapTable", packer.STRIP);
FileOutputStream fos = null;
try {
// Write out to a jtreg scratch area
fos = new FileOutputStream(packFile);
// Call the packer
packer.pack(jarFile, fos);
} finally {
Utils.close(fos);
Utils.close(jarFile);
}
Utils.cleanup();
}
}

View file

@ -1,341 +0,0 @@
/*
* Copyright (c) 2010, 2018, 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.
*
* 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.
*/
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.jar.JarFile;
import java.util.jar.JarInputStream;
import java.util.jar.JarOutputStream;
import java.util.jar.Pack200;
/*
* @test
* @bug 6985763
* @summary verify that proper exceptions are thrown
* @compile -XDignore.symbol.file Utils.java TestExceptions.java
* @run main TestExceptions
* @author ksrini
*/
public class TestExceptions {
static final File testJar = new File("test.jar");
static final File testPackFile = new File("test.pack");
static void init() {
Utils.jar("cvf", testJar.getAbsolutePath(), ".");
JarFile jf = null;
try {
jf = new JarFile(testJar);
Utils.pack(jf, testPackFile);
} catch (IOException ioe) {
throw new Error("Initialization error", ioe);
} finally {
Utils.close(jf);
}
}
// a test that closes the input jarFile.
static void pack200Test1() {
PackTestInput ti = null;
// setup the scenario
try {
ti = new PackTestInput(new JarFile(testJar), new ByteArrayOutputStream());
} catch (Exception e) {
throw new Error("Initialization error", e);
} finally {
Utils.close(ti.getJarFile());
}
// test the scenario
try {
System.out.println(ti);
Pack200.Packer p = Pack200.newPacker();
p.pack(ti.getJarFile(), ti.getOutputStream());
} catch (Exception e) {
ti.checkException(e);
} finally {
if (ti != null) {
ti.close();
}
}
}
// test the Pack200.pack(JarFile, OutputStream);
static void pack200Test2() {
List<PackTestInput> tlist = new ArrayList<PackTestInput>();
try {
// setup the test scenarios
try {
tlist.add(new PackTestInput((JarFile)null, null));
tlist.add(new PackTestInput(new JarFile(testJar), null));
tlist.add(new PackTestInput((JarFile)null, new ByteArrayOutputStream()));
} catch (Exception e) {
throw new Error("Initialization error", e);
}
// test the scenarios
for (PackTestInput ti : tlist) {
System.out.println(ti);
try {
Pack200.Packer p = Pack200.newPacker();
p.pack(ti.getJarFile(), ti.getOutputStream());
} catch (Exception e) {
ti.checkException(e);
}
}
} finally { // clean up
for (TestInput ti : tlist) {
if (ti != null) {
ti.close();
}
}
}
}
// test the Pack200.pack(JarInputStream, OutputStream);
static void pack200Test3() {
List<PackTestJarInputStream> tlist = new ArrayList<PackTestJarInputStream>();
try {
// setup the test scenarios
try {
tlist.add(new PackTestJarInputStream((JarInputStream)null, null));
tlist.add(new PackTestJarInputStream((JarInputStream)null,
new ByteArrayOutputStream()));
tlist.add(new PackTestJarInputStream(
new JarInputStream(new FileInputStream(testJar)), null));
} catch (Exception e) {
throw new Error("Initialization error", e);
}
for (PackTestJarInputStream ti : tlist) {
System.out.println(ti);
try {
Pack200.Packer p = Pack200.newPacker();
p.pack(ti.getJarInputStream(), ti.getOutputStream());
} catch (Exception e) {
ti.checkException(e);
}
}
} finally { // clean up
for (PackTestJarInputStream ti : tlist) {
if (ti != null) {
ti.close();
}
}
}
}
// test the Pack200.unpack(InputStream, OutputStream);
static void unpack200Test1() {
List<UnpackTestInput> tlist = new ArrayList<UnpackTestInput>();
try {
// setup the test scenarios
try {
tlist.add(new UnpackTestInput((InputStream)null, null));
tlist.add(new UnpackTestInput(new FileInputStream(testPackFile),
null));
tlist.add(new UnpackTestInput((InputStream) null,
new JarOutputStream(new ByteArrayOutputStream())));
} catch (Exception e) {
throw new Error("Initialization error", e);
}
// test the scenarios
for (UnpackTestInput ti : tlist) {
System.out.println(ti);
try {
Pack200.Unpacker unpacker = Pack200.newUnpacker();
unpacker.unpack(ti.getInputStream(), ti.getJarOutputStream());
} catch (Exception e) {
ti.checkException(e);
}
}
} finally { // clean up
for (TestInput ti : tlist) {
if (ti != null) {
ti.close();
}
}
}
}
// test the Pack200.unpack(File, OutputStream);
static void unpack200Test2() {
List<UnpackTestFileInput> tlist = new ArrayList<UnpackTestFileInput>();
try {
// setup the test scenarios
try {
tlist.add(new UnpackTestFileInput((File)null, null));
tlist.add(new UnpackTestFileInput(testPackFile, null));
tlist.add(new UnpackTestFileInput((File)null,
new JarOutputStream(new ByteArrayOutputStream())));
} catch (Exception e) {
throw new Error("Initialization error", e);
}
// test the scenarios
for (UnpackTestFileInput ti : tlist) {
System.out.println(ti);
try {
Pack200.Unpacker unpacker = Pack200.newUnpacker();
unpacker.unpack(ti.getInputFile(), ti.getJarOutputStream());
} catch (Exception e) {
ti.checkException(e);
}
}
} finally { // clean up
for (TestInput ti : tlist) {
if (ti != null) {
ti.close();
}
}
}
}
public static void main(String... args) throws IOException {
init();
pack200Test1();
pack200Test2();
pack200Test3();
unpack200Test1();
Utils.cleanup();
}
// containers for test inputs and management
static abstract class TestInput {
private final Object in;
private final Object out;
final boolean shouldNPE;
final String testname;
public TestInput(String name, Object in, Object out) {
this.testname = name;
this.in = in;
this.out = out;
shouldNPE = (in == null || out == null);
}
@Override
public String toString() {
StringBuilder outStr = new StringBuilder(testname);
outStr.append(", input:").append(in);
outStr.append(", output:").append(this.out);
outStr.append(", should NPE:").append(shouldNPE);
return outStr.toString();
}
void close() {
if (in != null && (in instanceof Closeable)) {
Utils.close((Closeable) in);
}
if (out != null && (out instanceof Closeable)) {
Utils.close((Closeable) out);
}
}
void checkException(Throwable t) {
if (shouldNPE) {
if (t instanceof NullPointerException) {
System.out.println("Got expected exception");
return;
} else {
throw new RuntimeException("Expected NPE, but got ", t);
}
}
if (t instanceof IOException) {
System.out.println("Got expected exception");
return;
} else {
throw new RuntimeException("Expected IOException but got ", t);
}
}
}
static class PackTestInput extends TestInput {
public PackTestInput(JarFile jf, OutputStream out) {
super("PackTestInput", jf, out);
}
JarFile getJarFile() {
return (JarFile) super.in;
}
OutputStream getOutputStream() {
return (OutputStream) super.out;
}
};
static class PackTestJarInputStream extends TestInput {
public PackTestJarInputStream(JarInputStream in, OutputStream out) {
super("PackTestJarInputStream", in, out);
}
JarInputStream getJarInputStream() {
return (JarInputStream) super.in;
}
OutputStream getOutputStream() {
return (OutputStream) super.out;
}
};
static class UnpackTestInput extends TestInput {
public UnpackTestInput(InputStream in, JarOutputStream out) {
super("UnpackTestInput", in, out);
}
InputStream getInputStream() {
return (InputStream) super.in;
}
JarOutputStream getJarOutputStream() {
return (JarOutputStream) super.out;
}
};
static class UnpackTestFileInput extends TestInput {
public UnpackTestFileInput(File in, JarOutputStream out) {
super("UnpackTestInput", in, out);
}
File getInputFile() {
return (File) super.in;
}
JarOutputStream getJarOutputStream() {
return (JarOutputStream) super.out;
}
};
}

View file

@ -1,61 +0,0 @@
/*
* Copyright (c) 2013, 2016, 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.
*
* 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.
*/
/*
* @test
* @run main/timeout=600 TestNormal
* @bug 8020802 8156807
* @summary Need an ability to create jar files that are invariant to the pack200 packing/unpacking
* @author Alexander Zuev
*/
import java.io.*;
public class TestNormal {
private static String FS = File.separator;
public static void main(String args[]) throws Exception {
String testdir = Utils.TEST_CLS_DIR.getAbsolutePath();
try {
String jarCmd = Utils.getJarCmd();
String packCmd = Utils.getPack200Cmd();
// create the original jar
Utils.runExec(jarCmd, "cf", "original.jar", "-C", testdir, ".");
// create the reference jar
Utils.runExec(packCmd, "-r", "repacked.jar", "original.jar");
// create the normalized jar using jar(1)
Utils.runExec(jarCmd, "cnf", "normalized.jar", "-C", testdir, ".");
// compare archive contents bit wise, these should be identical!
Utils.doCompareBitWise(new File("repacked.jar"),
new File("normalized.jar"));
} finally {
Utils.cleanup();
}
}
}

View file

@ -1,157 +0,0 @@
/*
* Copyright (c) 2010, 2014, 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.
*
* 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.
*/
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.TimeZone;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarOutputStream;
/*
* @test
* @bug 6966740
* @summary verify identical timestamps, unpacked in any timezone
* @compile -XDignore.symbol.file Utils.java TimeStamp.java
* @run main/othervm TimeStamp
* @author ksrini
*/
/**
* First we pack the file in some time zone say India, then we unpack the file
* in the current time zone, and ensure the timestamp recorded in the unpacked
* jar are the same.
*/
public class TimeStamp {
static final TimeZone tz = TimeZone.getDefault();
public static void main(String... args) throws IOException {
// make a local copy of our test file
File srcFile = Utils.getGoldenJar();
File goldenFile = new File("golden.jar");
Utils.copyFile(srcFile, goldenFile);
JarFile goldenJarFile = new JarFile(goldenFile);
File packFile = new File("golden.pack");
// set the test timezone and pack the file
TimeZone.setDefault(TimeZone.getTimeZone("IST"));
Utils.pack(goldenJarFile, packFile);
TimeZone.setDefault(tz); // reset the timezone
// unpack in the test timezone
File istFile = new File("golden.jar.java.IST");
unpackJava(packFile, istFile);
verifyJar(goldenFile, istFile);
istFile.delete();
// unpack in some other timezone
File pstFile = new File("golden.jar.java.PST");
unpackJava(packFile, pstFile);
verifyJar(goldenFile, pstFile);
pstFile.delete();
// repeat the test for unpack200 tool.
istFile = new File("golden.jar.native.IST");
unpackNative(packFile, istFile);
verifyJar(goldenFile, istFile);
istFile.delete();
pstFile = new File("golden.jar.native.PST");
unpackNative(packFile, pstFile);
verifyJar(goldenFile, pstFile);
pstFile.delete();
Utils.cleanup();
}
static void unpackNative(File packFile, File outFile) {
String name = outFile.getName();
String tzname = name.substring(name.lastIndexOf(".") + 1);
HashMap<String, String> env = new HashMap<>();
switch(tzname) {
case "PST":
env.put("TZ", "US/Pacific");
break;
case "IST":
env.put("TZ", "Asia/Calcutta");
break;
default:
throw new RuntimeException("not implemented: " + tzname);
}
List<String> cmdsList = new ArrayList<>();
cmdsList.add(Utils.getUnpack200Cmd());
cmdsList.add(packFile.getName());
cmdsList.add(outFile.getName());
Utils.runExec(cmdsList, env);
}
static void unpackJava(File packFile, File outFile) throws IOException {
String name = outFile.getName();
String tzname = name.substring(name.lastIndexOf(".") + 1);
JarOutputStream jos = null;
try {
TimeZone.setDefault(TimeZone.getTimeZone(tzname));
jos = new JarOutputStream(new FileOutputStream(outFile));
System.out.println("Using timezone: " + TimeZone.getDefault());
Utils.unpackj(packFile, jos);
} finally {
Utils.close(jos);
TimeZone.setDefault(tz); // always reset
}
}
static void verifyJar(File f1, File f2) throws IOException {
int errors = 0;
JarFile jf1 = null;
JarFile jf2 = null;
try {
jf1 = new JarFile(f1);
jf2 = new JarFile(f2);
System.out.println("Verifying: " + f1 + " and " + f2);
for (JarEntry je1 : Collections.list(jf1.entries())) {
JarEntry je2 = jf2.getJarEntry(je1.getName());
if (je1.getTime() != je2.getTime()) {
System.out.println("Error:");
System.out.println(" expected:" + jf1.getName() + ":"
+ je1.getName() + ":" + je1.getTime());
System.out.println(" obtained:" + jf2.getName() + ":"
+ je2.getName() + ":" + je2.getTime());
errors++;
}
}
} finally {
Utils.close(jf1);
Utils.close(jf2);
}
if (errors > 0) {
throw new RuntimeException("FAIL:" + errors + " error(s) encounted");
}
}
}

View file

@ -1,87 +0,0 @@
/*
* Copyright (c) 2010, 2013, 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.
*
* 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.
*/
/*
* @test
* @bug 6531345
* @summary check for unpacker memory leaks
* @compile -XDignore.symbol.file Utils.java UnpackerMemoryTest.java
* @run main/othervm/timeout=1200 -Xmx32m UnpackerMemoryTest
* @author ksrini
*/
import java.io.File;
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.io.IOException;
import java.util.jar.JarFile;
import java.util.jar.JarOutputStream;
public class UnpackerMemoryTest {
private static void createPackFile(File packFile) throws IOException {
File tFile = new File("test.dat");
FileOutputStream fos = null;
PrintStream ps = null;
String jarFileName = Utils.baseName(packFile, Utils.PACK_FILE_EXT)
+ Utils.JAR_FILE_EXT;
JarFile jarFile = null;
try {
fos = new FileOutputStream(tFile);
ps = new PrintStream(fos);
ps.println("A quick brown fox");
Utils.jar("cvf", jarFileName, tFile.getName());
jarFile = new JarFile(jarFileName);
Utils.pack(jarFile, packFile);
} finally {
Utils.close(ps);
tFile.delete();
Utils.close(jarFile);
}
}
public static void main(String[] args) throws Exception {
String name = "foo";
File packFile = new File(name + Utils.PACK_FILE_EXT);
createPackFile(packFile);
if (!packFile.exists()) {
throw new RuntimeException(packFile + " not found");
}
File jarOut = new File(name + ".out");
for (int i = 0; i < 2000; i++) {
JarOutputStream jarOS = null;
FileOutputStream fos = null;
try {
fos = new FileOutputStream(jarOut);
jarOS = new JarOutputStream(fos);
System.out.println("Unpacking[" + i + "]" + packFile);
Utils.unpackn(packFile, jarOS);
} finally {
Utils.close(jarOS);
Utils.close(fos);
}
}
Utils.cleanup();
}
}

View file

@ -1,670 +0,0 @@
/*
* Copyright (c) 2007, 2016, 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.
*
* 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.
*/
import java.nio.file.Path;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.File;
import java.io.FileFilter;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.URI;
import java.nio.charset.Charset;
import java.nio.file.attribute.BasicFileAttributes;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.FileVisitResult;
import java.nio.file.FileVisitor;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import java.util.jar.JarFile;
import java.util.jar.JarOutputStream;
import java.util.jar.Pack200;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import static java.nio.file.StandardCopyOption.*;
import static java.nio.file.StandardOpenOption.*;
/**
*
* @author ksrini
*/
/*
* This class contains the commonly used utilities.
*/
class Utils {
static final String JavaHome = System.getProperty("test.java",
System.getProperty("java.home"));
static final boolean IsWindows =
System.getProperty("os.name").startsWith("Windows");
static final boolean Is64Bit =
System.getProperty("sun.arch.data.model", "32").equals("64");
static final File JavaSDK = new File(JavaHome);
static final String PACK_FILE_EXT = ".pack";
static final String JAVA_FILE_EXT = ".java";
static final String CLASS_FILE_EXT = ".class";
static final String JAR_FILE_EXT = ".jar";
static final File TEST_SRC_DIR = new File(System.getProperty("test.src"));
static final File TEST_CLS_DIR = new File(System.getProperty("test.classes"));
static final String VERIFIER_DIR_NAME = "pack200-verifier";
static final File VerifierJar = new File(VERIFIER_DIR_NAME + JAR_FILE_EXT);
static final File XCLASSES = new File("xclasses");
private Utils() {} // all static
private static void init() throws IOException {
if (VerifierJar.exists()) {
return;
}
File srcDir = new File(getVerifierDir(), "src");
List<File> javaFileList = findFiles(srcDir, createFilter(JAVA_FILE_EXT));
File tmpFile = File.createTempFile("javac", ".tmp", new File("."));
XCLASSES.mkdirs();
FileOutputStream fos = null;
PrintStream ps = null;
try {
fos = new FileOutputStream(tmpFile);
ps = new PrintStream(fos);
for (File f : javaFileList) {
ps.println(f.getAbsolutePath());
}
} finally {
close(ps);
close(fos);
}
compiler("-d",
XCLASSES.getName(),
"--add-modules=jdk.jdeps",
"--add-exports=jdk.jdeps/com.sun.tools.classfile=ALL-UNNAMED",
"@" + tmpFile.getAbsolutePath());
jar("cvfe",
VerifierJar.getName(),
"sun.tools.pack.verify.Main",
"-C",
XCLASSES.getName(),
".");
}
private static File getVerifierDir() {
File srcDir = new File(TEST_SRC_DIR, VERIFIER_DIR_NAME);
if (!srcDir.exists()) {
// if not available try one level above
srcDir = new File(TEST_SRC_DIR.getParentFile(), VERIFIER_DIR_NAME);
}
return srcDir;
}
static File getGoldenJar() {
return new File(new File(getVerifierDir(), "data"), "golden.jar");
}
static void dirlist(File dir) {
File[] files = dir.listFiles();
System.out.println("--listing " + dir.getAbsolutePath() + "---");
for (File f : files) {
StringBuffer sb = new StringBuffer();
sb.append(f.isDirectory() ? "d " : "- ");
sb.append(f.getName());
System.out.println(sb);
}
}
static void doCompareVerify(File reference, File specimen) throws IOException {
init();
List<String> cmds = new ArrayList<String>();
cmds.add(getJavaCmd());
cmds.add("--add-exports=jdk.jdeps/com.sun.tools.classfile=ALL-UNNAMED");
cmds.add("-cp");
cmds.add(VerifierJar.getName());
cmds.add("sun.tools.pack.verify.Main");
cmds.add(reference.getAbsolutePath());
cmds.add(specimen.getAbsolutePath());
cmds.add("-O");
runExec(cmds);
}
static void doCompareBitWise(File reference, File specimen)
throws IOException {
init();
List<String> cmds = new ArrayList<String>();
cmds.add(getJavaCmd());
cmds.add("-cp");
cmds.add(VerifierJar.getName());
cmds.add("sun.tools.pack.verify.Main");
cmds.add(reference.getName());
cmds.add(specimen.getName());
cmds.add("-O");
cmds.add("-b");
runExec(cmds);
}
static FileFilter createFilter(final String extension) {
return new FileFilter() {
@Override
public boolean accept(File pathname) {
String name = pathname.getName();
if (name.endsWith(extension)) {
return true;
}
return false;
}
};
}
/*
* clean up all the usual suspects
*/
static void cleanup() throws IOException {
recursiveDelete(XCLASSES);
List<File> toDelete = new ArrayList<>();
toDelete.addAll(Utils.findFiles(new File("."),
Utils.createFilter(".out")));
toDelete.addAll(Utils.findFiles(new File("."),
Utils.createFilter(".bak")));
toDelete.addAll(Utils.findFiles(new File("."),
Utils.createFilter(".jar")));
toDelete.addAll(Utils.findFiles(new File("."),
Utils.createFilter(".pack")));
toDelete.addAll(Utils.findFiles(new File("."),
Utils.createFilter(".bnd")));
toDelete.addAll(Utils.findFiles(new File("."),
Utils.createFilter(".txt")));
toDelete.addAll(Utils.findFiles(new File("."),
Utils.createFilter(".idx")));
toDelete.addAll(Utils.findFiles(new File("."),
Utils.createFilter(".gidx")));
toDelete.addAll(Utils.findFiles(new File("."),
Utils.createFilter(".tmp")));
toDelete.addAll(Utils.findFiles(new File("."),
Utils.createFilter(".class")));
for (File f : toDelete) {
f.delete();
}
}
static final FileFilter DIR_FILTER = new FileFilter() {
public boolean accept(File pathname) {
if (pathname.isDirectory()) {
return true;
}
return false;
}
};
static final FileFilter FILE_FILTER = new FileFilter() {
public boolean accept(File pathname) {
if (pathname.isFile()) {
return true;
}
return false;
}
};
static void copyFile(File src, File dst) throws IOException {
Path parent = dst.toPath().getParent();
if (parent != null) {
Files.createDirectories(parent);
}
Files.copy(src.toPath(), dst.toPath(), COPY_ATTRIBUTES, REPLACE_EXISTING);
if (dst.isDirectory() && !dst.canWrite()) {
dst.setWritable(true);
}
}
static String baseName(File file, String extension) {
return baseName(file.getAbsolutePath(), extension);
}
static String baseName(String name, String extension) {
int cut = name.length() - extension.length();
return name.lastIndexOf(extension) == cut
? name.substring(0, cut)
: name;
}
static void createFile(File outFile, List<String> content) throws IOException {
Files.write(outFile.getAbsoluteFile().toPath(), content,
Charset.defaultCharset(), CREATE_NEW, TRUNCATE_EXISTING);
}
/*
* Suppose a path is provided which consists of a full path
* this method returns the sub path for a full path ex: /foo/bar/baz/foobar.z
* and the base path is /foo/bar it will will return baz/foobar.z.
*/
private static String getEntryPath(String basePath, String fullPath) {
if (!fullPath.startsWith(basePath)) {
return null;
}
return fullPath.substring(basePath.length());
}
static String getEntryPath(File basePathFile, File fullPathFile) {
return getEntryPath(basePathFile.toString(), fullPathFile.toString());
}
public static void recursiveCopy(File src, File dest) throws IOException {
if (!src.exists() || !src.canRead()) {
throw new IOException("file not found or readable: " + src);
}
if (dest.exists() && !dest.isDirectory() && !dest.canWrite()) {
throw new IOException("file not found or writeable: " + dest);
}
if (!dest.exists()) {
dest.mkdirs();
}
List<File> a = directoryList(src);
for (File f : a) {
copyFile(f, new File(dest, getEntryPath(src, f)));
}
}
static List<File> directoryList(File dirname) {
List<File> dirList = new ArrayList<File>();
return directoryList(dirname, dirList, null);
}
private static List<File> directoryList(File dirname, List<File> dirList,
File[] dirs) {
dirList.addAll(Arrays.asList(dirname.listFiles(FILE_FILTER)));
dirs = dirname.listFiles(DIR_FILTER);
for (File f : dirs) {
if (f.isDirectory() && !f.equals(dirname)) {
dirList.add(f);
directoryList(f, dirList, dirs);
}
}
return dirList;
}
static void recursiveDelete(File dir) throws IOException {
if (dir.isFile()) {
dir.delete();
} else if (dir.isDirectory()) {
File[] entries = dir.listFiles();
for (int i = 0; i < entries.length; i++) {
if (entries[i].isDirectory()) {
recursiveDelete(entries[i]);
}
entries[i].delete();
}
dir.delete();
}
}
static List<File> findFiles(File startDir, FileFilter filter)
throws IOException {
List<File> list = new ArrayList<File>();
findFiles0(startDir, list, filter);
return list;
}
/*
* finds files in the start directory using the the filter, appends
* the files to the dirList.
*/
private static void findFiles0(File startDir, List<File> list,
FileFilter filter) throws IOException {
File[] foundFiles = startDir.listFiles(filter);
if (foundFiles == null) {
return;
}
list.addAll(Arrays.asList(foundFiles));
File[] dirs = startDir.listFiles(DIR_FILTER);
for (File dir : dirs) {
findFiles0(dir, list, filter);
}
}
static void close(Closeable c) {
if (c == null) {
return;
}
try {
c.close();
} catch (IOException ignore) {
}
}
static void compiler(String... javacCmds) {
List<String> cmdList = new ArrayList<>();
cmdList.add(getJavacCmd());
for (String x : javacCmds) {
cmdList.add(x);
}
runExec(cmdList);
}
static void jar(String... jargs) {
List<String> cmdList = new ArrayList<>();
cmdList.add(getJarCmd());
for (String x : jargs) {
cmdList.add(x);
}
runExec(cmdList);
}
static void testWithRepack(File inFile, String... repackOpts) throws IOException {
File cwd = new File(".");
// pack using --repack in native mode
File nativejarFile = new File(cwd, "out-n" + Utils.JAR_FILE_EXT);
repack(inFile, nativejarFile, false, repackOpts);
doCompareVerify(inFile, nativejarFile);
// ensure bit compatibility between the unpacker variants
File javajarFile = new File(cwd, "out-j" + Utils.JAR_FILE_EXT);
repack(inFile, javajarFile, true, repackOpts);
doCompareBitWise(javajarFile, nativejarFile);
}
static List<String> repack(File inFile, File outFile,
boolean disableNative, String... extraOpts) {
List<String> cmdList = new ArrayList<>();
cmdList.clear();
cmdList.add(Utils.getJavaCmd());
cmdList.add("-ea");
cmdList.add("-esa");
if (disableNative) {
cmdList.add("-Dcom.sun.java.util.jar.pack.disable.native=true");
}
cmdList.add("com.sun.java.util.jar.pack.Driver");
cmdList.add("--repack");
if (extraOpts != null) {
for (String opt: extraOpts) {
cmdList.add(opt);
}
}
cmdList.add(outFile.getName());
cmdList.add(inFile.getName());
return Utils.runExec(cmdList);
}
// given a jar file foo.jar will write to foo.pack
static void pack(JarFile jarFile, File packFile) throws IOException {
Pack200.Packer packer = Pack200.newPacker();
Map<String, String> p = packer.properties();
// Take the time optimization vs. space
p.put(packer.EFFORT, "1"); // CAUTION: do not use 0.
// Make the memory consumption as effective as possible
p.put(packer.SEGMENT_LIMIT, "10000");
// ignore all JAR deflation requests to save time
p.put(packer.DEFLATE_HINT, packer.FALSE);
// save the file ordering of the original JAR
p.put(packer.KEEP_FILE_ORDER, packer.TRUE);
FileOutputStream fos = null;
try {
// Write out to a jtreg scratch area
fos = new FileOutputStream(packFile);
// Call the packer
packer.pack(jarFile, fos);
} finally {
close(fos);
}
}
// uses java unpacker, slow but useful to discover issues with the packer
static void unpackj(File inFile, JarOutputStream jarStream)
throws IOException {
unpack0(inFile, jarStream, true);
}
// uses native unpacker using the java APIs
static void unpackn(File inFile, JarOutputStream jarStream)
throws IOException {
unpack0(inFile, jarStream, false);
}
// given a packed file, create the jar file in the current directory.
private static void unpack0(File inFile, JarOutputStream jarStream,
boolean useJavaUnpack) throws IOException {
// Unpack the files
Pack200.Unpacker unpacker = Pack200.newUnpacker();
Map<String, String> props = unpacker.properties();
if (useJavaUnpack) {
props.put("com.sun.java.util.jar.pack.disable.native", "true");
}
// Call the unpacker
unpacker.unpack(inFile, jarStream);
}
static byte[] getBuffer(ZipFile zf, ZipEntry ze) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte buf[] = new byte[8192];
InputStream is = null;
try {
is = zf.getInputStream(ze);
int n = is.read(buf);
while (n > 0) {
baos.write(buf, 0, n);
n = is.read(buf);
}
return baos.toByteArray();
} finally {
close(is);
}
}
static ArrayList<String> getZipFileEntryNames(ZipFile z) {
ArrayList<String> out = new ArrayList<String>();
for (ZipEntry ze : Collections.list(z.entries())) {
out.add(ze.getName());
}
return out;
}
static List<String> runExec(String... cmds) {
return runExec(Arrays.asList(cmds));
}
static List<String> runExec(List<String> cmdsList) {
return runExec(cmdsList, null);
}
static List<String> runExec(List<String> cmdsList, Map<String, String> penv) {
return runExec(cmdsList, penv, false);
}
static List<String> runExec(List<String> cmdsList, Map<String, String> penv, boolean ignoreReturnValue) {
ArrayList<String> alist = new ArrayList<String>();
ProcessBuilder pb =
new ProcessBuilder(cmdsList);
Map<String, String> env = pb.environment();
if (penv != null && !penv.isEmpty()) {
env.putAll(penv);
}
pb.directory(new File("."));
dirlist(new File("."));
for (String x : cmdsList) {
System.out.print(x + " ");
}
System.out.println("");
int retval = 0;
Process p = null;
InputStreamReader ir = null;
BufferedReader rd = null;
InputStream is = null;
try {
pb.redirectErrorStream(true);
p = pb.start();
is = p.getInputStream();
ir = new InputStreamReader(is);
rd = new BufferedReader(ir, 8192);
String in = rd.readLine();
while (in != null) {
alist.add(in);
System.out.println(in);
in = rd.readLine();
}
retval = p.waitFor();
if (!ignoreReturnValue && retval != 0) {
throw new RuntimeException("process failed with non-zero exit");
}
} catch (Exception ex) {
throw new RuntimeException(ex.getMessage());
} finally {
close(rd);
close(ir);
close(is);
if (p != null) {
p.destroy();
}
}
return alist;
}
static String getUnpack200Cmd() {
return getAjavaCmd("unpack200");
}
static String getPack200Cmd() {
return getAjavaCmd("pack200");
}
static String getJavaCmd() {
return getAjavaCmd("java");
}
static String getJavacCmd() {
return getAjavaCmd("javac");
}
static String getJarCmd() {
return getAjavaCmd("jar");
}
static String getAjavaCmd(String cmdStr) {
File binDir = new File(JavaHome, "bin");
File unpack200File = IsWindows
? new File(binDir, cmdStr + ".exe")
: new File(binDir, cmdStr);
String cmd = unpack200File.getAbsolutePath();
if (!unpack200File.canExecute()) {
throw new RuntimeException("please check" +
cmd + " exists and is executable");
}
return cmd;
}
// used to get all classes
static File createRtJar() throws Exception {
File rtJar = new File("rt.jar");
new JrtToZip(".*\\.class", rtJar).run();
return rtJar;
}
// used to select the contents
static File createRtJar(String pattern) throws Exception {
File rtJar = new File("rt.jar");
new JrtToZip(pattern, rtJar).run();
return rtJar;
}
/*
* A helper class to create a pseudo rt.jar.
*/
static class JrtToZip {
final File outFile;
final Pattern pattern;
public static void main(String[] args) throws Exception {
new JrtToZip(args[0], new File(args[1])).run();
}
JrtToZip(String pattern, File outFile) throws Exception {
this.pattern = Pattern.compile(pattern);
this.outFile = outFile;
}
void run() throws Exception {
URI uri = URI.create("jar:" + outFile.toURI());
Map<String, String> env = new HashMap<>();
env.put("create", "true");
try (FileSystem zipfs = FileSystems.newFileSystem(uri, env)) {
toZipfs(zipfs);
}
}
void toZipfs(FileSystem zipfs) throws Exception {
FileSystem jrtfs = FileSystems.getFileSystem(URI.create("jrt:/"));
for (Path root : jrtfs.getRootDirectories()) {
Files.walkFileTree(root, new FileVisitor<Path>() {
@Override
public FileVisitResult preVisitDirectory(Path dir,
BasicFileAttributes attrs) throws IOException {
// ignore unneeded directory
if (dir.startsWith("/packages"))
return FileVisitResult.SKIP_SUBTREE;
// pre-create required directories
Path zpath = zipfs.getPath(dir.toString());
Files.createDirectories(zpath);
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult visitFile(Path file,
BasicFileAttributes attrs) throws IOException {
Matcher matcher = pattern.matcher(file.toString());
if (matcher.matches()) {
// System.out.println("x: " + file);
Path zpath = zipfs.getPath(file.toString());
Files.copy(file, zpath, REPLACE_EXISTING);
}
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult visitFileFailed(Path file,
IOException exc) throws IOException {
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult postVisitDirectory(Path dir,
IOException exc) throws IOException {
return FileVisitResult.CONTINUE;
}
});
}
}
}
}

Binary file not shown.

View file

@ -1,46 +0,0 @@
The files contained in the golden.jar have been harvested from many
different sources, some are hand-crafted invalid class files (odds directory),
or from random JDK builds.
Generally these files serve to ensure the integrity of the packer and
unpacker by,
* maximizing the test coverage.
* exercising all the Bands in the pack200 specification.
* testing the behavior of the packer with invalid classes.
* testing the archive integrity, ordering and description (date, sizes,
CRC etc.)
Build:
To rebuild this JAR follow these steps:
1. unzip the golden.jar to some directory lets call it "example"
2. now we can add any directories with files into example.
3. run the script BUILDME.sh as
% sh BUILDME.sh example
Note: the BUILDME.sh is known to work on all Unix platforms as well as Windows
using Cygwin.
The above will create two JAR files in the current directory,
example.jar and example-cls.jar, now the example.jar can be used as the
golden.jar.
To ensure the JAR has been built correctly use jar -tvf and compare the
results of the old jar and the newly built one, note that the compressed sizes
may differ, however the timestamps etc. should be consistent.
Test:
Basic:
% pack200 --repack test.jar golden.jar
Advanced: inspection of band contents
Create a pack.conf as follows:
% cat pack.conf
com.sun.java.util.jar.pack.dump.bands=true
% pack200 --no-gzip --config-file=pack.conf \
--verbose golden.jar.pack golden.jar
This command will dump the Bands in a unique directory BD_XXXXXX,
one can then inspect the directory to ensure all of the bands are being
generated. Familiarity of the Pack200 specification is strongly
suggested.

View file

@ -1,64 +0,0 @@
<project name="PackageVerify" default="jar-file" basedir="..">
<!-- Requires ant 1.6.1+ and JDK 1.7+-->
<!-- set global properties for this build -->
<property name="src" value="${basedir}/src"/>
<property name="build" value="${basedir}/build"/>
<property name="dist" value="${basedir}/dist"/>
<property name="make" value="${basedir}/make"/>
<property name="classes" value="${build}/classes"/>
<property name="api" value="${build}/api"/>
<target name="init">
<!-- Create the time stamp -->
<tstamp/>
<!-- Create the build directory structure used by compile -->
<mkdir dir="${build}"/>
<mkdir dir="${dist}"/>
<mkdir dir="${classes}"/>
<mkdir dir="${api}"/>
</target>
<target name="compile" depends="init">
<!-- Compile the java code from ${src} into ${build} -->
<javac
source="1.9"
srcdir="${src}"
destdir="${build}/classes"
verbose="no"
debug="on">
<compilerarg line="--add-exports jdk.jdeps/com.sun.tools.classfile=ALL-UNNAMED"/>
</javac>
</target>
<target name="doc" depends="init, compile">
<javadoc
source="1.9"
sourcepath="${src}"
destdir="${api}"
/>
</target>
<target name="jar-file" depends="compile">
<!-- Put everything in jar file -->
<jar destfile="${dist}/pack200-verifier.jar">
<manifest>
<attribute name="Main-Class" value="sun.tools.pack.verify.Main"/>
</manifest>
<fileset dir="${classes}"/>
</jar>
</target>
<target name="all" depends="jar-file">
<zip destfile="dist/pack200-verifier-doc.zip">
<fileset dir="${api}"/>
</zip>
</target>
<target name="clean">
<!-- Delete the ${build} and ${dist} directory trees -->
<delete dir="${build}"/>
<delete dir="${dist}"/>
</target>
</project>

View file

@ -1,160 +0,0 @@
/*
* Copyright (c) 2010, 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.
*
* 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 sun.tools.pack.verify;
import java.io.*;
import java.util.*;
import java.util.jar.*;
import xmlkit.*;
public class ClassCompare {
/*
* @author ksrini
*/
private static XMLKit.Element getXMLelement(InputStream is,
boolean ignoreUnkAttrs,
List<String> ignoreElements) throws IOException {
ClassReader cr = new ClassReader();
cr.keepOrder = false;
XMLKit.Element e = cr.readFrom(is);
if (ignoreElements != null) {
XMLKit.Filter filter = XMLKit.elementFilter(ignoreElements);
e.removeAllInTree(filter);
}
if (ignoreUnkAttrs == true) {
// This removes any unknown attributes
e.removeAllInTree(XMLKit.elementFilter("Attribute"));
}
return e;
}
private static String getXMLPrettyString(XMLKit.Element e) throws IOException {
StringWriter out = new StringWriter();
e.writePrettyTo(out);
return out.toString();
}
private static boolean compareClass0(JarFile jf1, JarFile jf2,
JarEntry je, boolean ignoreUnkAttrs,
List<String> ignoreElements)
throws IOException {
InputStream is1 = jf1.getInputStream(je);
InputStream is2 = jf2.getInputStream(je);
// First we try to compare the bits if they are the same
boolean bCompare = JarFileCompare.compareStreams(is1, is2);
// If they are the same there is nothing more to do.
if (bCompare) {
Globals.println("+++" + je.getName() + "+++\t"
+ "b/b:PASS");
return bCompare;
}
is1.close();
is2.close();
is1 = jf1.getInputStream(je);
is2 = jf2.getInputStream(je);
XMLKit.Element e1 = getXMLelement(is1, ignoreUnkAttrs, ignoreElements);
XMLKit.Element e2 = getXMLelement(is2, ignoreUnkAttrs, ignoreElements);
Globals.print("+++" + je.getName() + "+++\t"
+ e1.size() + "/" + e1.size() + ":");
boolean result = true;
if (e1.equals(e2)) {
Globals.println("PASS");
} else {
Globals.println("FAIL");
Globals.log("Strings differs");
Globals.log(getXMLPrettyString(e1));
Globals.log("----------");
Globals.log(getXMLPrettyString(e2));
result = false;
}
return result;
}
/*
* Given two Class Paths could be jars the first being a reference
* will execute a series of comparisons on the classname specified
* The className could be null in which case it will iterate through
* all the classes, otherwise it will compare one class and exit.
*/
public static boolean compareClass(String jar1, String jar2,
String className, boolean ignoreUnkAttrs,
List<String> ignoreElements)
throws IOException {
Globals.println("Unknown attributes ignored:" + ignoreUnkAttrs);
if (ignoreElements != null) {
Globals.println(ignoreElements.toString());
}
JarFile jf1 = new JarFile(jar1);
JarFile jf2 = new JarFile(jar2);
boolean result = true;
if (className == null) {
for (JarEntry je1 : Collections.list((Enumeration<JarEntry>) jf1.entries())) {
if (je1.getName().endsWith(".class")) {
JarEntry je2 = jf2.getJarEntry(je1.getName());
boolean pf = compareClass0(jf1, jf2, je1, ignoreUnkAttrs, ignoreElements);
if (result == true) {
result = pf;
}
}
}
} else {
JarEntry je1 = jf1.getJarEntry(className);
result = compareClass0(jf1, jf2, je1, ignoreUnkAttrs, ignoreElements);
}
if (result == false) {
throw new RuntimeException("Class structural comparison failure");
}
return result;
}
public static boolean compareClass(String jar1, String jar2,
String className) throws IOException {
Stack<String> s = new Stack();
if (Globals.ignoreDebugAttributes()) {
s = new Stack();
s.push("LocalVariable");
s.push("LocalVariableType");
s.push("LineNumber");
s.push("SourceFile");
}
return compareClass(jar1, jar2, className, Globals.ignoreUnknownAttributes(), s);
}
}

View file

@ -1,309 +0,0 @@
/*
* Copyright (c) 2010, 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.
*
* 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.
*/
/*
* A collection of useful global utilities commonly used.
*/
package sun.tools.pack.verify;
import java.io.*;
import java.util.*;
/*
* @author ksrini
*/
class Globals {
private static int errors = 0;
private static PrintWriter _pw = null;
private static String _logFileName = null;
private static final String DEFAULT_LOG_FILE = "verifier.log";
private static boolean _verbose = true;
private static boolean _ignoreJarDirectories = false;
private static boolean _checkJarClassOrdering = true;
private static boolean _bitWiseClassCompare = false;
// Ignore Deprecated, SourceFile and Synthetic
private static boolean _ignoreCompileAttributes = false;
// Ignore Debug Attributes LocalVariableTable, LocalVariableType,LineNumberTable
private static boolean _ignoreDebugAttributes = false;
private static boolean _ignoreUnknownAttributes = false;
private static boolean _validateClass = true;
private static Globals _instance = null;
static Globals getInstance() {
if (_instance == null) {
_instance = new Globals();
_verbose = (System.getProperty("sun.tools.pack.verify.verbose") == null)
? false : true;
_ignoreJarDirectories = (System.getProperty("ignoreJarDirectories") == null)
? false : true;
}
return _instance;
}
static boolean ignoreCompileAttributes() {
return _ignoreCompileAttributes;
}
static boolean ignoreDebugAttributes() {
return _ignoreDebugAttributes;
}
static boolean ignoreUnknownAttributes() {
return _ignoreUnknownAttributes;
}
static boolean ignoreJarDirectories() {
return _ignoreJarDirectories;
}
static boolean validateClass() {
return _validateClass;
}
static void setCheckJarClassOrdering(boolean flag) {
_checkJarClassOrdering = flag;
}
static boolean checkJarClassOrdering() {
return _checkJarClassOrdering;
}
static boolean bitWiseClassCompare() {
return _bitWiseClassCompare;
}
static boolean setBitWiseClassCompare(boolean flag) {
return _bitWiseClassCompare = flag;
}
public static boolean setIgnoreCompileAttributes(boolean flag) {
return _ignoreCompileAttributes = flag;
}
static boolean setIgnoreDebugAttributes(boolean flag) {
return _ignoreDebugAttributes = flag;
}
static boolean setIgnoreUnknownAttributes(boolean flag) {
return _ignoreUnknownAttributes = flag;
}
static boolean setValidateClass(boolean flag) {
return _validateClass = flag;
}
static int getErrors() {
return errors;
}
static void trace(String s) {
if (_verbose) {
println(s);
}
}
static void print(String s) {
_pw.print(s);
}
static void println(String s) {
_pw.println(s);
}
static void log(String s) {
errors++;
_pw.println("ERROR:" + s);
}
static void lognoln(String s) {
errors++;
_pw.print(s);
}
private static PrintWriter openFile(String fileName) {
//Lets create the directory if it does not exist.
File f = new File(fileName);
File baseDir = f.getParentFile();
if (baseDir != null && baseDir.exists() == false) {
baseDir.mkdirs();
}
try {
return new PrintWriter(new FileWriter(f), true);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private static void closeFile() {
_pw.flush();
_pw.close();
}
static void printPropsToLog() {
println("Log started " + new Date(System.currentTimeMillis()));
print(System.getProperty("java.vm.version"));
println("\t" + System.getProperty("java.vm.name"));
println("System properties");
println("\tjava.home=" + System.getProperty("java.home"));
println("\tjava.class.version=" + System.getProperty("java.class.version"));
println("\tjava.class.path=" + System.getProperty("java.class.path"));
println("\tos.name=" + System.getProperty("os.name"));
println("\tos.arch=" + System.getProperty("os.arch"));
println("\tos.version=" + System.getProperty("os.version"));
println("\tuser.name=" + System.getProperty("user.name"));
println("\tuser.home=" + System.getProperty("user.home"));
println("\tuser.dir=" + System.getProperty("user.dir"));
println("\tLocale.getDefault=" + Locale.getDefault());
println("System properties end");
}
static void openLog(String s) {
_logFileName = (s != null) ? s : "." + File.separator + DEFAULT_LOG_FILE;
_logFileName = (new File(_logFileName).isDirectory())
? _logFileName + File.separator + DEFAULT_LOG_FILE : _logFileName;
_pw = openFile(_logFileName);
printPropsToLog();
}
static void closeLog() {
closeFile();
}
static String getLogFileName() {
return _logFileName;
}
static void diffCharData(String s1, String s2) {
boolean diff = false;
char[] c1 = s1.toCharArray();
char[] c2 = s2.toCharArray();
if (c1.length != c2.length) {
diff = true;
Globals.log("Length differs: " + (c1.length - c2.length));
}
// Take the smaller of the two arrays to prevent Array...Exception
int minlen = (c1.length < c2.length) ? c1.length : c2.length;
for (int i = 0; i < c1.length; i++) {
if (c1[i] != c2[i]) {
diff = true;
Globals.lognoln("\t idx[" + i + "] 0x" + Integer.toHexString(c1[i]) + "<>" + "0x" + Integer.toHexString(c2[i]));
Globals.log(" -> " + c1[i] + "<>" + c2[i]);
}
}
}
static void diffByteData(String s1, String s2) {
boolean diff = false;
byte[] b1 = s1.getBytes();
byte[] b2 = s2.getBytes();
if (b1.length != b2.length) {
diff = true;
//(+) b1 is greater, (-) b2 is greater
Globals.log("Length differs diff: " + (b1.length - b2.length));
}
// Take the smaller of the two array to prevent Array...Exception
int minlen = (b1.length < b2.length) ? b1.length : b2.length;
for (int i = 0; i < b1.length; i++) {
if (b1[i] != b2[i]) {
diff = true;
Globals.log("\t" + "idx[" + i + "] 0x" + Integer.toHexString(b1[i]) + "<>" + "0x" + Integer.toHexString(b2[i]));
}
}
}
static void dumpToHex(String s) {
try {
dumpToHex(s.getBytes("UTF-8"));
} catch (UnsupportedEncodingException uce) {
throw new RuntimeException(uce);
}
}
static void dumpToHex(byte[] buffer) {
int linecount = 0;
byte[] b = new byte[16];
for (int i = 0; i < buffer.length; i += 16) {
if (buffer.length - i > 16) {
System.arraycopy(buffer, i, b, 0, 16);
print16Bytes(b, linecount);
linecount += 16;
} else {
System.arraycopy(buffer, i, b, 0, buffer.length - i);
for (int n = buffer.length - (i + 1); n < 16; n++) {
b[n] = 0;
}
print16Bytes(b, linecount);
linecount += 16;
}
}
Globals.log("-----------------------------------------------------------------");
}
static void print16Bytes(byte[] buffer, int linecount) {
final int MAX = 4;
Globals.lognoln(paddedHexString(linecount, 4) + " ");
for (int i = 0; i < buffer.length; i += 2) {
int iOut = pack2Bytes2Int(buffer[i], buffer[i + 1]);
Globals.lognoln(paddedHexString(iOut, 4) + " ");
}
Globals.lognoln("| ");
StringBuilder sb = new StringBuilder(new String(buffer));
for (int i = 0; i < buffer.length; i++) {
if (Character.isISOControl(sb.charAt(i))) {
sb.setCharAt(i, '.');
}
}
Globals.log(sb.toString());
}
static int pack2Bytes2Int(byte b1, byte b2) {
int out = 0x0;
out += b1;
out <<= 8;
out &= 0x0000ffff;
out |= 0x000000ff & b2;
return out;
}
static String paddedHexString(int n, int max) {
char[] c = Integer.toHexString(n).toCharArray();
char[] out = new char[max];
for (int i = 0; i < max; i++) {
out[i] = '0';
}
int offset = (max - c.length < 0) ? 0 : max - c.length;
for (int i = 0; i < c.length; i++) {
out[offset + i] = c[i];
}
return new String(out);
}
}

View file

@ -1,199 +0,0 @@
/*
* Copyright (c) 2010, 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.
*
* 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 sun.tools.pack.verify;
import java.io.*;
import java.util.*;
import java.util.jar.*;
class JarFileCompare {
/*
* @author ksrini
*/
private static VerifyTreeSet getVerifyTreeSet(String jarPath) {
VerifyTreeSet vts = new VerifyTreeSet();
try {
JarFile j = new JarFile(jarPath);
for (JarEntry je : Collections.list((Enumeration<JarEntry>) j.entries())) {
if (!je.isDirectory()) { // totally ignore directories
vts.add(je.getName());
}
}
} catch (IOException ioe) {
throw new RuntimeException(ioe);
}
return vts;
}
private static LinkedList getListOfClasses(String jarPath) {
LinkedList l = new LinkedList();
try {
JarFile j = new JarFile(jarPath);
for (JarEntry je : Collections.list((Enumeration<JarEntry>) j.entries())) {
if (!je.isDirectory() && je.getName().endsWith(".class")) {
l.add(je.getName());
}
}
} catch (IOException ioe) {
throw new RuntimeException(ioe);
}
return l;
}
private static void jarDirectoryCompare(String jarPath1, String jarPath2) {
VerifyTreeSet vts1 = getVerifyTreeSet(jarPath1);
VerifyTreeSet vts2 = getVerifyTreeSet(jarPath2);
TreeSet diff1 = vts1.diff(vts2);
if (diff1.size() > 0) {
Globals.log("Left has the following entries that right does not have");
Globals.log(diff1.toString());
}
TreeSet diff2 = vts2.diff(vts1);
if (diff2.size() > 0) {
Globals.log("Right has the following entries that left does not have");
Globals.log(diff2.toString());
}
if (Globals.checkJarClassOrdering()) {
boolean error = false;
Globals.println("Checking Class Ordering");
LinkedList l1 = getListOfClasses(jarPath1);
LinkedList l2 = getListOfClasses(jarPath2);
if (l1.size() != l2.size()) {
error = true;
Globals.log("The number of classes differs");
Globals.log("\t" + l1.size() + "<>" + l2.size());
}
for (int i = 0; i < l1.size(); i++) {
String s1 = (String) l1.get(i);
String s2 = (String) l2.get(i);
if (s1.compareTo(s2) != 0) {
error = true;
Globals.log("Ordering differs at[" + i + "] = " + s1);
Globals.log("\t" + s2);
}
}
}
}
/*
* Returns true if the two Streams are bit identical, and false if they
* are not, no further diagnostics
*/
static boolean compareStreams(InputStream is1, InputStream is2) {
BufferedInputStream bis1 = new BufferedInputStream(is1, 8192);
BufferedInputStream bis2 = new BufferedInputStream(is2, 8192);
try {
int i1, i2;
int count = 0;
while ((i1 = bis1.read()) == (i2 = bis2.read())) {
count++;
if (i1 < 0) {
// System.out.println("bytes read " + count);
return true; // got all the way to EOF
}
}
return false; // reads returned dif
} catch (IOException ioe) {
throw new RuntimeException(ioe);
}
}
private static void checkEntry(JarFile jf1, JarFile jf2, JarEntry je) throws IOException {
InputStream is1 = jf1.getInputStream(je);
InputStream is2 = jf2.getInputStream(je);
if (is1 != null && is2 != null) {
if (!compareStreams(jf1.getInputStream(je), jf2.getInputStream(je))) {
Globals.println("+++" + je.getName() + "+++");
Globals.log("Error: File:" + je.getName()
+ " differs, use a diff util for further diagnostics");
}
} else {
Globals.println("+++" + je.getName() + "+++");
Globals.log("Error: File:" + je.getName() + " not found in " + jf2.getName());
}
}
/*
* Given two jar files we compare and see if the jarfiles have all the
* entries. The property ignoreJarDirectories is set to true by default
* which means that Directory entries in a jar may be ignore.
*/
static void jarCompare(String jarPath1, String jarPath2) {
jarDirectoryCompare(jarPath1, jarPath2);
try {
JarFile jf1 = new JarFile(jarPath1);
JarFile jf2 = new JarFile(jarPath2);
int nclasses = 0;
int nentries = 0;
int entries_checked = 0;
int classes_checked = 0;
for (JarEntry je : Collections.list((Enumeration<JarEntry>) jf1.entries())) {
if (!je.isDirectory() && !je.getName().endsWith(".class")) {
nentries++;
} else if (je.getName().endsWith(".class")) {
nclasses++;
}
}
for (JarEntry je : Collections.list((Enumeration<JarEntry>) jf1.entries())) {
if (je.isDirectory()) {
continue; // Ignore directories
}
if (!je.getName().endsWith(".class")) {
entries_checked++;
if (je.getName().compareTo("META-INF/MANIFEST.MF") == 0) {
Manifest mf1 = new Manifest(jf1.getInputStream(je));
Manifest mf2 = new Manifest(jf2.getInputStream(je));
if (!mf1.equals(mf2)) {
Globals.log("Error: Manifests differ");
Globals.log("Manifest1");
Globals.log(mf1.getMainAttributes().entrySet().toString());
Globals.log("Manifest2");
Globals.log(mf2.getMainAttributes().entrySet().toString());
}
} else {
checkEntry(jf1, jf2, je);
}
} else if (Globals.bitWiseClassCompare() == true) {
checkEntry(jf1, jf2, je);
classes_checked++;
}
}
if (Globals.bitWiseClassCompare()) {
Globals.println("Class entries checked (byte wise)/Total Class entries = "
+ classes_checked + "/" + nclasses);
}
Globals.println("Non-class entries checked/Total non-class entries = "
+ entries_checked + "/" + nentries);
} catch (IOException ioe) {
throw new RuntimeException(ioe);
}
}
}

View file

@ -1,171 +0,0 @@
/*
* Copyright (c) 2010, 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.
*
* 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.
*/
// The Main Entry point
package sun.tools.pack.verify;
import java.io.*;
/**
* This class provides a convenient entry point to the pack200 verifier. This
* compares two classes, either in path or in an archive.
* @see xmlkit.XMLKit
* @author ksrini
*/
public class Main {
private static void syntax() {
System.out.println("Usage: ");
System.out.println("\tREFERENCE_CLASSPATH COMPARED_CLASSPATH [Options]");
System.out.println("\tOptions:");
System.out.println("\t\t-O check jar ordering");
System.out.println("\t\t-C ignore compile attributes (Deprecated, SourceFile, Synthetic, )");
System.out.println("\t\t-D ignore debug attributes (LocalVariable, LineNumber)");
System.out.println("\t\t-u ignore unknown attributes");
System.out.println("\t\t-V turn off class validation");
System.out.println("\t\t-c CLASS, compare CLASS only");
System.out.println("\t\t-b Compares all entries bitwise only");
System.out.println("\t\t-l Directory or Log File Name");
}
/**
* main entry point to the class file comparator, which compares semantically
* class files in a classpath or an archive.
* @param args String array as described below
* @throws RuntimeException
* <pre>
* Usage:
* ReferenceClasspath SpecimenClaspath [Options]
* Options:
* -O check jar ordering
* -C do not compare compile attributes (Deprecated, SourceFile, Synthetic)
* -D do not compare debug attribute (LocalVariableTable, LineNumberTable)
* -u ignore unknown attributes
* -V turn off class validation
* -c class, compare a single class
* -b compares all entries bitwise (fastest)
* -l directory or log file name
* </pre>
*/
public static void main(String args[]) {
Globals.getInstance();
if (args == null || args.length < 2) {
syntax();
System.exit(1);
}
String refJarFileName = null;
String cmpJarFileName = null;
String specificClass = null;
String logDirFileName = null;
for (int i = 0; i < args.length; i++) {
if (i == 0) {
refJarFileName = args[0];
continue;
}
if (i == 1) {
cmpJarFileName = args[1];
continue;
}
if (args[i].startsWith("-O")) {
Globals.setCheckJarClassOrdering(true);
}
if (args[i].startsWith("-b")) {
Globals.setBitWiseClassCompare(true);
}
if (args[i].startsWith("-C")) {
Globals.setIgnoreCompileAttributes(true);
}
if (args[i].startsWith("-D")) {
Globals.setIgnoreDebugAttributes(true);
}
if (args[i].startsWith("-V")) {
Globals.setValidateClass(false);
}
if (args[i].startsWith("-c")) {
i++;
specificClass = args[i].trim();
}
if (args[i].startsWith("-u")) {
i++;
Globals.setIgnoreUnknownAttributes(true);
}
if (args[i].startsWith("-l")) {
i++;
logDirFileName = args[i].trim();
}
}
Globals.openLog(logDirFileName);
File refJarFile = new File(refJarFileName);
File cmpJarFile = new File(cmpJarFileName);
String f1 = refJarFile.getAbsoluteFile().toString();
String f2 = cmpJarFile.getAbsoluteFile().toString();
System.out.println("LogFile:" + Globals.getLogFileName());
System.out.println("Reference JAR:" + f1);
System.out.println("Compared JAR:" + f2);
Globals.println("LogFile:" + Globals.getLogFileName());
Globals.println("Reference JAR:" + f1);
Globals.println("Compared JAR:" + f2);
Globals.println("Ignore Compile Attributes:" + Globals.ignoreCompileAttributes());
Globals.println("Ignore Debug Attributes:" + Globals.ignoreDebugAttributes());
Globals.println("Ignore Unknown Attributes:" + Globals.ignoreUnknownAttributes());
Globals.println("Class ordering check:" + Globals.checkJarClassOrdering());
Globals.println("Class validation check:" + Globals.validateClass());
Globals.println("Bit-wise compare:" + Globals.bitWiseClassCompare());
Globals.println("ClassName:" + ((specificClass == null) ? "ALL" : specificClass));
if (specificClass == null && Globals.bitWiseClassCompare() == true) {
JarFileCompare.jarCompare(refJarFileName, cmpJarFileName);
} else {
try {
ClassCompare.compareClass(refJarFileName, cmpJarFileName, specificClass);
} catch (Exception e) {
Globals.log("Exception " + e);
throw new RuntimeException(e);
}
}
if (Globals.getErrors() > 0) {
System.out.println("FAIL");
Globals.println("FAIL");
System.exit(Globals.getErrors());
}
System.out.println("PASS");
Globals.println("PASS");
System.exit(Globals.getErrors());
}
}

View file

@ -1,46 +0,0 @@
/*
* Copyright (c) 2010, 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.
*
* 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 sun.tools.pack.verify;
import java.util.*;
/*
* @author ksrini
*/
class VerifyTreeSet<K> extends java.util.TreeSet {
VerifyTreeSet() {
super();
}
public VerifyTreeSet(Comparator c) {
super(c);
}
public TreeSet<K> diff(TreeSet in) {
TreeSet<K> delta = (TreeSet<K>) this.clone();
delta.removeAll(in);
return delta;
}
}

View file

@ -1,282 +0,0 @@
/*
* Copyright (c) 2010, 2018, 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.
*
* 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 xmlkit; // -*- mode: java; indent-tabs-mode: nil -*-
import java.util.*;
/*
* @author jrose
*/
public class CommandLineParser {
public CommandLineParser(String optionString) {
setOptionMap(optionString);
}
TreeMap<String, String[]> optionMap;
public void setOptionMap(String options) {
// Convert options string into optLines dictionary.
TreeMap<String, String[]> optmap = new TreeMap<String, String[]>();
loadOptmap:
for (String optline : options.split("\n")) {
String[] words = optline.split("\\p{Space}+");
if (words.length == 0) {
continue loadOptmap;
}
String opt = words[0];
words[0] = ""; // initial word is not a spec
if (opt.length() == 0 && words.length >= 1) {
opt = words[1]; // initial "word" is empty due to leading ' '
words[1] = "";
}
if (opt.length() == 0) {
continue loadOptmap;
}
String[] prevWords = optmap.put(opt, words);
if (prevWords != null) {
throw new RuntimeException("duplicate option: "
+ optline.trim());
}
}
optionMap = optmap;
}
public String getOptionMap() {
TreeMap<String, String[]> optmap = optionMap;
StringBuffer sb = new StringBuffer();
for (String opt : optmap.keySet()) {
sb.append(opt);
for (String spec : optmap.get(opt)) {
sb.append(' ').append(spec);
}
sb.append('\n');
}
return sb.toString();
}
/**
* Remove a set of command-line options from args,
* storing them in the properties map in a canonicalized form.
*/
public String parse(List<String> args, Map<String, String> properties) {
//System.out.println(args+" // "+properties);
String resultString = null;
TreeMap<String, String[]> optmap = optionMap;
// State machine for parsing a command line.
ListIterator<String> argp = args.listIterator();
ListIterator<String> pbp = new ArrayList<String>().listIterator();
doArgs:
for (;;) {
// One trip through this loop per argument.
// Multiple trips per option only if several options per argument.
String arg;
if (pbp.hasPrevious()) {
arg = pbp.previous();
pbp.remove();
} else if (argp.hasNext()) {
arg = argp.next();
} else {
// No more arguments at all.
break doArgs;
}
tryOpt:
for (int optlen = arg.length();; optlen--) {
// One time through this loop for each matching arg prefix.
String opt;
// Match some prefix of the argument to a key in optmap.
findOpt:
for (;;) {
opt = arg.substring(0, optlen);
if (optmap.containsKey(opt)) {
break findOpt;
}
if (optlen == 0) {
break tryOpt;
}
// Decide on a smaller prefix to search for.
SortedMap<String, String[]> pfxmap = optmap.headMap(opt);
// pfxmap.lastKey is no shorter than any prefix in optmap.
int len = pfxmap.isEmpty() ? 0 : pfxmap.lastKey().length();
optlen = Math.min(len, optlen - 1);
opt = arg.substring(0, optlen);
// (Note: We could cut opt down to its common prefix with
// pfxmap.lastKey, but that wouldn't save many cycles.)
}
opt = opt.intern();
assert (arg.startsWith(opt));
assert (opt.length() == optlen);
String val = arg.substring(optlen); // arg == opt+val
// Execute the option processing specs for this opt.
// If no actions are taken, then look for a shorter prefix.
boolean didAction = false;
boolean isError = false;
int pbpMark = pbp.nextIndex(); // in case of backtracking
String[] specs = optmap.get(opt);
eachSpec:
for (String spec : specs) {
if (spec.length() == 0) {
continue eachSpec;
}
if (spec.startsWith("#")) {
break eachSpec;
}
int sidx = 0;
char specop = spec.charAt(sidx++);
// Deal with '+'/'*' prefixes (spec conditions).
boolean ok;
switch (specop) {
case '+':
// + means we want an non-empty val suffix.
ok = (val.length() != 0);
specop = spec.charAt(sidx++);
break;
case '*':
// * means we accept empty or non-empty
ok = true;
specop = spec.charAt(sidx++);
break;
default:
// No condition prefix means we require an exact
// match, as indicated by an empty val suffix.
ok = (val.length() == 0);
break;
}
if (!ok) {
continue eachSpec;
}
String specarg = spec.substring(sidx);
switch (specop) {
case '.': // terminate the option sequence
resultString = (specarg.length() != 0) ? specarg.intern() : opt;
break doArgs;
case '?': // abort the option sequence
resultString = (specarg.length() != 0) ? specarg.intern() : arg;
isError = true;
break eachSpec;
case '@': // change the effective opt name
opt = specarg.intern();
break;
case '>': // shift remaining arg val to next arg
pbp.add(specarg + val); // push a new argument
val = "";
break;
case '!': // negation option
String negopt = (specarg.length() != 0) ? specarg.intern() : opt;
properties.remove(negopt);
properties.put(negopt, null); // leave placeholder
didAction = true;
break;
case '$': // normal "boolean" option
String boolval;
if (specarg.length() != 0) {
// If there is a given spec token, store it.
boolval = specarg;
} else {
String old = properties.get(opt);
if (old == null || old.length() == 0) {
boolval = "1";
} else {
// Increment any previous value as a numeral.
boolval = "" + (1 + Integer.parseInt(old));
}
}
properties.put(opt, boolval);
didAction = true;
break;
case '=': // "string" option
case '&': // "collection" option
// Read an option.
boolean append = (specop == '&');
String strval;
if (pbp.hasPrevious()) {
strval = pbp.previous();
pbp.remove();
} else if (argp.hasNext()) {
strval = argp.next();
} else {
resultString = arg + " ?";
isError = true;
break eachSpec;
}
if (append) {
String old = properties.get(opt);
if (old != null) {
// Append new val to old with embedded delim.
String delim = specarg;
if (delim.length() == 0) {
delim = " ";
}
strval = old + specarg + strval;
}
}
properties.put(opt, strval);
didAction = true;
break;
default:
throw new RuntimeException("bad spec for "
+ opt + ": " + spec);
}
}
// Done processing specs.
if (didAction && !isError) {
continue doArgs;
}
// The specs should have done something, but did not.
while (pbp.nextIndex() > pbpMark) {
// Remove anything pushed during these specs.
pbp.previous();
pbp.remove();
}
if (isError) {
throw new IllegalArgumentException(resultString);
}
if (optlen == 0) {
// We cannot try a shorter matching option.
break tryOpt;
}
}
// If we come here, there was no matching option.
// So, push back the argument, and return to caller.
pbp.add(arg);
break doArgs;
}
// Report number of arguments consumed.
args.subList(0, argp.nextIndex()).clear();
// Report any unconsumed partial argument.
while (pbp.hasPrevious()) {
args.add(0, pbp.previous());
}
//System.out.println(args+" // "+properties+" -> "+resultString);
return resultString;
}
}

Some files were not shown because too many files have changed in this diff Show more