Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
openanolis
dragonwell8_jdk
提交
130dc864
D
dragonwell8_jdk
项目概览
openanolis
/
dragonwell8_jdk
通知
4
Star
2
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
D
dragonwell8_jdk
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
130dc864
编写于
8月 23, 2010
作者:
L
lana
浏览文件
操作
浏览文件
下载
差异文件
Merge
上级
7f54b605
957224b8
变更
71
隐藏空白更改
内联
并排
Showing
71 changed file
with
11886 addition
and
1091 deletion
+11886
-1091
make/common/shared/Defs-windows.gmk
make/common/shared/Defs-windows.gmk
+1
-1
make/common/shared/Defs.gmk
make/common/shared/Defs.gmk
+8
-3
make/jdk_generic_profile.sh
make/jdk_generic_profile.sh
+55
-0
src/share/classes/com/sun/java/util/jar/pack/Attribute.java
src/share/classes/com/sun/java/util/jar/pack/Attribute.java
+47
-53
src/share/classes/com/sun/java/util/jar/pack/ConstantPool.java
...hare/classes/com/sun/java/util/jar/pack/ConstantPool.java
+62
-51
src/share/classes/com/sun/java/util/jar/pack/Driver.java
src/share/classes/com/sun/java/util/jar/pack/Driver.java
+13
-10
src/share/classes/com/sun/java/util/jar/pack/NativeUnpack.java
...hare/classes/com/sun/java/util/jar/pack/NativeUnpack.java
+4
-9
src/share/classes/com/sun/java/util/jar/pack/Package.java
src/share/classes/com/sun/java/util/jar/pack/Package.java
+59
-63
src/share/classes/com/sun/java/util/jar/pack/PackerImpl.java
src/share/classes/com/sun/java/util/jar/pack/PackerImpl.java
+65
-75
src/share/classes/com/sun/java/util/jar/pack/PropMap.java
src/share/classes/com/sun/java/util/jar/pack/PropMap.java
+1
-1
src/share/classes/com/sun/java/util/jar/pack/TLGlobals.java
src/share/classes/com/sun/java/util/jar/pack/TLGlobals.java
+97
-0
src/share/classes/com/sun/java/util/jar/pack/UnpackerImpl.java
...hare/classes/com/sun/java/util/jar/pack/UnpackerImpl.java
+32
-35
src/share/classes/com/sun/java/util/jar/pack/Utils.java
src/share/classes/com/sun/java/util/jar/pack/Utils.java
+42
-6
src/share/classes/com/sun/jndi/ldap/Connection.java
src/share/classes/com/sun/jndi/ldap/Connection.java
+2
-1
src/share/classes/java/lang/AbstractStringBuilder.java
src/share/classes/java/lang/AbstractStringBuilder.java
+3
-2
src/share/classes/java/lang/Thread.java
src/share/classes/java/lang/Thread.java
+12
-0
src/share/classes/java/lang/Throwable.java
src/share/classes/java/lang/Throwable.java
+24
-10
src/share/classes/java/net/HttpCookie.java
src/share/classes/java/net/HttpCookie.java
+6
-10
src/share/classes/java/net/URI.java
src/share/classes/java/net/URI.java
+1
-3
src/share/classes/java/security/KeyStore.java
src/share/classes/java/security/KeyStore.java
+6
-4
src/share/classes/java/sql/Date.java
src/share/classes/java/sql/Date.java
+30
-11
src/share/classes/sun/net/www/protocol/file/FileURLConnection.java
.../classes/sun/net/www/protocol/file/FileURLConnection.java
+6
-3
src/share/classes/sun/net/www/protocol/http/HttpURLConnection.java
.../classes/sun/net/www/protocol/http/HttpURLConnection.java
+4
-0
src/share/classes/sun/nio/ch/DatagramChannelImpl.java
src/share/classes/sun/nio/ch/DatagramChannelImpl.java
+12
-26
src/share/classes/sun/nio/ch/FileChannelImpl.java
src/share/classes/sun/nio/ch/FileChannelImpl.java
+70
-46
src/share/classes/sun/nio/ch/IOUtil.java
src/share/classes/sun/nio/ch/IOUtil.java
+131
-173
src/share/classes/sun/nio/ch/IOVecWrapper.java
src/share/classes/sun/nio/ch/IOVecWrapper.java
+85
-13
src/share/classes/sun/nio/ch/SocketChannelImpl.java
src/share/classes/sun/nio/ch/SocketChannelImpl.java
+12
-26
src/share/classes/sun/nio/ch/Util.java
src/share/classes/sun/nio/ch/Util.java
+157
-44
src/share/lib/security/java.security-solaris
src/share/lib/security/java.security-solaris
+27
-0
src/share/lib/security/java.security-windows
src/share/lib/security/java.security-windows
+27
-0
src/share/native/common/check_code.c
src/share/native/common/check_code.c
+13
-4
src/solaris/classes/java/io/UnixFileSystem.java
src/solaris/classes/java/io/UnixFileSystem.java
+0
-1
src/solaris/classes/sun/nio/fs/UnixPath.java
src/solaris/classes/sun/nio/fs/UnixPath.java
+7
-0
src/solaris/native/java/net/PlainDatagramSocketImpl.c
src/solaris/native/java/net/PlainDatagramSocketImpl.c
+22
-14
src/solaris/native/java/net/PlainSocketImpl.c
src/solaris/native/java/net/PlainSocketImpl.c
+29
-13
src/solaris/native/sun/nio/ch/Net.c
src/solaris/native/sun/nio/ch/Net.c
+16
-0
src/windows/classes/java/io/Win32FileSystem.java
src/windows/classes/java/io/Win32FileSystem.java
+0
-1
test/java/lang/ClassLoader/deadlock/TestCrossDelegate.sh
test/java/lang/ClassLoader/deadlock/TestCrossDelegate.sh
+1
-1
test/java/net/URI/Test.java
test/java/net/URI/Test.java
+14
-0
test/java/nio/file/Path/Misc.java
test/java/nio/file/Path/Misc.java
+15
-0
test/sun/jvmstat/monitor/MonitoredVm/MonitorVmStartTerminate.sh
...un/jvmstat/monitor/MonitoredVm/MonitorVmStartTerminate.sh
+1
-0
test/sun/net/www/protocol/file/DirPermissionDenied.java
test/sun/net/www/protocol/file/DirPermissionDenied.java
+59
-0
test/sun/net/www/protocol/file/DirPermissionDenied.sh
test/sun/net/www/protocol/file/DirPermissionDenied.sh
+41
-0
test/sun/security/krb5/BadKdcDefaultValue.java
test/sun/security/krb5/BadKdcDefaultValue.java
+40
-0
test/sun/security/ssl/sun/net/www/protocol/https/HttpsURLConnection/B6226610.java
...n/net/www/protocol/https/HttpsURLConnection/B6226610.java
+26
-53
test/tools/jar/JarEntryTime.java
test/tools/jar/JarEntryTime.java
+12
-9
test/tools/pack200/CommandLineTests.java
test/tools/pack200/CommandLineTests.java
+179
-0
test/tools/pack200/Pack200Props.java
test/tools/pack200/Pack200Props.java
+128
-0
test/tools/pack200/Pack200Simple.sh
test/tools/pack200/Pack200Simple.sh
+0
-197
test/tools/pack200/Pack200Test.java
test/tools/pack200/Pack200Test.java
+72
-85
test/tools/pack200/PackageVersionTest.java
test/tools/pack200/PackageVersionTest.java
+13
-34
test/tools/pack200/TimeStamp.java
test/tools/pack200/TimeStamp.java
+156
-0
test/tools/pack200/UnpackerMemoryTest.java
test/tools/pack200/UnpackerMemoryTest.java
+86
-0
test/tools/pack200/Utils.java
test/tools/pack200/Utils.java
+516
-0
test/tools/pack200/pack200-verifier/data/README
test/tools/pack200/pack200-verifier/data/README
+45
-0
test/tools/pack200/pack200-verifier/data/golden.jar
test/tools/pack200/pack200-verifier/data/golden.jar
+0
-0
test/tools/pack200/pack200-verifier/make/build.xml
test/tools/pack200/pack200-verifier/make/build.xml
+59
-0
test/tools/pack200/pack200-verifier/src/sun/tools/pack/verify/ClassCompare.java
...k200-verifier/src/sun/tools/pack/verify/ClassCompare.java
+160
-0
test/tools/pack200/pack200-verifier/src/sun/tools/pack/verify/Globals.java
...0/pack200-verifier/src/sun/tools/pack/verify/Globals.java
+310
-0
test/tools/pack200/pack200-verifier/src/sun/tools/pack/verify/JarFileCompare.java
...00-verifier/src/sun/tools/pack/verify/JarFileCompare.java
+199
-0
test/tools/pack200/pack200-verifier/src/sun/tools/pack/verify/Main.java
...k200/pack200-verifier/src/sun/tools/pack/verify/Main.java
+171
-0
test/tools/pack200/pack200-verifier/src/sun/tools/pack/verify/VerifyTreeSet.java
...200-verifier/src/sun/tools/pack/verify/VerifyTreeSet.java
+46
-0
test/tools/pack200/pack200-verifier/src/xmlkit/ClassReader.java
...ools/pack200/pack200-verifier/src/xmlkit/ClassReader.java
+1003
-0
test/tools/pack200/pack200-verifier/src/xmlkit/ClassSyntax.java
...ools/pack200/pack200-verifier/src/xmlkit/ClassSyntax.java
+518
-0
test/tools/pack200/pack200-verifier/src/xmlkit/ClassWriter.java
...ools/pack200/pack200-verifier/src/xmlkit/ClassWriter.java
+818
-0
test/tools/pack200/pack200-verifier/src/xmlkit/CommandLineParser.java
...ack200/pack200-verifier/src/xmlkit/CommandLineParser.java
+284
-0
test/tools/pack200/pack200-verifier/src/xmlkit/InstructionAssembler.java
...200/pack200-verifier/src/xmlkit/InstructionAssembler.java
+464
-0
test/tools/pack200/pack200-verifier/src/xmlkit/InstructionSyntax.java
...ack200/pack200-verifier/src/xmlkit/InstructionSyntax.java
+483
-0
test/tools/pack200/pack200-verifier/src/xmlkit/TokenList.java
.../tools/pack200/pack200-verifier/src/xmlkit/TokenList.java
+449
-0
test/tools/pack200/pack200-verifier/src/xmlkit/XMLKit.java
test/tools/pack200/pack200-verifier/src/xmlkit/XMLKit.java
+4330
-0
未找到文件。
make/common/shared/Defs-windows.gmk
浏览文件 @
130dc864
...
@@ -89,7 +89,7 @@ define FullPath
...
@@ -89,7 +89,7 @@ define FullPath
$(shell $(CYGPATH_CMD) $1 2> $(DEV_NULL))
$(shell $(CYGPATH_CMD) $1 2> $(DEV_NULL))
endef
endef
define OptFullPath
define OptFullPath
$(shell if [ "$1" != "" -a -d "$1" ]; then $(CYGPATH_CMD) "$1"; else echo "$1"; fi)
$(shell if [ "$1" != "" -a -d "$1" ]; then $(CYGPATH_CMD) "$1"
2> $(DEV_NULL)
; else echo "$1"; fi)
endef
endef
else
else
# Temporary until we upgrade to MKS 8.7, MKS pwd returns mixed mode path
# Temporary until we upgrade to MKS 8.7, MKS pwd returns mixed mode path
...
...
make/common/shared/Defs.gmk
浏览文件 @
130dc864
...
@@ -136,15 +136,20 @@ define GetVersion
...
@@ -136,15 +136,20 @@ define GetVersion
$(shell echo $1 | sed -e 's@[^0-9]*\([0-9][0-9]*\.[0-9][.0-9]*\).*@\1@' )
$(shell echo $1 | sed -e 's@[^0-9]*\([0-9][0-9]*\.[0-9][.0-9]*\).*@\1@' )
endef
endef
# Return one part of the version numbers, watch out for non digits.
define VersionWord # Number Version
$(word $1,$(subst ., ,$(subst -, ,$2)))
endef
# Given a major.minor.micro version, return the major, minor, or micro number
# Given a major.minor.micro version, return the major, minor, or micro number
define MajorVersion
define MajorVersion
$(if $(
word 1, $(subst ., ,$1)),$(word 1, $(subst ., ,$1)
),0)
$(if $(
call VersionWord,1,$1),$(call VersionWord,1,$1
),0)
endef
endef
define MinorVersion
define MinorVersion
$(if $(
word 2, $(subst ., ,$1)),$(word 2, $(subst ., ,$1)
),0)
$(if $(
call VersionWord,2,$1),$(call VersionWord,2,$1
),0)
endef
endef
define MicroVersion
define MicroVersion
$(if $(
word 3, $(subst ., ,$1)),$(word 3, $(subst ., ,$1)
),0)
$(if $(
call VersionWord,3,$1),$(call VersionWord,3,$1
),0)
endef
endef
# Macro that returns missing, same, newer, or older $1=version $2=required
# Macro that returns missing, same, newer, or older $1=version $2=required
...
...
make/jdk_generic_profile.sh
浏览文件 @
130dc864
...
@@ -340,6 +340,10 @@ PATH="${path4sdk}"
...
@@ -340,6 +340,10 @@ PATH="${path4sdk}"
export
PATH
export
PATH
# Export variables required for Zero
# Export variables required for Zero
if
[
"
${
SHARK_BUILD
}
"
=
true
]
;
then
ZERO_BUILD
=
true
export
ZERO_BUILD
fi
if
[
"
${
ZERO_BUILD
}
"
=
true
]
;
then
if
[
"
${
ZERO_BUILD
}
"
=
true
]
;
then
# ZERO_LIBARCH is the name of the architecture-specific
# ZERO_LIBARCH is the name of the architecture-specific
# subdirectory under $JAVA_HOME/jre/lib
# subdirectory under $JAVA_HOME/jre/lib
...
@@ -417,4 +421,55 @@ if [ "${ZERO_BUILD}" = true ] ; then
...
@@ -417,4 +421,55 @@ if [ "${ZERO_BUILD}" = true ] ; then
fi
fi
export
LIBFFI_CFLAGS
export
LIBFFI_CFLAGS
export
LIBFFI_LIBS
export
LIBFFI_LIBS
# LLVM_CFLAGS, LLVM_LDFLAGS and LLVM_LIBS tell the compiler how to
# compile and link against LLVM
if
[
"
${
SHARK_BUILD
}
"
=
true
]
;
then
if
[
"
${
LLVM_CONFIG
}
"
=
""
]
;
then
LLVM_CONFIG
=
$(
which llvm-config 2>/dev/null
)
fi
if
[
!
-x
"
${
LLVM_CONFIG
}
"
]
;
then
echo
"ERROR: Unable to locate llvm-config"
exit
1
fi
llvm_components
=
"jit engine nativecodegen"
unset
LLVM_CFLAGS
for
flag
in
$(
"
${
LLVM_CONFIG
}
"
--cxxflags
$llvm_components
)
;
do
if
echo
"
${
flag
}
"
|
grep
-q
'^-[ID]'
;
then
if
[
"
${
flag
}
"
!=
"-D_DEBUG"
]
;
then
if
[
"
${
LLVM_CFLAGS
}
"
!=
""
]
;
then
LLVM_CFLAGS
=
"
${
LLVM_CFLAGS
}
"
fi
LLVM_CFLAGS
=
"
${
LLVM_CFLAGS
}${
flag
}
"
fi
fi
done
llvm_version
=
$(
"
${
LLVM_CONFIG
}
"
--version
|
sed
's/\.//; s/svn.*//'
)
LLVM_CFLAGS
=
"
${
LLVM_CFLAGS
}
-DSHARK_LLVM_VERSION=
${
llvm_version
}
"
unset
LLVM_LDFLAGS
for
flag
in
$(
"
${
LLVM_CONFIG
}
"
--ldflags
$llvm_components
)
;
do
if
echo
"
${
flag
}
"
|
grep
-q
'^-L'
;
then
if
[
"
${
LLVM_LDFLAGS
}
"
!=
""
]
;
then
LLVM_LDFLAGS
=
"
${
LLVM_LDFLAGS
}
"
fi
LLVM_LDFLAGS
=
"
${
LLVM_LDFLAGS
}${
flag
}
"
fi
done
unset
LLVM_LIBS
for
flag
in
$(
"
${
LLVM_CONFIG
}
"
--libs
$llvm_components
)
;
do
if
echo
"
${
flag
}
"
|
grep
-q
'^-l'
;
then
if
[
"
${
LLVM_LIBS
}
"
!=
""
]
;
then
LLVM_LIBS
=
"
${
LLVM_LIBS
}
"
fi
LLVM_LIBS
=
"
${
LLVM_LIBS
}${
flag
}
"
fi
done
export
LLVM_CFLAGS
export
LLVM_LDFLAGS
export
LLVM_LIBS
fi
fi
fi
src/share/classes/com/sun/java/util/jar/pack/Attribute.java
浏览文件 @
130dc864
/*
/*
* Copyright (c) 2003, 20
05
, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 20
10
, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
*
* This code is free software; you can redistribute it and/or modify it
* This code is free software; you can redistribute it and/or modify it
...
@@ -27,7 +27,6 @@ package com.sun.java.util.jar.pack;
...
@@ -27,7 +27,6 @@ package com.sun.java.util.jar.pack;
import
java.io.*
;
import
java.io.*
;
import
java.util.*
;
import
java.util.*
;
import
com.sun.java.util.jar.pack.Package.Class
;
import
com.sun.java.util.jar.pack.ConstantPool.*
;
import
com.sun.java.util.jar.pack.ConstantPool.*
;
/**
/**
...
@@ -96,20 +95,20 @@ class Attribute implements Comparable, Constants {
...
@@ -96,20 +95,20 @@ class Attribute implements Comparable, Constants {
return
this
.
def
.
compareTo
(
that
.
def
);
return
this
.
def
.
compareTo
(
that
.
def
);
}
}
static
private
final
byte
[]
noBytes
=
{};
private
static
final
byte
[]
noBytes
=
{};
static
private
final
HashMap
canonLists
=
new
HashMap
();
private
static
final
Map
<
List
<
Attribute
>,
List
<
Attribute
>>
canonLists
=
new
HashMap
<>
();
static
private
final
HashMap
attributes
=
new
HashMap
();
private
static
final
Map
<
Layout
,
Attribute
>
attributes
=
new
HashMap
<>
();
static
private
final
HashMap
standardDefs
=
new
HashMap
();
private
static
final
Map
<
Layout
,
Attribute
>
standardDefs
=
new
HashMap
<>
();
// Canonicalized lists of trivial attrs (Deprecated, etc.)
// Canonicalized lists of trivial attrs (Deprecated, etc.)
// are used by trimToSize, in order to reduce footprint
// are used by trimToSize, in order to reduce footprint
// of some common cases. (Note that Code attributes are
// of some common cases. (Note that Code attributes are
// always zero size.)
// always zero size.)
public
static
List
getCanonList
(
List
al
)
{
public
static
List
getCanonList
(
List
<
Attribute
>
al
)
{
synchronized
(
canonLists
)
{
synchronized
(
canonLists
)
{
List
cl
=
(
List
)
canonLists
.
get
(
al
);
List
<
Attribute
>
cl
=
canonLists
.
get
(
al
);
if
(
cl
==
null
)
{
if
(
cl
==
null
)
{
cl
=
new
ArrayList
(
al
.
size
());
cl
=
new
ArrayList
<>
(
al
.
size
());
cl
.
addAll
(
al
);
cl
.
addAll
(
al
);
cl
=
Collections
.
unmodifiableList
(
cl
);
cl
=
Collections
.
unmodifiableList
(
cl
);
canonLists
.
put
(
al
,
cl
);
canonLists
.
put
(
al
,
cl
);
...
@@ -122,7 +121,7 @@ class Attribute implements Comparable, Constants {
...
@@ -122,7 +121,7 @@ class Attribute implements Comparable, Constants {
public
static
Attribute
find
(
int
ctype
,
String
name
,
String
layout
)
{
public
static
Attribute
find
(
int
ctype
,
String
name
,
String
layout
)
{
Layout
key
=
Layout
.
makeKey
(
ctype
,
name
,
layout
);
Layout
key
=
Layout
.
makeKey
(
ctype
,
name
,
layout
);
synchronized
(
attributes
)
{
synchronized
(
attributes
)
{
Attribute
a
=
(
Attribute
)
attributes
.
get
(
key
);
Attribute
a
=
attributes
.
get
(
key
);
if
(
a
==
null
)
{
if
(
a
==
null
)
{
a
=
new
Layout
(
ctype
,
name
,
layout
).
canonicalInstance
();
a
=
new
Layout
(
ctype
,
name
,
layout
).
canonicalInstance
();
attributes
.
put
(
key
,
a
);
attributes
.
put
(
key
,
a
);
...
@@ -131,24 +130,29 @@ class Attribute implements Comparable, Constants {
...
@@ -131,24 +130,29 @@ class Attribute implements Comparable, Constants {
}
}
}
}
public
static
Objec
t
keyForLookup
(
int
ctype
,
String
name
)
{
public
static
Layou
t
keyForLookup
(
int
ctype
,
String
name
)
{
return
Layout
.
makeKey
(
ctype
,
name
);
return
Layout
.
makeKey
(
ctype
,
name
);
}
}
// Find canonical empty attribute with given ctype and name,
// Find canonical empty attribute with given ctype and name,
// and with the standard layout.
// and with the standard layout.
public
static
Attribute
lookup
(
Map
defs
,
int
ctype
,
String
name
)
{
public
static
Attribute
lookup
(
Map
<
Layout
,
Attribute
>
defs
,
int
ctype
,
if
(
defs
==
null
)
defs
=
standardDefs
;
String
name
)
{
return
(
Attribute
)
defs
.
get
(
Layout
.
makeKey
(
ctype
,
name
));
if
(
defs
==
null
)
{
defs
=
standardDefs
;
}
return
defs
.
get
(
Layout
.
makeKey
(
ctype
,
name
));
}
}
public
static
Attribute
define
(
Map
defs
,
int
ctype
,
String
name
,
String
layout
)
{
public
static
Attribute
define
(
Map
<
Layout
,
Attribute
>
defs
,
int
ctype
,
String
name
,
String
layout
)
{
Attribute
a
=
find
(
ctype
,
name
,
layout
);
Attribute
a
=
find
(
ctype
,
name
,
layout
);
defs
.
put
(
Layout
.
makeKey
(
ctype
,
name
),
a
);
defs
.
put
(
Layout
.
makeKey
(
ctype
,
name
),
a
);
return
a
;
return
a
;
}
}
static
{
static
{
Map
sd
=
standardDefs
;
Map
<
Layout
,
Attribute
>
sd
=
standardDefs
;
define
(
sd
,
ATTR_CONTEXT_CLASS
,
"Signature"
,
"RSH"
);
define
(
sd
,
ATTR_CONTEXT_CLASS
,
"Signature"
,
"RSH"
);
define
(
sd
,
ATTR_CONTEXT_CLASS
,
"Synthetic"
,
""
);
define
(
sd
,
ATTR_CONTEXT_CLASS
,
"Synthetic"
,
""
);
define
(
sd
,
ATTR_CONTEXT_CLASS
,
"Deprecated"
,
""
);
define
(
sd
,
ATTR_CONTEXT_CLASS
,
"Deprecated"
,
""
);
...
@@ -244,7 +248,7 @@ class Attribute implements Comparable, Constants {
...
@@ -244,7 +248,7 @@ class Attribute implements Comparable, Constants {
+
"\n ()[] ]"
+
"\n ()[] ]"
)
)
};
};
Map
sd
=
standardDefs
;
Map
<
Layout
,
Attribute
>
sd
=
standardDefs
;
String
defaultLayout
=
mdLayouts
[
2
];
String
defaultLayout
=
mdLayouts
[
2
];
String
annotationsLayout
=
mdLayouts
[
1
]
+
mdLayouts
[
2
];
String
annotationsLayout
=
mdLayouts
[
1
]
+
mdLayouts
[
2
];
String
paramsLayout
=
mdLayouts
[
0
]
+
annotationsLayout
;
String
paramsLayout
=
mdLayouts
[
0
]
+
annotationsLayout
;
...
@@ -275,10 +279,6 @@ class Attribute implements Comparable, Constants {
...
@@ -275,10 +279,6 @@ class Attribute implements Comparable, Constants {
return
null
;
return
null
;
}
}
public
static
Map
getStandardDefs
()
{
return
new
HashMap
(
standardDefs
);
}
/** Base class for any attributed object (Class, Field, Method, Code).
/** Base class for any attributed object (Class, Field, Method, Code).
* Flags are included because they are used to help transmit the
* Flags are included because they are used to help transmit the
* presence of attributes. That is, flags are a mix of modifier
* presence of attributes. That is, flags are a mix of modifier
...
@@ -291,7 +291,7 @@ class Attribute implements Comparable, Constants {
...
@@ -291,7 +291,7 @@ class Attribute implements Comparable, Constants {
protected
abstract
Entry
[]
getCPMap
();
protected
abstract
Entry
[]
getCPMap
();
protected
int
flags
;
// defined here for convenience
protected
int
flags
;
// defined here for convenience
protected
List
attributes
;
protected
List
<
Attribute
>
attributes
;
public
int
attributeSize
()
{
public
int
attributeSize
()
{
return
(
attributes
==
null
)
?
0
:
attributes
.
size
();
return
(
attributes
==
null
)
?
0
:
attributes
.
size
();
...
@@ -301,16 +301,15 @@ class Attribute implements Comparable, Constants {
...
@@ -301,16 +301,15 @@ class Attribute implements Comparable, Constants {
if
(
attributes
==
null
)
{
if
(
attributes
==
null
)
{
return
;
return
;
}
}
if
(
attributes
.
size
()
==
0
)
{
if
(
attributes
.
isEmpty
()
)
{
attributes
=
null
;
attributes
=
null
;
return
;
return
;
}
}
if
(
attributes
instanceof
ArrayList
)
{
if
(
attributes
instanceof
ArrayList
)
{
ArrayList
al
=
(
ArrayList
)
attributes
;
ArrayList
<
Attribute
>
al
=
(
ArrayList
<
Attribute
>)
attributes
;
al
.
trimToSize
();
al
.
trimToSize
();
boolean
allCanon
=
true
;
boolean
allCanon
=
true
;
for
(
Iterator
i
=
al
.
iterator
();
i
.
hasNext
();
)
{
for
(
Attribute
a
:
al
)
{
Attribute
a
=
(
Attribute
)
i
.
next
();
if
(!
a
.
isCanonical
())
{
if
(!
a
.
isCanonical
())
{
allCanon
=
false
;
allCanon
=
false
;
}
}
...
@@ -330,9 +329,9 @@ class Attribute implements Comparable, Constants {
...
@@ -330,9 +329,9 @@ class Attribute implements Comparable, Constants {
public
void
addAttribute
(
Attribute
a
)
{
public
void
addAttribute
(
Attribute
a
)
{
if
(
attributes
==
null
)
if
(
attributes
==
null
)
attributes
=
new
ArrayList
(
3
);
attributes
=
new
ArrayList
<>
(
3
);
else
if
(!(
attributes
instanceof
ArrayList
))
else
if
(!(
attributes
instanceof
ArrayList
))
attributes
=
new
ArrayList
(
attributes
);
// unfreeze it
attributes
=
new
ArrayList
<>
(
attributes
);
// unfreeze it
attributes
.
add
(
a
);
attributes
.
add
(
a
);
}
}
...
@@ -340,32 +339,31 @@ class Attribute implements Comparable, Constants {
...
@@ -340,32 +339,31 @@ class Attribute implements Comparable, Constants {
if
(
attributes
==
null
)
return
null
;
if
(
attributes
==
null
)
return
null
;
if
(!
attributes
.
contains
(
a
))
return
null
;
if
(!
attributes
.
contains
(
a
))
return
null
;
if
(!(
attributes
instanceof
ArrayList
))
if
(!(
attributes
instanceof
ArrayList
))
attributes
=
new
ArrayList
(
attributes
);
// unfreeze it
attributes
=
new
ArrayList
<>
(
attributes
);
// unfreeze it
attributes
.
remove
(
a
);
attributes
.
remove
(
a
);
return
a
;
return
a
;
}
}
public
Attribute
getAttribute
(
int
n
)
{
public
Attribute
getAttribute
(
int
n
)
{
return
(
Attribute
)
attributes
.
get
(
n
);
return
attributes
.
get
(
n
);
}
}
protected
void
visitRefs
(
int
mode
,
Collection
refs
)
{
protected
void
visitRefs
(
int
mode
,
Collection
<
Entry
>
refs
)
{
if
(
attributes
==
null
)
return
;
if
(
attributes
==
null
)
return
;
for
(
Iterator
i
=
attributes
.
iterator
();
i
.
hasNext
();
)
{
for
(
Attribute
a
:
attributes
)
{
Attribute
a
=
(
Attribute
)
i
.
next
();
a
.
visitRefs
(
this
,
mode
,
refs
);
a
.
visitRefs
(
this
,
mode
,
refs
);
}
}
}
}
static
final
List
noAttributes
=
Arrays
.
asList
(
new
Object
[
0
]);
static
final
List
<
Attribute
>
noAttributes
=
Arrays
.
asList
(
new
Attribute
[
0
]);
public
List
getAttributes
()
{
public
List
<
Attribute
>
getAttributes
()
{
if
(
attributes
==
null
)
if
(
attributes
==
null
)
return
noAttributes
;
return
noAttributes
;
return
attributes
;
return
attributes
;
}
}
public
void
setAttributes
(
List
attrList
)
{
public
void
setAttributes
(
List
<
Attribute
>
attrList
)
{
if
(
attrList
.
isEmpty
())
if
(
attrList
.
isEmpty
())
attributes
=
null
;
attributes
=
null
;
else
else
...
@@ -374,8 +372,7 @@ class Attribute implements Comparable, Constants {
...
@@ -374,8 +372,7 @@ class Attribute implements Comparable, Constants {
public
Attribute
getAttribute
(
String
attrName
)
{
public
Attribute
getAttribute
(
String
attrName
)
{
if
(
attributes
==
null
)
return
null
;
if
(
attributes
==
null
)
return
null
;
for
(
Iterator
i
=
attributes
.
iterator
();
i
.
hasNext
();
)
{
for
(
Attribute
a
:
attributes
)
{
Attribute
a
=
(
Attribute
)
i
.
next
();
if
(
a
.
name
().
equals
(
attrName
))
if
(
a
.
name
().
equals
(
attrName
))
return
a
;
return
a
;
}
}
...
@@ -384,8 +381,7 @@ class Attribute implements Comparable, Constants {
...
@@ -384,8 +381,7 @@ class Attribute implements Comparable, Constants {
public
Attribute
getAttribute
(
Layout
attrDef
)
{
public
Attribute
getAttribute
(
Layout
attrDef
)
{
if
(
attributes
==
null
)
return
null
;
if
(
attributes
==
null
)
return
null
;
for
(
Iterator
i
=
attributes
.
iterator
();
i
.
hasNext
();
)
{
for
(
Attribute
a
:
attributes
)
{
Attribute
a
=
(
Attribute
)
i
.
next
();
if
(
a
.
layout
()
==
attrDef
)
if
(
a
.
layout
()
==
attrDef
)
return
a
;
return
a
;
}
}
...
@@ -457,14 +453,8 @@ class Attribute implements Comparable, Constants {
...
@@ -457,14 +453,8 @@ class Attribute implements Comparable, Constants {
public
String
layout
()
{
return
layout
;
}
public
String
layout
()
{
return
layout
;
}
public
Attribute
canonicalInstance
()
{
return
canon
;
}
public
Attribute
canonicalInstance
()
{
return
canon
;
}
// Cache of name reference.
private
Entry
nameRef
;
// name, for use by visitRefs
public
Entry
getNameRef
()
{
public
Entry
getNameRef
()
{
Entry
nameRef
=
this
.
nameRef
;
return
ConstantPool
.
getUtf8Entry
(
name
());
if
(
nameRef
==
null
)
{
this
.
nameRef
=
nameRef
=
ConstantPool
.
getUtf8Entry
(
name
());
}
return
nameRef
;
}
}
public
boolean
isEmpty
()
{
return
layout
==
""
;
}
public
boolean
isEmpty
()
{
return
layout
==
""
;
}
...
@@ -834,14 +824,14 @@ class Attribute implements Comparable, Constants {
...
@@ -834,14 +824,14 @@ class Attribute implements Comparable, Constants {
*/
*/
static
//private
static
//private
Layout
.
Element
[]
tokenizeLayout
(
Layout
self
,
int
curCble
,
String
layout
)
{
Layout
.
Element
[]
tokenizeLayout
(
Layout
self
,
int
curCble
,
String
layout
)
{
ArrayList
col
=
new
ArrayList
(
layout
.
length
());
ArrayList
<
Layout
.
Element
>
col
=
new
ArrayList
<>
(
layout
.
length
());
tokenizeLayout
(
self
,
curCble
,
layout
,
col
);
tokenizeLayout
(
self
,
curCble
,
layout
,
col
);
Layout
.
Element
[]
res
=
new
Layout
.
Element
[
col
.
size
()];
Layout
.
Element
[]
res
=
new
Layout
.
Element
[
col
.
size
()];
col
.
toArray
(
res
);
col
.
toArray
(
res
);
return
res
;
return
res
;
}
}
static
//private
static
//private
void
tokenizeLayout
(
Layout
self
,
int
curCble
,
String
layout
,
ArrayList
col
)
{
void
tokenizeLayout
(
Layout
self
,
int
curCble
,
String
layout
,
ArrayList
<
Layout
.
Element
>
col
)
{
boolean
prevBCI
=
false
;
boolean
prevBCI
=
false
;
for
(
int
len
=
layout
.
length
(),
i
=
0
;
i
<
len
;
)
{
for
(
int
len
=
layout
.
length
(),
i
=
0
;
i
<
len
;
)
{
int
start
=
i
;
int
start
=
i
;
...
@@ -899,7 +889,7 @@ class Attribute implements Comparable, Constants {
...
@@ -899,7 +889,7 @@ class Attribute implements Comparable, Constants {
case
'T'
:
// union: 'T' any_int union_case* '(' ')' '[' body ']'
case
'T'
:
// union: 'T' any_int union_case* '(' ')' '[' body ']'
kind
=
EK_UN
;
kind
=
EK_UN
;
i
=
tokenizeSInt
(
e
,
layout
,
i
);
i
=
tokenizeSInt
(
e
,
layout
,
i
);
ArrayList
cases
=
new
ArrayList
();
ArrayList
<
Layout
.
Element
>
cases
=
new
ArrayList
<>
();
for
(;;)
{
for
(;;)
{
// Keep parsing cases until we hit the default case.
// Keep parsing cases until we hit the default case.
if
(
layout
.
charAt
(
i
++)
!=
'('
)
if
(
layout
.
charAt
(
i
++)
!=
'('
)
...
@@ -1053,7 +1043,7 @@ class Attribute implements Comparable, Constants {
...
@@ -1053,7 +1043,7 @@ class Attribute implements Comparable, Constants {
}
}
static
//private
static
//private
String
[]
splitBodies
(
String
layout
)
{
String
[]
splitBodies
(
String
layout
)
{
ArrayList
bodies
=
new
ArrayList
();
ArrayList
<
String
>
bodies
=
new
ArrayList
<>
();
// Parse several independent layout bodies: "[foo][bar]...[baz]"
// Parse several independent layout bodies: "[foo][bar]...[baz]"
for
(
int
i
=
0
;
i
<
layout
.
length
();
i
++)
{
for
(
int
i
=
0
;
i
<
layout
.
length
();
i
++)
{
if
(
layout
.
charAt
(
i
++)
!=
'['
)
if
(
layout
.
charAt
(
i
++)
!=
'['
)
...
@@ -1132,7 +1122,9 @@ class Attribute implements Comparable, Constants {
...
@@ -1132,7 +1122,9 @@ class Attribute implements Comparable, Constants {
int
parseIntBefore
(
String
layout
,
int
dash
)
{
int
parseIntBefore
(
String
layout
,
int
dash
)
{
int
end
=
dash
;
int
end
=
dash
;
int
beg
=
end
;
int
beg
=
end
;
while
(
beg
>
0
&&
isDigit
(
layout
.
charAt
(
beg
-
1
)))
--
beg
;
while
(
beg
>
0
&&
isDigit
(
layout
.
charAt
(
beg
-
1
)))
{
--
beg
;
}
if
(
beg
==
end
)
return
Integer
.
parseInt
(
"empty"
);
if
(
beg
==
end
)
return
Integer
.
parseInt
(
"empty"
);
// skip backward over a sign
// skip backward over a sign
if
(
beg
>=
1
&&
layout
.
charAt
(
beg
-
1
)
==
'-'
)
--
beg
;
if
(
beg
>=
1
&&
layout
.
charAt
(
beg
-
1
)
==
'-'
)
--
beg
;
...
@@ -1145,7 +1137,9 @@ class Attribute implements Comparable, Constants {
...
@@ -1145,7 +1137,9 @@ class Attribute implements Comparable, Constants {
int
end
=
beg
;
int
end
=
beg
;
int
limit
=
layout
.
length
();
int
limit
=
layout
.
length
();
if
(
end
<
limit
&&
layout
.
charAt
(
end
)
==
'-'
)
++
end
;
if
(
end
<
limit
&&
layout
.
charAt
(
end
)
==
'-'
)
++
end
;
while
(
end
<
limit
&&
isDigit
(
layout
.
charAt
(
end
)))
++
end
;
while
(
end
<
limit
&&
isDigit
(
layout
.
charAt
(
end
)))
{
++
end
;
}
if
(
beg
==
end
)
return
Integer
.
parseInt
(
"empty"
);
if
(
beg
==
end
)
return
Integer
.
parseInt
(
"empty"
);
return
Integer
.
parseInt
(
layout
.
substring
(
beg
,
end
));
return
Integer
.
parseInt
(
layout
.
substring
(
beg
,
end
));
}
}
...
...
src/share/classes/com/sun/java/util/jar/pack/ConstantPool.java
浏览文件 @
130dc864
/*
/*
* Copyright (c) 2001, 20
03
, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 20
10
, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
*
* This code is free software; you can redistribute it and/or modify it
* This code is free software; you can redistribute it and/or modify it
...
@@ -25,7 +25,6 @@
...
@@ -25,7 +25,6 @@
package
com.sun.java.util.jar.pack
;
package
com.sun.java.util.jar.pack
;
import
java.io.*
;
import
java.util.*
;
import
java.util.*
;
/**
/**
...
@@ -40,20 +39,13 @@ class ConstantPool implements Constants {
...
@@ -40,20 +39,13 @@ class ConstantPool implements Constants {
return
Utils
.
currentPropMap
().
getInteger
(
Utils
.
DEBUG_VERBOSE
);
return
Utils
.
currentPropMap
().
getInteger
(
Utils
.
DEBUG_VERBOSE
);
}
}
// Uniquification tables for factory methods:
private
static
final
HashMap
utf8Entries
=
new
HashMap
();
private
static
final
HashMap
classEntries
=
new
HashMap
();
private
static
final
HashMap
literalEntries
=
new
HashMap
();
private
static
final
HashMap
signatureEntries
=
new
HashMap
();
private
static
final
HashMap
descriptorEntries
=
new
HashMap
();
private
static
final
HashMap
memberEntries
=
new
HashMap
();
/** Factory for Utf8 string constants.
/** Factory for Utf8 string constants.
* Used for well-known strings like "SourceFile", "<init>", etc.
* Used for well-known strings like "SourceFile", "<init>", etc.
* Also used to back up more complex constant pool entries, like Class.
* Also used to back up more complex constant pool entries, like Class.
*/
*/
public
static
synchronized
Utf8Entry
getUtf8Entry
(
String
value
)
{
public
static
synchronized
Utf8Entry
getUtf8Entry
(
String
value
)
{
Utf8Entry
e
=
(
Utf8Entry
)
utf8Entries
.
get
(
value
);
Map
<
String
,
Utf8Entry
>
utf8Entries
=
Utils
.
getUtf8Entries
();
Utf8Entry
e
=
utf8Entries
.
get
(
value
);
if
(
e
==
null
)
{
if
(
e
==
null
)
{
e
=
new
Utf8Entry
(
value
);
e
=
new
Utf8Entry
(
value
);
utf8Entries
.
put
(
e
.
stringValue
(),
e
);
utf8Entries
.
put
(
e
.
stringValue
(),
e
);
...
@@ -62,9 +54,10 @@ class ConstantPool implements Constants {
...
@@ -62,9 +54,10 @@ class ConstantPool implements Constants {
}
}
/** Factory for Class constants. */
/** Factory for Class constants. */
public
static
synchronized
ClassEntry
getClassEntry
(
String
name
)
{
public
static
synchronized
ClassEntry
getClassEntry
(
String
name
)
{
ClassEntry
e
=
(
ClassEntry
)
classEntries
.
get
(
name
);
Map
<
String
,
ClassEntry
>
classEntries
=
Utils
.
getClassEntries
();
ClassEntry
e
=
classEntries
.
get
(
name
);
if
(
e
==
null
)
{
if
(
e
==
null
)
{
e
=
(
ClassEntry
)
new
ClassEntry
(
getUtf8Entry
(
name
));
e
=
new
ClassEntry
(
getUtf8Entry
(
name
));
assert
(
name
.
equals
(
e
.
stringValue
()));
assert
(
name
.
equals
(
e
.
stringValue
()));
classEntries
.
put
(
e
.
stringValue
(),
e
);
classEntries
.
put
(
e
.
stringValue
(),
e
);
}
}
...
@@ -72,7 +65,8 @@ class ConstantPool implements Constants {
...
@@ -72,7 +65,8 @@ class ConstantPool implements Constants {
}
}
/** Factory for literal constants (String, Integer, etc.). */
/** Factory for literal constants (String, Integer, etc.). */
public
static
synchronized
LiteralEntry
getLiteralEntry
(
Comparable
value
)
{
public
static
synchronized
LiteralEntry
getLiteralEntry
(
Comparable
value
)
{
LiteralEntry
e
=
(
LiteralEntry
)
literalEntries
.
get
(
value
);
Map
<
Object
,
LiteralEntry
>
literalEntries
=
Utils
.
getLiteralEntries
();
LiteralEntry
e
=
literalEntries
.
get
(
value
);
if
(
e
==
null
)
{
if
(
e
==
null
)
{
if
(
value
instanceof
String
)
if
(
value
instanceof
String
)
e
=
new
StringEntry
(
getUtf8Entry
((
String
)
value
));
e
=
new
StringEntry
(
getUtf8Entry
((
String
)
value
));
...
@@ -89,7 +83,8 @@ class ConstantPool implements Constants {
...
@@ -89,7 +83,8 @@ class ConstantPool implements Constants {
/** Factory for signature (type) constants. */
/** Factory for signature (type) constants. */
public
static
synchronized
SignatureEntry
getSignatureEntry
(
String
type
)
{
public
static
synchronized
SignatureEntry
getSignatureEntry
(
String
type
)
{
SignatureEntry
e
=
(
SignatureEntry
)
signatureEntries
.
get
(
type
);
Map
<
String
,
SignatureEntry
>
signatureEntries
=
Utils
.
getSignatureEntries
();
SignatureEntry
e
=
signatureEntries
.
get
(
type
);
if
(
e
==
null
)
{
if
(
e
==
null
)
{
e
=
new
SignatureEntry
(
type
);
e
=
new
SignatureEntry
(
type
);
assert
(
e
.
stringValue
().
equals
(
type
));
assert
(
e
.
stringValue
().
equals
(
type
));
...
@@ -104,8 +99,9 @@ class ConstantPool implements Constants {
...
@@ -104,8 +99,9 @@ class ConstantPool implements Constants {
/** Factory for descriptor (name-and-type) constants. */
/** Factory for descriptor (name-and-type) constants. */
public
static
synchronized
DescriptorEntry
getDescriptorEntry
(
Utf8Entry
nameRef
,
SignatureEntry
typeRef
)
{
public
static
synchronized
DescriptorEntry
getDescriptorEntry
(
Utf8Entry
nameRef
,
SignatureEntry
typeRef
)
{
Map
<
String
,
DescriptorEntry
>
descriptorEntries
=
Utils
.
getDescriptorEntries
();
String
key
=
DescriptorEntry
.
stringValueOf
(
nameRef
,
typeRef
);
String
key
=
DescriptorEntry
.
stringValueOf
(
nameRef
,
typeRef
);
DescriptorEntry
e
=
(
DescriptorEntry
)
descriptorEntries
.
get
(
key
);
DescriptorEntry
e
=
descriptorEntries
.
get
(
key
);
if
(
e
==
null
)
{
if
(
e
==
null
)
{
e
=
new
DescriptorEntry
(
nameRef
,
typeRef
);
e
=
new
DescriptorEntry
(
nameRef
,
typeRef
);
assert
(
e
.
stringValue
().
equals
(
key
))
assert
(
e
.
stringValue
().
equals
(
key
))
...
@@ -121,8 +117,9 @@ class ConstantPool implements Constants {
...
@@ -121,8 +117,9 @@ class ConstantPool implements Constants {
/** Factory for member reference constants. */
/** Factory for member reference constants. */
public
static
synchronized
MemberEntry
getMemberEntry
(
byte
tag
,
ClassEntry
classRef
,
DescriptorEntry
descRef
)
{
public
static
synchronized
MemberEntry
getMemberEntry
(
byte
tag
,
ClassEntry
classRef
,
DescriptorEntry
descRef
)
{
Map
<
String
,
MemberEntry
>
memberEntries
=
Utils
.
getMemberEntries
();
String
key
=
MemberEntry
.
stringValueOf
(
tag
,
classRef
,
descRef
);
String
key
=
MemberEntry
.
stringValueOf
(
tag
,
classRef
,
descRef
);
MemberEntry
e
=
(
MemberEntry
)
memberEntries
.
get
(
key
);
MemberEntry
e
=
memberEntries
.
get
(
key
);
if
(
e
==
null
)
{
if
(
e
==
null
)
{
e
=
new
MemberEntry
(
tag
,
classRef
,
descRef
);
e
=
new
MemberEntry
(
tag
,
classRef
,
descRef
);
assert
(
e
.
stringValue
().
equals
(
key
))
assert
(
e
.
stringValue
().
equals
(
key
))
...
@@ -489,8 +486,9 @@ class ConstantPool implements Constants {
...
@@ -489,8 +486,9 @@ class ConstantPool implements Constants {
String
[]
parts
=
structureSignature
(
value
);
String
[]
parts
=
structureSignature
(
value
);
formRef
=
getUtf8Entry
(
parts
[
0
]);
formRef
=
getUtf8Entry
(
parts
[
0
]);
classRefs
=
new
ClassEntry
[
parts
.
length
-
1
];
classRefs
=
new
ClassEntry
[
parts
.
length
-
1
];
for
(
int
i
=
1
;
i
<
parts
.
length
;
i
++)
for
(
int
i
=
1
;
i
<
parts
.
length
;
i
++)
{
classRefs
[
i
-
1
]
=
getClassEntry
(
parts
[
i
]);
classRefs
[
i
-
1
]
=
getClassEntry
(
parts
[
i
]);
}
hashCode
();
// force computation of valueHash
hashCode
();
// force computation of valueHash
}
}
protected
int
computeValueHash
()
{
protected
int
computeValueHash
()
{
...
@@ -527,8 +525,9 @@ class ConstantPool implements Constants {
...
@@ -527,8 +525,9 @@ class ConstantPool implements Constants {
String
stringValueOf
(
Utf8Entry
formRef
,
ClassEntry
[]
classRefs
)
{
String
stringValueOf
(
Utf8Entry
formRef
,
ClassEntry
[]
classRefs
)
{
String
[]
parts
=
new
String
[
1
+
classRefs
.
length
];
String
[]
parts
=
new
String
[
1
+
classRefs
.
length
];
parts
[
0
]
=
formRef
.
stringValue
();
parts
[
0
]
=
formRef
.
stringValue
();
for
(
int
i
=
1
;
i
<
parts
.
length
;
i
++)
for
(
int
i
=
1
;
i
<
parts
.
length
;
i
++)
{
parts
[
i
]
=
classRefs
[
i
-
1
].
stringValue
();
parts
[
i
]
=
classRefs
[
i
-
1
].
stringValue
();
}
return
flattenSignature
(
parts
).
intern
();
return
flattenSignature
(
parts
).
intern
();
}
}
...
@@ -543,19 +542,23 @@ class ConstantPool implements Constants {
...
@@ -543,19 +542,23 @@ class ConstantPool implements Constants {
int
size
=
0
;
int
size
=
0
;
for
(
int
i
=
min
;
i
<
max
;
i
++)
{
for
(
int
i
=
min
;
i
<
max
;
i
++)
{
switch
(
form
.
charAt
(
i
))
{
switch
(
form
.
charAt
(
i
))
{
case
'D'
:
case
'D'
:
case
'J'
:
case
'J'
:
if
(
countDoublesTwice
)
size
++;
if
(
countDoublesTwice
)
{
break
;
size
++;
case
'['
:
}
// Skip rest of array info.
break
;
while
(
form
.
charAt
(
i
)
==
'['
)
++
i
;
case
'['
:
break
;
// Skip rest of array info.
case
';'
:
while
(
form
.
charAt
(
i
)
==
'['
)
{
continue
;
++
i
;
default
:
}
assert
(
0
<=
JAVA_SIGNATURE_CHARS
.
indexOf
(
form
.
charAt
(
i
)));
break
;
break
;
case
';'
:
continue
;
default
:
assert
(
0
<=
JAVA_SIGNATURE_CHARS
.
indexOf
(
form
.
charAt
(
i
)));
break
;
}
}
size
++;
size
++;
}
}
...
@@ -586,8 +589,9 @@ class ConstantPool implements Constants {
...
@@ -586,8 +589,9 @@ class ConstantPool implements Constants {
s
=
"/"
+
formRef
.
stringValue
();
s
=
"/"
+
formRef
.
stringValue
();
}
}
int
i
;
int
i
;
while
((
i
=
s
.
indexOf
(
';'
))
>=
0
)
while
((
i
=
s
.
indexOf
(
';'
))
>=
0
)
{
s
=
s
.
substring
(
0
,
i
)
+
s
.
substring
(
i
+
1
);
s
=
s
.
substring
(
0
,
i
)
+
s
.
substring
(
i
+
1
);
}
return
s
;
return
s
;
}
}
}
}
...
@@ -732,11 +736,11 @@ class ConstantPool implements Constants {
...
@@ -732,11 +736,11 @@ class ConstantPool implements Constants {
clearIndex
();
clearIndex
();
this
.
cpMap
=
cpMap
;
this
.
cpMap
=
cpMap
;
}
}
protected
Index
(
String
debugName
,
Collection
cpMapList
)
{
protected
Index
(
String
debugName
,
Collection
<
Entry
>
cpMapList
)
{
this
(
debugName
);
this
(
debugName
);
setMap
(
cpMapList
);
setMap
(
cpMapList
);
}
}
protected
void
setMap
(
Collection
cpMapList
)
{
protected
void
setMap
(
Collection
<
Entry
>
cpMapList
)
{
cpMap
=
new
Entry
[
cpMapList
.
size
()];
cpMap
=
new
Entry
[
cpMapList
.
size
()];
cpMapList
.
toArray
(
cpMap
);
cpMapList
.
toArray
(
cpMap
);
setMap
(
cpMap
);
setMap
(
cpMap
);
...
@@ -756,11 +760,13 @@ class ConstantPool implements Constants {
...
@@ -756,11 +760,13 @@ class ConstantPool implements Constants {
//
//
// As a special hack, if flattenSigs, signatures are
// As a special hack, if flattenSigs, signatures are
// treated as equivalent entries of cpMap. This is wrong
// treated as equivalent entries of cpMap. This is wrong
// fro
n
a Collection point of view, because contains()
// fro
m
a Collection point of view, because contains()
// reports true for signatures, but the iterator()
// reports true for signatures, but the iterator()
// never produces them!
// never produces them!
private
int
findIndexOf
(
Entry
e
)
{
private
int
findIndexOf
(
Entry
e
)
{
if
(
indexKey
==
null
)
initializeIndex
();
if
(
indexKey
==
null
)
{
initializeIndex
();
}
int
probe
=
findIndexLocation
(
e
);
int
probe
=
findIndexLocation
(
e
);
if
(
indexKey
[
probe
]
!=
e
)
{
if
(
indexKey
[
probe
]
!=
e
)
{
if
(
flattenSigs
&&
e
.
tag
==
CONSTANT_Signature
)
{
if
(
flattenSigs
&&
e
.
tag
==
CONSTANT_Signature
)
{
...
@@ -832,7 +838,9 @@ class ConstantPool implements Constants {
...
@@ -832,7 +838,9 @@ class ConstantPool implements Constants {
System
.
out
.
println
(
"initialize Index "
+
debugName
+
" ["
+
size
()+
"]"
);
System
.
out
.
println
(
"initialize Index "
+
debugName
+
" ["
+
size
()+
"]"
);
int
hsize0
=
(
int
)((
cpMap
.
length
+
10
)
*
1.5
);
int
hsize0
=
(
int
)((
cpMap
.
length
+
10
)
*
1.5
);
int
hsize
=
1
;
int
hsize
=
1
;
while
(
hsize
<
hsize0
)
hsize
<<=
1
;
while
(
hsize
<
hsize0
)
{
hsize
<<=
1
;
}
indexKey
=
new
Entry
[
hsize
];
indexKey
=
new
Entry
[
hsize
];
indexValue
=
new
int
[
hsize
];
indexValue
=
new
int
[
hsize
];
for
(
int
i
=
0
;
i
<
cpMap
.
length
;
i
++)
{
for
(
int
i
=
0
;
i
<
cpMap
.
length
;
i
++)
{
...
@@ -855,7 +863,7 @@ class ConstantPool implements Constants {
...
@@ -855,7 +863,7 @@ class ConstantPool implements Constants {
return
toArray
(
new
Entry
[
size
()]);
return
toArray
(
new
Entry
[
size
()]);
}
}
public
Object
clone
()
{
public
Object
clone
()
{
return
new
Index
(
debugName
,
(
Entry
[])
cpMap
.
clone
());
return
new
Index
(
debugName
,
cpMap
.
clone
());
}
}
public
String
toString
()
{
public
String
toString
()
{
return
"Index "
+
debugName
+
" ["
+
size
()+
"]"
;
return
"Index "
+
debugName
+
" ["
+
size
()+
"]"
;
...
@@ -901,22 +909,24 @@ class ConstantPool implements Constants {
...
@@ -901,22 +909,24 @@ class ConstantPool implements Constants {
public
static
public
static
Index
[]
partition
(
Index
ix
,
int
[]
keys
)
{
Index
[]
partition
(
Index
ix
,
int
[]
keys
)
{
// %%% Should move this into class Index.
// %%% Should move this into class Index.
ArrayList
parts
=
new
ArrayList
();
ArrayList
<
List
<
Entry
>>
parts
=
new
ArrayList
<>
();
Entry
[]
cpMap
=
ix
.
cpMap
;
Entry
[]
cpMap
=
ix
.
cpMap
;
assert
(
keys
.
length
==
cpMap
.
length
);
assert
(
keys
.
length
==
cpMap
.
length
);
for
(
int
i
=
0
;
i
<
keys
.
length
;
i
++)
{
for
(
int
i
=
0
;
i
<
keys
.
length
;
i
++)
{
int
key
=
keys
[
i
];
int
key
=
keys
[
i
];
if
(
key
<
0
)
continue
;
if
(
key
<
0
)
continue
;
while
(
key
>=
parts
.
size
())
parts
.
add
(
null
);
while
(
key
>=
parts
.
size
())
{
ArrayList
part
=
(
ArrayList
)
parts
.
get
(
key
);
parts
.
add
(
null
);
}
List
<
Entry
>
part
=
parts
.
get
(
key
);
if
(
part
==
null
)
{
if
(
part
==
null
)
{
parts
.
set
(
key
,
part
=
new
ArrayList
());
parts
.
set
(
key
,
part
=
new
ArrayList
<>
());
}
}
part
.
add
(
cpMap
[
i
]);
part
.
add
(
cpMap
[
i
]);
}
}
Index
[]
indexes
=
new
Index
[
parts
.
size
()];
Index
[]
indexes
=
new
Index
[
parts
.
size
()];
for
(
int
key
=
0
;
key
<
indexes
.
length
;
key
++)
{
for
(
int
key
=
0
;
key
<
indexes
.
length
;
key
++)
{
ArrayList
part
=
(
ArrayList
)
parts
.
get
(
key
);
List
<
Entry
>
part
=
parts
.
get
(
key
);
if
(
part
==
null
)
continue
;
if
(
part
==
null
)
continue
;
indexes
[
key
]
=
new
Index
(
ix
.
debugName
+
"/part#"
+
key
,
part
);
indexes
[
key
]
=
new
Index
(
ix
.
debugName
+
"/part#"
+
key
,
part
);
assert
(
indexes
[
key
].
indexOf
(
part
.
get
(
0
))
==
0
);
assert
(
indexes
[
key
].
indexOf
(
part
.
get
(
0
))
==
0
);
...
@@ -1048,9 +1058,10 @@ class ConstantPool implements Constants {
...
@@ -1048,9 +1058,10 @@ class ConstantPool implements Constants {
whichClasses
[
i
]
=
whichClass
;
whichClasses
[
i
]
=
whichClass
;
}
}
perClassIndexes
=
partition
(
allMembers
,
whichClasses
);
perClassIndexes
=
partition
(
allMembers
,
whichClasses
);
for
(
int
i
=
0
;
i
<
perClassIndexes
.
length
;
i
++)
for
(
int
i
=
0
;
i
<
perClassIndexes
.
length
;
i
++)
{
assert
(
perClassIndexes
[
i
]==
null
assert
(
perClassIndexes
[
i
]
==
null
||
||
perClassIndexes
[
i
].
assertIsSorted
());
perClassIndexes
[
i
].
assertIsSorted
());
}
indexByTagAndClass
[
tag
]
=
perClassIndexes
;
indexByTagAndClass
[
tag
]
=
perClassIndexes
;
}
}
int
whichClass
=
allClasses
.
indexOf
(
classRef
);
int
whichClass
=
allClasses
.
indexOf
(
classRef
);
...
@@ -1113,7 +1124,7 @@ class ConstantPool implements Constants {
...
@@ -1113,7 +1124,7 @@ class ConstantPool implements Constants {
* Also, discard null from cpRefs.
* Also, discard null from cpRefs.
*/
*/
public
static
public
static
void
completeReferencesIn
(
Set
cpRefs
,
boolean
flattenSigs
)
{
void
completeReferencesIn
(
Set
<
Entry
>
cpRefs
,
boolean
flattenSigs
)
{
cpRefs
.
remove
(
null
);
cpRefs
.
remove
(
null
);
for
(
ListIterator
work
=
for
(
ListIterator
work
=
new
ArrayList
(
cpRefs
).
listIterator
(
cpRefs
.
size
());
new
ArrayList
(
cpRefs
).
listIterator
(
cpRefs
.
size
());
...
...
src/share/classes/com/sun/java/util/jar/pack/Driver.java
浏览文件 @
130dc864
/*
/*
* Copyright (c) 2003, 20
05
, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 20
10
, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
*
* This code is free software; you can redistribute it and/or modify it
* This code is free software; you can redistribute it and/or modify it
...
@@ -25,7 +25,6 @@
...
@@ -25,7 +25,6 @@
package
com.sun.java.util.jar.pack
;
package
com.sun.java.util.jar.pack
;
import
java.lang.Error
;
import
java.io.*
;
import
java.io.*
;
import
java.text.MessageFormat
;
import
java.text.MessageFormat
;
import
java.util.*
;
import
java.util.*
;
...
@@ -35,10 +34,11 @@ import java.util.zip.*;
...
@@ -35,10 +34,11 @@ import java.util.zip.*;
/** Command line interface for Pack200.
/** Command line interface for Pack200.
*/
*/
class
Driver
{
class
Driver
{
private
static
final
ResourceBundle
RESOURCE
=
ResourceBundle
.
getBundle
(
"com.sun.java.util.jar.pack.DriverResource"
);
private
static
final
ResourceBundle
RESOURCE
=
ResourceBundle
.
getBundle
(
"com.sun.java.util.jar.pack.DriverResource"
);
public
static
void
main
(
String
[]
ava
)
throws
IOException
{
public
static
void
main
(
String
[]
ava
)
throws
IOException
{
ArrayList
<
String
>
av
=
new
ArrayList
<
String
>(
Arrays
.
asList
(
ava
));
ArrayList
<
String
>
av
=
new
ArrayList
<>(
Arrays
.
asList
(
ava
));
boolean
doPack
=
true
;
boolean
doPack
=
true
;
boolean
doUnpack
=
false
;
boolean
doUnpack
=
false
;
...
@@ -61,7 +61,7 @@ class Driver {
...
@@ -61,7 +61,7 @@ class Driver {
}
}
// Collect engine properties here:
// Collect engine properties here:
HashMap
<
String
,
String
>
engProps
=
new
HashMap
<
String
,
String
>();
HashMap
<
String
,
String
>
engProps
=
new
HashMap
<>();
engProps
.
put
(
verboseProp
,
System
.
getProperty
(
verboseProp
));
engProps
.
put
(
verboseProp
,
System
.
getProperty
(
verboseProp
));
String
optionMap
;
String
optionMap
;
...
@@ -75,7 +75,7 @@ class Driver {
...
@@ -75,7 +75,7 @@ class Driver {
}
}
// Collect argument properties here:
// Collect argument properties here:
HashMap
<
String
,
String
>
avProps
=
new
HashMap
<
String
,
String
>();
HashMap
<
String
,
String
>
avProps
=
new
HashMap
<>();
try
{
try
{
for
(;;)
{
for
(;;)
{
String
state
=
parseCommandOptions
(
av
,
optionMap
,
avProps
);
String
state
=
parseCommandOptions
(
av
,
optionMap
,
avProps
);
...
@@ -133,8 +133,9 @@ class Driver {
...
@@ -133,8 +133,9 @@ class Driver {
if
(
engProps
.
get
(
verboseProp
)
!=
null
)
if
(
engProps
.
get
(
verboseProp
)
!=
null
)
fileProps
.
list
(
System
.
out
);
fileProps
.
list
(
System
.
out
);
propIn
.
close
();
propIn
.
close
();
for
(
Map
.
Entry
<
Object
,
Object
>
me
:
fileProps
.
entrySet
())
for
(
Map
.
Entry
<
Object
,
Object
>
me
:
fileProps
.
entrySet
())
{
engProps
.
put
((
String
)
me
.
getKey
(),
(
String
)
me
.
getValue
());
engProps
.
put
((
String
)
me
.
getKey
(),
(
String
)
me
.
getValue
());
}
}
else
if
(
state
==
"--version"
)
{
}
else
if
(
state
==
"--version"
)
{
System
.
out
.
println
(
MessageFormat
.
format
(
RESOURCE
.
getString
(
DriverResource
.
VERSION
),
Driver
.
class
.
getName
(),
"1.31, 07/05/05"
));
System
.
out
.
println
(
MessageFormat
.
format
(
RESOURCE
.
getString
(
DriverResource
.
VERSION
),
Driver
.
class
.
getName
(),
"1.31, 07/05/05"
));
return
;
return
;
...
@@ -493,7 +494,7 @@ class Driver {
...
@@ -493,7 +494,7 @@ class Driver {
String
resultString
=
null
;
String
resultString
=
null
;
// Convert options string into optLines dictionary.
// Convert options string into optLines dictionary.
TreeMap
<
String
,
String
[]>
optmap
=
new
TreeMap
<
String
,
String
[]
>();
TreeMap
<
String
,
String
[]>
optmap
=
new
TreeMap
<>();
loadOptmap:
loadOptmap:
for
(
String
optline
:
options
.
split
(
"\n"
))
{
for
(
String
optline
:
options
.
split
(
"\n"
))
{
String
[]
words
=
optline
.
split
(
"\\p{Space}+"
);
String
[]
words
=
optline
.
split
(
"\\p{Space}+"
);
...
@@ -687,7 +688,9 @@ class Driver {
...
@@ -687,7 +688,9 @@ class Driver {
// Report number of arguments consumed.
// Report number of arguments consumed.
args
.
subList
(
0
,
argp
.
nextIndex
()).
clear
();
args
.
subList
(
0
,
argp
.
nextIndex
()).
clear
();
// Report any unconsumed partial argument.
// Report any unconsumed partial argument.
while
(
pbp
.
hasPrevious
())
args
.
add
(
0
,
pbp
.
previous
());
while
(
pbp
.
hasPrevious
())
{
args
.
add
(
0
,
pbp
.
previous
());
}
//System.out.println(args+" // "+properties+" -> "+resultString);
//System.out.println(args+" // "+properties+" -> "+resultString);
return
resultString
;
return
resultString
;
}
}
...
...
src/share/classes/com/sun/java/util/jar/pack/NativeUnpack.java
浏览文件 @
130dc864
/*
/*
* Copyright (c) 2003, 20
04
, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 20
10
, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
*
* This code is free software; you can redistribute it and/or modify it
* This code is free software; you can redistribute it and/or modify it
...
@@ -28,13 +28,8 @@ package com.sun.java.util.jar.pack;
...
@@ -28,13 +28,8 @@ package com.sun.java.util.jar.pack;
import
java.nio.*
;
import
java.nio.*
;
import
java.io.*
;
import
java.io.*
;
import
java.nio.channels.*
;
import
java.util.Date
;
import
java.util.jar.*
;
import
java.util.jar.*
;
import
java.util.zip.*
;
import
java.util.zip.*
;
import
java.util.*
;
//import com.sun.java.util.jar.pack.Pack200;
class
NativeUnpack
{
class
NativeUnpack
{
// Pointer to the native unpacker obj
// Pointer to the native unpacker obj
...
@@ -91,13 +86,13 @@ class NativeUnpack {
...
@@ -91,13 +86,13 @@ class NativeUnpack {
NativeUnpack
(
UnpackerImpl
p200
)
{
NativeUnpack
(
UnpackerImpl
p200
)
{
super
();
super
();
_p200
=
p200
;
_p200
=
p200
;
_props
=
p200
.
_
props
;
_props
=
p200
.
props
;
p200
.
_nunp
=
this
;
p200
.
_nunp
=
this
;
}
}
// for JNI callbacks
// for JNI callbacks
static
private
Object
currentInstance
()
{
static
private
Object
currentInstance
()
{
UnpackerImpl
p200
=
(
UnpackerImpl
)
Utils
.
currentInstance
.
get
();
UnpackerImpl
p200
=
(
UnpackerImpl
)
Utils
.
getTLGlobals
();
return
(
p200
==
null
)?
null
:
p200
.
_nunp
;
return
(
p200
==
null
)?
null
:
p200
.
_nunp
;
}
}
...
@@ -216,10 +211,10 @@ class NativeUnpack {
...
@@ -216,10 +211,10 @@ class NativeUnpack {
++
_fileCount
;
++
_fileCount
;
updateProgress
();
updateProgress
();
}
}
presetInput
=
getUnusedInput
();
long
consumed
=
finish
();
long
consumed
=
finish
();
if
(
_verbose
>
0
)
if
(
_verbose
>
0
)
Utils
.
log
.
info
(
"bytes consumed = "
+
consumed
);
Utils
.
log
.
info
(
"bytes consumed = "
+
consumed
);
presetInput
=
getUnusedInput
();
if
(
presetInput
==
null
&&
if
(
presetInput
==
null
&&
!
Utils
.
isPackMagic
(
Utils
.
readMagic
(
in
)))
{
!
Utils
.
isPackMagic
(
Utils
.
readMagic
(
in
)))
{
break
;
break
;
...
...
src/share/classes/com/sun/java/util/jar/pack/Package.java
浏览文件 @
130dc864
...
@@ -25,9 +25,9 @@
...
@@ -25,9 +25,9 @@
package
com.sun.java.util.jar.pack
;
package
com.sun.java.util.jar.pack
;
import
com.sun.java.util.jar.pack.Attribute.Layout
;
import
java.lang.reflect.Modifier
;
import
java.lang.reflect.Modifier
;
import
java.util.*
;
import
java.util.*
;
import
java.util.zip.*
;
import
java.util.jar.*
;
import
java.util.jar.*
;
import
java.io.*
;
import
java.io.*
;
import
com.sun.java.util.jar.pack.ConstantPool.*
;
import
com.sun.java.util.jar.pack.ConstantPool.*
;
...
@@ -77,10 +77,11 @@ class Package implements Constants {
...
@@ -77,10 +77,11 @@ class Package implements Constants {
cp
=
new
ConstantPool
.
IndexGroup
();
cp
=
new
ConstantPool
.
IndexGroup
();
classes
.
clear
();
classes
.
clear
();
files
.
clear
();
files
.
clear
();
BandStructure
.
nextSeqForDebug
=
0
;
}
}
int
getPackageVersion
()
{
int
getPackageVersion
()
{
return
(
package_majver
<<
16
)
+
(
int
)
package_minver
;
return
(
package_majver
<<
16
)
+
package_minver
;
}
}
// Special empty versions of Code and InnerClasses, used for markers.
// Special empty versions of Code and InnerClasses, used for markers.
...
@@ -89,7 +90,7 @@ class Package implements Constants {
...
@@ -89,7 +90,7 @@ class Package implements Constants {
public
static
final
Attribute
.
Layout
attrSourceFileSpecial
;
public
static
final
Attribute
.
Layout
attrSourceFileSpecial
;
public
static
final
Map
attrDefs
;
public
static
final
Map
attrDefs
;
static
{
static
{
HashMap
ad
=
new
HashMap
(
2
);
HashMap
<
Layout
,
Attribute
>
ad
=
new
HashMap
<>(
3
);
attrCodeEmpty
=
Attribute
.
define
(
ad
,
ATTR_CONTEXT_METHOD
,
attrCodeEmpty
=
Attribute
.
define
(
ad
,
ATTR_CONTEXT_METHOD
,
"Code"
,
""
).
layout
();
"Code"
,
""
).
layout
();
attrInnerClassesEmpty
=
Attribute
.
define
(
ad
,
ATTR_CONTEXT_CLASS
,
attrInnerClassesEmpty
=
Attribute
.
define
(
ad
,
ATTR_CONTEXT_CLASS
,
...
@@ -159,9 +160,9 @@ class Package implements Constants {
...
@@ -159,9 +160,9 @@ class Package implements Constants {
}
}
}
}
ArrayList
classes
=
new
ArrayList
();
ArrayList
<
Package
.
Class
>
classes
=
new
ArrayList
<>
();
public
List
getClasses
()
{
public
List
<
Package
.
Class
>
getClasses
()
{
return
classes
;
return
classes
;
}
}
...
@@ -186,11 +187,11 @@ class Package implements Constants {
...
@@ -186,11 +187,11 @@ class Package implements Constants {
ClassEntry
[]
interfaces
;
ClassEntry
[]
interfaces
;
// Class parts
// Class parts
ArrayList
fields
;
ArrayList
<
Field
>
fields
;
ArrayList
methods
;
ArrayList
<
Method
>
methods
;
//ArrayList attributes; // in Attribute.Holder.this.attributes
//ArrayList attributes; // in Attribute.Holder.this.attributes
// Note that InnerClasses may be collected at the package level.
// Note that InnerClasses may be collected at the package level.
ArrayList
innerClasses
;
ArrayList
<
InnerClass
>
innerClasses
;
Class
(
int
flags
,
ClassEntry
thisClass
,
ClassEntry
superClass
,
ClassEntry
[]
interfaces
)
{
Class
(
int
flags
,
ClassEntry
thisClass
,
ClassEntry
superClass
,
ClassEntry
[]
interfaces
)
{
this
.
magic
=
JAVA_MAGIC
;
this
.
magic
=
JAVA_MAGIC
;
...
@@ -270,7 +271,7 @@ class Package implements Constants {
...
@@ -270,7 +271,7 @@ class Package implements Constants {
if
(
a
!=
olda
)
{
if
(
a
!=
olda
)
{
if
(
verbose
>
2
)
if
(
verbose
>
2
)
Utils
.
log
.
fine
(
"recoding obvious SourceFile="
+
obvious
);
Utils
.
log
.
fine
(
"recoding obvious SourceFile="
+
obvious
);
List
newAttrs
=
new
ArrayList
(
getAttributes
());
List
<
Attribute
>
newAttrs
=
new
ArrayList
<>
(
getAttributes
());
int
where
=
newAttrs
.
indexOf
(
olda
);
int
where
=
newAttrs
.
indexOf
(
olda
);
newAttrs
.
set
(
where
,
a
);
newAttrs
.
set
(
where
,
a
);
setAttributes
(
newAttrs
);
setAttributes
(
newAttrs
);
...
@@ -295,12 +296,12 @@ class Package implements Constants {
...
@@ -295,12 +296,12 @@ class Package implements Constants {
boolean
hasInnerClasses
()
{
boolean
hasInnerClasses
()
{
return
innerClasses
!=
null
;
return
innerClasses
!=
null
;
}
}
List
getInnerClasses
()
{
List
<
InnerClass
>
getInnerClasses
()
{
return
innerClasses
;
return
innerClasses
;
}
}
public
void
setInnerClasses
(
Collection
ics
)
{
public
void
setInnerClasses
(
Collection
<
InnerClass
>
ics
)
{
innerClasses
=
(
ics
==
null
)
?
null
:
new
ArrayList
(
ics
);
innerClasses
=
(
ics
==
null
)
?
null
:
new
ArrayList
<
InnerClass
>
(
ics
);
// Edit the attribute list, if necessary.
// Edit the attribute list, if necessary.
Attribute
a
=
getAttribute
(
attrInnerClassesEmpty
);
Attribute
a
=
getAttribute
(
attrInnerClassesEmpty
);
if
(
innerClasses
!=
null
&&
a
==
null
)
if
(
innerClasses
!=
null
&&
a
==
null
)
...
@@ -318,19 +319,18 @@ class Package implements Constants {
...
@@ -318,19 +319,18 @@ class Package implements Constants {
* The order of the resulting list is consistent
* The order of the resulting list is consistent
* with that of Package.this.allInnerClasses.
* with that of Package.this.allInnerClasses.
*/
*/
public
List
computeGloballyImpliedICs
()
{
public
List
<
InnerClass
>
computeGloballyImpliedICs
()
{
HashSet
cpRefs
=
new
HashSet
();
HashSet
<
Entry
>
cpRefs
=
new
HashSet
<>
();
{
// This block temporarily displaces this.innerClasses.
{
// This block temporarily displaces this.innerClasses.
ArrayList
innerClassesSaved
=
innerClasses
;
ArrayList
<
InnerClass
>
innerClassesSaved
=
innerClasses
;
innerClasses
=
null
;
// ignore for the moment
innerClasses
=
null
;
// ignore for the moment
visitRefs
(
VRM_CLASSIC
,
cpRefs
);
visitRefs
(
VRM_CLASSIC
,
cpRefs
);
innerClasses
=
innerClassesSaved
;
innerClasses
=
innerClassesSaved
;
}
}
ConstantPool
.
completeReferencesIn
(
cpRefs
,
true
);
ConstantPool
.
completeReferencesIn
(
cpRefs
,
true
);
HashSet
icRefs
=
new
HashSet
();
HashSet
<
Entry
>
icRefs
=
new
HashSet
<>();
for
(
Iterator
i
=
cpRefs
.
iterator
();
i
.
hasNext
();
)
{
for
(
Entry
e
:
cpRefs
)
{
Entry
e
=
(
Entry
)
i
.
next
();
// Restrict cpRefs to InnerClasses entries only.
// Restrict cpRefs to InnerClasses entries only.
if
(!(
e
instanceof
ClassEntry
))
continue
;
if
(!(
e
instanceof
ClassEntry
))
continue
;
// For every IC reference, add its outers also.
// For every IC reference, add its outers also.
...
@@ -345,9 +345,8 @@ class Package implements Constants {
...
@@ -345,9 +345,8 @@ class Package implements Constants {
// This loop is structured this way so as to accumulate
// This loop is structured this way so as to accumulate
// entries into impliedICs in an order which reflects
// entries into impliedICs in an order which reflects
// the order of allInnerClasses.
// the order of allInnerClasses.
ArrayList
impliedICs
=
new
ArrayList
();
ArrayList
<
InnerClass
>
impliedICs
=
new
ArrayList
<>();
for
(
Iterator
i
=
allInnerClasses
.
iterator
();
i
.
hasNext
();
)
{
for
(
InnerClass
ic
:
allInnerClasses
)
{
InnerClass
ic
=
(
InnerClass
)
i
.
next
();
// This one is locally relevant if it describes
// This one is locally relevant if it describes
// a member of the current class, or if the current
// a member of the current class, or if the current
// class uses it somehow. In the particular case
// class uses it somehow. In the particular case
...
@@ -366,10 +365,11 @@ class Package implements Constants {
...
@@ -366,10 +365,11 @@ class Package implements Constants {
// Helper for both minimizing and expanding.
// Helper for both minimizing and expanding.
// Computes a symmetric difference.
// Computes a symmetric difference.
private
List
computeICdiff
()
{
private
List
<
InnerClass
>
computeICdiff
()
{
List
impliedICs
=
computeGloballyImpliedICs
();
List
<
InnerClass
>
impliedICs
=
computeGloballyImpliedICs
();
List
actualICs
=
getInnerClasses
();
List
<
InnerClass
>
actualICs
=
getInnerClasses
();
if
(
actualICs
==
null
)
actualICs
=
Collections
.
EMPTY_LIST
;
if
(
actualICs
==
null
)
actualICs
=
Collections
.
EMPTY_LIST
;
// Symmetric difference is calculated from I, A like this:
// Symmetric difference is calculated from I, A like this:
// diff = (I+A) - (I*A)
// diff = (I+A) - (I*A)
...
@@ -388,8 +388,8 @@ class Package implements Constants {
...
@@ -388,8 +388,8 @@ class Package implements Constants {
// Diff is A since I is empty.
// Diff is A since I is empty.
}
}
// (I*A) is non-trivial
// (I*A) is non-trivial
HashSet
center
=
new
HashSet
(
actualICs
);
HashSet
<
InnerClass
>
center
=
new
HashSet
<>
(
actualICs
);
center
.
retainAll
(
new
HashSet
(
impliedICs
));
center
.
retainAll
(
new
HashSet
<>
(
impliedICs
));
impliedICs
.
addAll
(
actualICs
);
impliedICs
.
addAll
(
actualICs
);
impliedICs
.
removeAll
(
center
);
impliedICs
.
removeAll
(
center
);
// Diff is now I^A = (I+A)-(I*A).
// Diff is now I^A = (I+A)-(I*A).
...
@@ -407,9 +407,9 @@ class Package implements Constants {
...
@@ -407,9 +407,9 @@ class Package implements Constants {
* to use the globally implied ICs changed.
* to use the globally implied ICs changed.
*/
*/
void
minimizeLocalICs
()
{
void
minimizeLocalICs
()
{
List
diff
=
computeICdiff
();
List
<
InnerClass
>
diff
=
computeICdiff
();
List
actualICs
=
innerClasses
;
List
<
InnerClass
>
actualICs
=
innerClasses
;
List
localICs
;
// will be the diff, modulo edge cases
List
<
InnerClass
>
localICs
;
// will be the diff, modulo edge cases
if
(
diff
.
isEmpty
())
{
if
(
diff
.
isEmpty
())
{
// No diff, so transmit no attribute.
// No diff, so transmit no attribute.
localICs
=
null
;
localICs
=
null
;
...
@@ -439,12 +439,12 @@ class Package implements Constants {
...
@@ -439,12 +439,12 @@ class Package implements Constants {
* Otherwise, return positive if any IC tuples were added.
* Otherwise, return positive if any IC tuples were added.
*/
*/
int
expandLocalICs
()
{
int
expandLocalICs
()
{
List
localICs
=
innerClasses
;
List
<
InnerClass
>
localICs
=
innerClasses
;
List
actualICs
;
List
<
InnerClass
>
actualICs
;
int
changed
;
int
changed
;
if
(
localICs
==
null
)
{
if
(
localICs
==
null
)
{
// Diff was empty. (Common case.)
// Diff was empty. (Common case.)
List
impliedICs
=
computeGloballyImpliedICs
();
List
<
InnerClass
>
impliedICs
=
computeGloballyImpliedICs
();
if
(
impliedICs
.
isEmpty
())
{
if
(
impliedICs
.
isEmpty
())
{
actualICs
=
null
;
actualICs
=
null
;
changed
=
0
;
changed
=
0
;
...
@@ -490,7 +490,7 @@ class Package implements Constants {
...
@@ -490,7 +490,7 @@ class Package implements Constants {
protected
Entry
[]
getCPMap
()
{
protected
Entry
[]
getCPMap
()
{
return
cpMap
;
return
cpMap
;
}
}
protected
void
visitRefs
(
int
mode
,
Collection
refs
)
{
protected
void
visitRefs
(
int
mode
,
Collection
<
Entry
>
refs
)
{
if
(
verbose
>
2
)
Utils
.
log
.
fine
(
"visitRefs "
+
this
);
if
(
verbose
>
2
)
Utils
.
log
.
fine
(
"visitRefs "
+
this
);
// Careful: The descriptor is used by the package,
// Careful: The descriptor is used by the package,
// but the classfile breaks it into component refs.
// but the classfile breaks it into component refs.
...
@@ -518,7 +518,7 @@ class Package implements Constants {
...
@@ -518,7 +518,7 @@ class Package implements Constants {
super
(
flags
,
descriptor
);
super
(
flags
,
descriptor
);
assert
(!
descriptor
.
isMethod
());
assert
(!
descriptor
.
isMethod
());
if
(
fields
==
null
)
if
(
fields
==
null
)
fields
=
new
ArrayList
();
fields
=
new
ArrayList
<>
();
boolean
added
=
fields
.
add
(
this
);
boolean
added
=
fields
.
add
(
this
);
assert
(
added
);
assert
(
added
);
order
=
fields
.
size
();
order
=
fields
.
size
();
...
@@ -543,7 +543,7 @@ class Package implements Constants {
...
@@ -543,7 +543,7 @@ class Package implements Constants {
super
(
flags
,
descriptor
);
super
(
flags
,
descriptor
);
assert
(
descriptor
.
isMethod
());
assert
(
descriptor
.
isMethod
());
if
(
methods
==
null
)
if
(
methods
==
null
)
methods
=
new
ArrayList
();
methods
=
new
ArrayList
<>
();
boolean
added
=
methods
.
add
(
this
);
boolean
added
=
methods
.
add
(
this
);
assert
(
added
);
assert
(
added
);
}
}
...
@@ -573,7 +573,7 @@ class Package implements Constants {
...
@@ -573,7 +573,7 @@ class Package implements Constants {
code
.
strip
(
attrName
);
code
.
strip
(
attrName
);
super
.
strip
(
attrName
);
super
.
strip
(
attrName
);
}
}
protected
void
visitRefs
(
int
mode
,
Collection
refs
)
{
protected
void
visitRefs
(
int
mode
,
Collection
<
Entry
>
refs
)
{
super
.
visitRefs
(
mode
,
refs
);
super
.
visitRefs
(
mode
,
refs
);
if
(
code
!=
null
)
{
if
(
code
!=
null
)
{
if
(
mode
==
VRM_CLASSIC
)
{
if
(
mode
==
VRM_CLASSIC
)
{
...
@@ -614,7 +614,7 @@ class Package implements Constants {
...
@@ -614,7 +614,7 @@ class Package implements Constants {
super
.
strip
(
attrName
);
super
.
strip
(
attrName
);
}
}
protected
void
visitRefs
(
int
mode
,
Collection
refs
)
{
protected
void
visitRefs
(
int
mode
,
Collection
<
Entry
>
refs
)
{
if
(
verbose
>
2
)
Utils
.
log
.
fine
(
"visitRefs "
+
this
);
if
(
verbose
>
2
)
Utils
.
log
.
fine
(
"visitRefs "
+
this
);
refs
.
add
(
thisClass
);
refs
.
add
(
thisClass
);
refs
.
add
(
superClass
);
refs
.
add
(
superClass
);
...
@@ -641,7 +641,7 @@ class Package implements Constants {
...
@@ -641,7 +641,7 @@ class Package implements Constants {
super
.
visitRefs
(
mode
,
refs
);
super
.
visitRefs
(
mode
,
refs
);
}
}
protected
void
visitInnerClassRefs
(
int
mode
,
Collection
refs
)
{
protected
void
visitInnerClassRefs
(
int
mode
,
Collection
<
Entry
>
refs
)
{
Package
.
visitInnerClassRefs
(
innerClasses
,
mode
,
refs
);
Package
.
visitInnerClassRefs
(
innerClasses
,
mode
,
refs
);
}
}
...
@@ -713,16 +713,15 @@ class Package implements Constants {
...
@@ -713,16 +713,15 @@ class Package implements Constants {
}
}
// What non-class files are in this unit?
// What non-class files are in this unit?
ArrayList
files
=
new
ArrayList
();
ArrayList
<
File
>
files
=
new
ArrayList
<>
();
public
List
getFiles
()
{
public
List
<
File
>
getFiles
()
{
return
files
;
return
files
;
}
}
public
List
getClassStubs
()
{
public
List
<
File
>
getClassStubs
()
{
ArrayList
classStubs
=
new
ArrayList
(
classes
.
size
());
ArrayList
<
File
>
classStubs
=
new
ArrayList
<>(
classes
.
size
());
for
(
Iterator
i
=
classes
.
iterator
();
i
.
hasNext
();
)
{
for
(
Class
cls
:
classes
)
{
Class
cls
=
(
Class
)
i
.
next
();
assert
(
cls
.
file
.
isClassStub
());
assert
(
cls
.
file
.
isClassStub
());
classStubs
.
add
(
cls
.
file
);
classStubs
.
add
(
cls
.
file
);
}
}
...
@@ -840,7 +839,7 @@ class Package implements Constants {
...
@@ -840,7 +839,7 @@ class Package implements Constants {
public
InputStream
getInputStream
()
{
public
InputStream
getInputStream
()
{
InputStream
in
=
new
ByteArrayInputStream
(
append
.
toByteArray
());
InputStream
in
=
new
ByteArrayInputStream
(
append
.
toByteArray
());
if
(
prepend
.
size
()
==
0
)
return
in
;
if
(
prepend
.
size
()
==
0
)
return
in
;
ArrayList
isa
=
new
ArrayList
(
prepend
.
size
()+
1
);
ArrayList
<
InputStream
>
isa
=
new
ArrayList
<>
(
prepend
.
size
()+
1
);
for
(
Iterator
i
=
prepend
.
iterator
();
i
.
hasNext
();
)
{
for
(
Iterator
i
=
prepend
.
iterator
();
i
.
hasNext
();
)
{
byte
[]
bytes
=
(
byte
[])
i
.
next
();
byte
[]
bytes
=
(
byte
[])
i
.
next
();
isa
.
add
(
new
ByteArrayInputStream
(
bytes
));
isa
.
add
(
new
ByteArrayInputStream
(
bytes
));
...
@@ -849,7 +848,7 @@ class Package implements Constants {
...
@@ -849,7 +848,7 @@ class Package implements Constants {
return
new
SequenceInputStream
(
Collections
.
enumeration
(
isa
));
return
new
SequenceInputStream
(
Collections
.
enumeration
(
isa
));
}
}
protected
void
visitRefs
(
int
mode
,
Collection
refs
)
{
protected
void
visitRefs
(
int
mode
,
Collection
<
Entry
>
refs
)
{
assert
(
name
!=
null
);
assert
(
name
!=
null
);
refs
.
add
(
name
);
refs
.
add
(
name
);
}
}
...
@@ -877,8 +876,8 @@ class Package implements Constants {
...
@@ -877,8 +876,8 @@ class Package implements Constants {
}
}
// Is there a globally declared table of inner classes?
// Is there a globally declared table of inner classes?
ArrayList
allInnerClasses
=
new
ArrayList
();
ArrayList
<
InnerClass
>
allInnerClasses
=
new
ArrayList
<>
();
HashMap
allInnerClassesByThis
;
HashMap
<
ClassEntry
,
InnerClass
>
allInnerClassesByThis
;
public
public
List
getAllInnerClasses
()
{
List
getAllInnerClasses
()
{
...
@@ -886,15 +885,14 @@ class Package implements Constants {
...
@@ -886,15 +885,14 @@ class Package implements Constants {
}
}
public
public
void
setAllInnerClasses
(
Collection
ics
)
{
void
setAllInnerClasses
(
Collection
<
InnerClass
>
ics
)
{
assert
(
ics
!=
allInnerClasses
);
assert
(
ics
!=
allInnerClasses
);
allInnerClasses
.
clear
();
allInnerClasses
.
clear
();
allInnerClasses
.
addAll
(
ics
);
allInnerClasses
.
addAll
(
ics
);
// Make an index:
// Make an index:
allInnerClassesByThis
=
new
HashMap
(
allInnerClasses
.
size
());
allInnerClassesByThis
=
new
HashMap
<>(
allInnerClasses
.
size
());
for
(
Iterator
i
=
allInnerClasses
.
iterator
();
i
.
hasNext
();
)
{
for
(
InnerClass
ic
:
allInnerClasses
)
{
InnerClass
ic
=
(
InnerClass
)
i
.
next
();
Object
pic
=
allInnerClassesByThis
.
put
(
ic
.
thisClass
,
ic
);
Object
pic
=
allInnerClassesByThis
.
put
(
ic
.
thisClass
,
ic
);
assert
(
pic
==
null
);
// caller must ensure key uniqueness!
assert
(
pic
==
null
);
// caller must ensure key uniqueness!
}
}
...
@@ -904,7 +902,7 @@ class Package implements Constants {
...
@@ -904,7 +902,7 @@ class Package implements Constants {
public
public
InnerClass
getGlobalInnerClass
(
Entry
thisClass
)
{
InnerClass
getGlobalInnerClass
(
Entry
thisClass
)
{
assert
(
thisClass
instanceof
ClassEntry
);
assert
(
thisClass
instanceof
ClassEntry
);
return
(
InnerClass
)
allInnerClassesByThis
.
get
(
thisClass
);
return
allInnerClassesByThis
.
get
(
thisClass
);
}
}
static
static
...
@@ -963,7 +961,7 @@ class Package implements Constants {
...
@@ -963,7 +961,7 @@ class Package implements Constants {
return
this
.
thisClass
.
compareTo
(
that
.
thisClass
);
return
this
.
thisClass
.
compareTo
(
that
.
thisClass
);
}
}
protected
void
visitRefs
(
int
mode
,
Collection
refs
)
{
protected
void
visitRefs
(
int
mode
,
Collection
<
Entry
>
refs
)
{
refs
.
add
(
thisClass
);
refs
.
add
(
thisClass
);
if
(
mode
==
VRM_CLASSIC
||
!
predictable
)
{
if
(
mode
==
VRM_CLASSIC
||
!
predictable
)
{
// If the name can be demangled, the package omits
// If the name can be demangled, the package omits
...
@@ -980,7 +978,7 @@ class Package implements Constants {
...
@@ -980,7 +978,7 @@ class Package implements Constants {
// Helper for building InnerClasses attributes.
// Helper for building InnerClasses attributes.
static
private
static
private
void
visitInnerClassRefs
(
Collection
innerClasses
,
int
mode
,
Collection
refs
)
{
void
visitInnerClassRefs
(
Collection
innerClasses
,
int
mode
,
Collection
<
Entry
>
refs
)
{
if
(
innerClasses
==
null
)
{
if
(
innerClasses
==
null
)
{
return
;
// no attribute; nothing to do
return
;
// no attribute; nothing to do
}
}
...
@@ -1165,9 +1163,8 @@ class Package implements Constants {
...
@@ -1165,9 +1163,8 @@ class Package implements Constants {
}
}
}
}
protected
void
visitRefs
(
int
mode
,
Collection
refs
)
{
protected
void
visitRefs
(
int
mode
,
Collection
<
Entry
>
refs
)
{
for
(
Iterator
i
=
classes
.
iterator
();
i
.
hasNext
();
)
{
for
(
Class
c
:
classes
)
{
Class
c
=
(
Class
)
i
.
next
();
c
.
visitRefs
(
mode
,
refs
);
c
.
visitRefs
(
mode
,
refs
);
}
}
if
(
mode
!=
VRM_CLASSIC
)
{
if
(
mode
!=
VRM_CLASSIC
)
{
...
@@ -1259,7 +1256,7 @@ class Package implements Constants {
...
@@ -1259,7 +1256,7 @@ class Package implements Constants {
}
}
// Use this before writing the package file.
// Use this before writing the package file.
void
buildGlobalConstantPool
(
Set
requiredEntries
)
{
void
buildGlobalConstantPool
(
Set
<
Entry
>
requiredEntries
)
{
if
(
verbose
>
1
)
if
(
verbose
>
1
)
Utils
.
log
.
fine
(
"Checking for unused CP entries"
);
Utils
.
log
.
fine
(
"Checking for unused CP entries"
);
requiredEntries
.
add
(
getRefString
(
""
));
// uconditionally present
requiredEntries
.
add
(
getRefString
(
""
));
// uconditionally present
...
@@ -1291,9 +1288,8 @@ class Package implements Constants {
...
@@ -1291,9 +1288,8 @@ class Package implements Constants {
// Use this before writing the class files.
// Use this before writing the class files.
void
ensureAllClassFiles
()
{
void
ensureAllClassFiles
()
{
HashSet
fileSet
=
new
HashSet
(
files
);
HashSet
<
File
>
fileSet
=
new
HashSet
<>(
files
);
for
(
Iterator
i
=
classes
.
iterator
();
i
.
hasNext
();
)
{
for
(
Class
cls
:
classes
)
{
Class
cls
=
(
Class
)
i
.
next
();
// Add to the end of ths list:
// Add to the end of ths list:
if
(!
fileSet
.
contains
(
cls
.
file
))
if
(!
fileSet
.
contains
(
cls
.
file
))
files
.
add
(
cls
.
file
);
files
.
add
(
cls
.
file
);
...
...
src/share/classes/com/sun/java/util/jar/pack/PackerImpl.java
浏览文件 @
130dc864
/*
/*
* Copyright (c) 2003, 20
05
, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 20
10
, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
*
* This code is free software; you can redistribute it and/or modify it
* This code is free software; you can redistribute it and/or modify it
...
@@ -25,12 +25,11 @@
...
@@ -25,12 +25,11 @@
package
com.sun.java.util.jar.pack
;
package
com.sun.java.util.jar.pack
;
import
com.sun.java.util.jar.pack.Attribute.Layout
;
import
java.util.*
;
import
java.util.*
;
import
java.util.jar.*
;
import
java.util.jar.*
;
import
java.util.zip.*
;
import
java.io.*
;
import
java.io.*
;
import
java.beans.PropertyChangeListener
;
import
java.beans.PropertyChangeListener
;
import
java.beans.PropertyChangeEvent
;
/*
/*
...
@@ -41,31 +40,22 @@ import java.beans.PropertyChangeEvent;
...
@@ -41,31 +40,22 @@ import java.beans.PropertyChangeEvent;
*/
*/
public
class
PackerImpl
implements
Pack200
.
Packer
{
public
class
PackerImpl
extends
TLGlobals
implements
Pack200
.
Packer
{
/**
/**
* Constructs a Packer object and sets the initial state of
* Constructs a Packer object and sets the initial state of
* the packer engines.
* the packer engines.
*/
*/
public
PackerImpl
()
{
public
PackerImpl
()
{}
_props
=
new
PropMap
();
//_props.getProperty() consults defaultProps invisibly.
//_props.putAll(defaultProps);
}
// Private stuff.
final
PropMap
_props
;
/**
/**
* Get the set of options for the pack and unpack engines.
* Get the set of options for the pack and unpack engines.
* @return A sorted association of option key strings to option values.
* @return A sorted association of option key strings to option values.
*/
*/
public
SortedMap
properties
()
{
public
SortedMap
<
String
,
String
>
properties
()
{
return
_
props
;
return
props
;
}
}
//Driver routines
//Driver routines
/**
/**
...
@@ -78,21 +68,22 @@ public class PackerImpl implements Pack200.Packer {
...
@@ -78,21 +68,22 @@ public class PackerImpl implements Pack200.Packer {
*/
*/
public
void
pack
(
JarFile
in
,
OutputStream
out
)
throws
IOException
{
public
void
pack
(
JarFile
in
,
OutputStream
out
)
throws
IOException
{
assert
(
Utils
.
currentInstance
.
get
()
==
null
);
assert
(
Utils
.
currentInstance
.
get
()
==
null
);
TimeZone
tz
=
(
_props
.
getBoolean
(
Utils
.
PACK_DEFAULT_TIMEZONE
))
?
null
:
TimeZone
tz
=
(
props
.
getBoolean
(
Utils
.
PACK_DEFAULT_TIMEZONE
))
TimeZone
.
getDefault
();
?
null
:
TimeZone
.
getDefault
();
try
{
try
{
Utils
.
currentInstance
.
set
(
this
);
Utils
.
currentInstance
.
set
(
this
);
if
(
tz
!=
null
)
TimeZone
.
setDefault
(
TimeZone
.
getTimeZone
(
"UTC"
));
if
(
tz
!=
null
)
TimeZone
.
setDefault
(
TimeZone
.
getTimeZone
(
"UTC"
));
if
(
"0"
.
equals
(
_
props
.
getProperty
(
Pack200
.
Packer
.
EFFORT
)))
{
if
(
"0"
.
equals
(
props
.
getProperty
(
Pack200
.
Packer
.
EFFORT
)))
{
Utils
.
copyJarFile
(
in
,
out
);
Utils
.
copyJarFile
(
in
,
out
);
}
else
{
}
else
{
(
new
DoPack
()).
run
(
in
,
out
);
(
new
DoPack
()).
run
(
in
,
out
);
in
.
close
();
}
}
}
finally
{
}
finally
{
Utils
.
currentInstance
.
set
(
null
);
Utils
.
currentInstance
.
set
(
null
);
if
(
tz
!=
null
)
TimeZone
.
setDefault
(
tz
);
if
(
tz
!=
null
)
TimeZone
.
setDefault
(
tz
);
in
.
close
();
}
}
}
}
...
@@ -112,21 +103,20 @@ public class PackerImpl implements Pack200.Packer {
...
@@ -112,21 +103,20 @@ public class PackerImpl implements Pack200.Packer {
*/
*/
public
void
pack
(
JarInputStream
in
,
OutputStream
out
)
throws
IOException
{
public
void
pack
(
JarInputStream
in
,
OutputStream
out
)
throws
IOException
{
assert
(
Utils
.
currentInstance
.
get
()
==
null
);
assert
(
Utils
.
currentInstance
.
get
()
==
null
);
TimeZone
tz
=
(
_
props
.
getBoolean
(
Utils
.
PACK_DEFAULT_TIMEZONE
))
?
null
:
TimeZone
tz
=
(
props
.
getBoolean
(
Utils
.
PACK_DEFAULT_TIMEZONE
))
?
null
:
TimeZone
.
getDefault
();
TimeZone
.
getDefault
();
try
{
try
{
Utils
.
currentInstance
.
set
(
this
);
Utils
.
currentInstance
.
set
(
this
);
if
(
tz
!=
null
)
TimeZone
.
setDefault
(
TimeZone
.
getTimeZone
(
"UTC"
));
if
(
tz
!=
null
)
TimeZone
.
setDefault
(
TimeZone
.
getTimeZone
(
"UTC"
));
if
(
"0"
.
equals
(
_
props
.
getProperty
(
Pack200
.
Packer
.
EFFORT
)))
{
if
(
"0"
.
equals
(
props
.
getProperty
(
Pack200
.
Packer
.
EFFORT
)))
{
Utils
.
copyJarFile
(
in
,
out
);
Utils
.
copyJarFile
(
in
,
out
);
}
else
{
}
else
{
(
new
DoPack
()).
run
(
in
,
out
);
(
new
DoPack
()).
run
(
in
,
out
);
in
.
close
();
}
}
}
finally
{
}
finally
{
Utils
.
currentInstance
.
set
(
null
);
Utils
.
currentInstance
.
set
(
null
);
if
(
tz
!=
null
)
TimeZone
.
setDefault
(
tz
);
if
(
tz
!=
null
)
TimeZone
.
setDefault
(
tz
);
in
.
close
();
}
}
}
}
/**
/**
...
@@ -134,7 +124,7 @@ public class PackerImpl implements Pack200.Packer {
...
@@ -134,7 +124,7 @@ public class PackerImpl implements Pack200.Packer {
* @param listener An object to be invoked when a property is changed.
* @param listener An object to be invoked when a property is changed.
*/
*/
public
void
addPropertyChangeListener
(
PropertyChangeListener
listener
)
{
public
void
addPropertyChangeListener
(
PropertyChangeListener
listener
)
{
_
props
.
addListener
(
listener
);
props
.
addListener
(
listener
);
}
}
/**
/**
...
@@ -142,7 +132,7 @@ public class PackerImpl implements Pack200.Packer {
...
@@ -142,7 +132,7 @@ public class PackerImpl implements Pack200.Packer {
* @param listener The PropertyChange listener to be removed.
* @param listener The PropertyChange listener to be removed.
*/
*/
public
void
removePropertyChangeListener
(
PropertyChangeListener
listener
)
{
public
void
removePropertyChangeListener
(
PropertyChangeListener
listener
)
{
_
props
.
removeListener
(
listener
);
props
.
removeListener
(
listener
);
}
}
...
@@ -151,11 +141,11 @@ public class PackerImpl implements Pack200.Packer {
...
@@ -151,11 +141,11 @@ public class PackerImpl implements Pack200.Packer {
// The packer worker.
// The packer worker.
private
class
DoPack
{
private
class
DoPack
{
final
int
verbose
=
_
props
.
getInteger
(
Utils
.
DEBUG_VERBOSE
);
final
int
verbose
=
props
.
getInteger
(
Utils
.
DEBUG_VERBOSE
);
{
{
_
props
.
setInteger
(
Pack200
.
Packer
.
PROGRESS
,
0
);
props
.
setInteger
(
Pack200
.
Packer
.
PROGRESS
,
0
);
if
(
verbose
>
0
)
Utils
.
log
.
info
(
_
props
.
toString
());
if
(
verbose
>
0
)
Utils
.
log
.
info
(
props
.
toString
());
}
}
// Here's where the bits are collected before getting packed:
// Here's where the bits are collected before getting packed:
...
@@ -163,7 +153,7 @@ public class PackerImpl implements Pack200.Packer {
...
@@ -163,7 +153,7 @@ public class PackerImpl implements Pack200.Packer {
final
String
unknownAttrCommand
;
final
String
unknownAttrCommand
;
{
{
String
uaMode
=
_
props
.
getProperty
(
Pack200
.
Packer
.
UNKNOWN_ATTRIBUTE
,
Pack200
.
Packer
.
PASS
);
String
uaMode
=
props
.
getProperty
(
Pack200
.
Packer
.
UNKNOWN_ATTRIBUTE
,
Pack200
.
Packer
.
PASS
);
if
(!(
Pack200
.
Packer
.
STRIP
.
equals
(
uaMode
)
||
if
(!(
Pack200
.
Packer
.
STRIP
.
equals
(
uaMode
)
||
Pack200
.
Packer
.
PASS
.
equals
(
uaMode
)
||
Pack200
.
Packer
.
PASS
.
equals
(
uaMode
)
||
Pack200
.
Packer
.
ERROR
.
equals
(
uaMode
)))
{
Pack200
.
Packer
.
ERROR
.
equals
(
uaMode
)))
{
...
@@ -191,13 +181,12 @@ public class PackerImpl implements Pack200.Packer {
...
@@ -191,13 +181,12 @@ public class PackerImpl implements Pack200.Packer {
};
};
for
(
int
i
=
0
;
i
<
ctypes
.
length
;
i
++)
{
for
(
int
i
=
0
;
i
<
ctypes
.
length
;
i
++)
{
String
pfx
=
keys
[
i
];
String
pfx
=
keys
[
i
];
Map
map
=
_props
.
prefixMap
(
pfx
);
Map
<
String
,
String
>
map
=
props
.
prefixMap
(
pfx
);
for
(
Iterator
j
=
map
.
keySet
().
iterator
();
j
.
hasNext
();
)
{
for
(
String
key
:
map
.
keySet
())
{
String
key
=
(
String
)
j
.
next
();
assert
(
key
.
startsWith
(
pfx
));
assert
(
key
.
startsWith
(
pfx
));
String
name
=
key
.
substring
(
pfx
.
length
());
String
name
=
key
.
substring
(
pfx
.
length
());
String
layout
=
_
props
.
getProperty
(
key
);
String
layout
=
props
.
getProperty
(
key
);
Objec
t
lkey
=
Attribute
.
keyForLookup
(
ctypes
[
i
],
name
);
Layou
t
lkey
=
Attribute
.
keyForLookup
(
ctypes
[
i
],
name
);
if
(
Pack200
.
Packer
.
STRIP
.
equals
(
layout
)
||
if
(
Pack200
.
Packer
.
STRIP
.
equals
(
layout
)
||
Pack200
.
Packer
.
PASS
.
equals
(
layout
)
||
Pack200
.
Packer
.
PASS
.
equals
(
layout
)
||
Pack200
.
Packer
.
ERROR
.
equals
(
layout
))
{
Pack200
.
Packer
.
ERROR
.
equals
(
layout
))
{
...
@@ -222,25 +211,25 @@ public class PackerImpl implements Pack200.Packer {
...
@@ -222,25 +211,25 @@ public class PackerImpl implements Pack200.Packer {
}
}
final
boolean
keepFileOrder
final
boolean
keepFileOrder
=
_
props
.
getBoolean
(
Pack200
.
Packer
.
KEEP_FILE_ORDER
);
=
props
.
getBoolean
(
Pack200
.
Packer
.
KEEP_FILE_ORDER
);
final
boolean
keepClassOrder
final
boolean
keepClassOrder
=
_
props
.
getBoolean
(
Utils
.
PACK_KEEP_CLASS_ORDER
);
=
props
.
getBoolean
(
Utils
.
PACK_KEEP_CLASS_ORDER
);
final
boolean
keepModtime
final
boolean
keepModtime
=
Pack200
.
Packer
.
KEEP
.
equals
(
_
props
.
getProperty
(
Pack200
.
Packer
.
MODIFICATION_TIME
));
=
Pack200
.
Packer
.
KEEP
.
equals
(
props
.
getProperty
(
Pack200
.
Packer
.
MODIFICATION_TIME
));
final
boolean
latestModtime
final
boolean
latestModtime
=
Pack200
.
Packer
.
LATEST
.
equals
(
_
props
.
getProperty
(
Pack200
.
Packer
.
MODIFICATION_TIME
));
=
Pack200
.
Packer
.
LATEST
.
equals
(
props
.
getProperty
(
Pack200
.
Packer
.
MODIFICATION_TIME
));
final
boolean
keepDeflateHint
final
boolean
keepDeflateHint
=
Pack200
.
Packer
.
KEEP
.
equals
(
_
props
.
getProperty
(
Pack200
.
Packer
.
DEFLATE_HINT
));
=
Pack200
.
Packer
.
KEEP
.
equals
(
props
.
getProperty
(
Pack200
.
Packer
.
DEFLATE_HINT
));
{
{
if
(!
keepModtime
&&
!
latestModtime
)
{
if
(!
keepModtime
&&
!
latestModtime
)
{
int
modtime
=
_
props
.
getTime
(
Pack200
.
Packer
.
MODIFICATION_TIME
);
int
modtime
=
props
.
getTime
(
Pack200
.
Packer
.
MODIFICATION_TIME
);
if
(
modtime
!=
Constants
.
NO_MODTIME
)
{
if
(
modtime
!=
Constants
.
NO_MODTIME
)
{
pkg
.
default_modtime
=
modtime
;
pkg
.
default_modtime
=
modtime
;
}
}
}
}
if
(!
keepDeflateHint
)
{
if
(!
keepDeflateHint
)
{
boolean
deflate_hint
=
_
props
.
getBoolean
(
Pack200
.
Packer
.
DEFLATE_HINT
);
boolean
deflate_hint
=
props
.
getBoolean
(
Pack200
.
Packer
.
DEFLATE_HINT
);
if
(
deflate_hint
)
{
if
(
deflate_hint
)
{
pkg
.
default_options
|=
Constants
.
AO_DEFLATE_HINT
;
pkg
.
default_options
|=
Constants
.
AO_DEFLATE_HINT
;
}
}
...
@@ -254,10 +243,10 @@ public class PackerImpl implements Pack200.Packer {
...
@@ -254,10 +243,10 @@ public class PackerImpl implements Pack200.Packer {
final
long
segmentLimit
;
final
long
segmentLimit
;
{
{
long
limit
;
long
limit
;
if
(
_
props
.
getProperty
(
Pack200
.
Packer
.
SEGMENT_LIMIT
,
""
).
equals
(
""
))
if
(
props
.
getProperty
(
Pack200
.
Packer
.
SEGMENT_LIMIT
,
""
).
equals
(
""
))
limit
=
-
1
;
limit
=
-
1
;
else
else
limit
=
_
props
.
getLong
(
Pack200
.
Packer
.
SEGMENT_LIMIT
);
limit
=
props
.
getLong
(
Pack200
.
Packer
.
SEGMENT_LIMIT
);
limit
=
Math
.
min
(
Integer
.
MAX_VALUE
,
limit
);
limit
=
Math
.
min
(
Integer
.
MAX_VALUE
,
limit
);
limit
=
Math
.
max
(-
1
,
limit
);
limit
=
Math
.
max
(-
1
,
limit
);
if
(
limit
==
-
1
)
if
(
limit
==
-
1
)
...
@@ -265,10 +254,10 @@ public class PackerImpl implements Pack200.Packer {
...
@@ -265,10 +254,10 @@ public class PackerImpl implements Pack200.Packer {
segmentLimit
=
limit
;
segmentLimit
=
limit
;
}
}
final
List
passFiles
;
// parsed pack.pass.file options
final
List
<
String
>
passFiles
;
// parsed pack.pass.file options
{
{
// Which class files will be passed through?
// Which class files will be passed through?
passFiles
=
_
props
.
getProperties
(
Pack200
.
Packer
.
PASS_FILE_PFX
);
passFiles
=
props
.
getProperties
(
Pack200
.
Packer
.
PASS_FILE_PFX
);
for
(
ListIterator
i
=
passFiles
.
listIterator
();
i
.
hasNext
();
)
{
for
(
ListIterator
i
=
passFiles
.
listIterator
();
i
.
hasNext
();
)
{
String
file
=
(
String
)
i
.
next
();
String
file
=
(
String
)
i
.
next
();
if
(
file
==
null
)
{
i
.
remove
();
continue
;
}
if
(
file
==
null
)
{
i
.
remove
();
continue
;
}
...
@@ -283,28 +272,28 @@ public class PackerImpl implements Pack200.Packer {
...
@@ -283,28 +272,28 @@ public class PackerImpl implements Pack200.Packer {
{
{
// Fill in permitted range of major/minor version numbers.
// Fill in permitted range of major/minor version numbers.
int
ver
;
int
ver
;
if
((
ver
=
_
props
.
getInteger
(
Utils
.
COM_PREFIX
+
"min.class.majver"
))
!=
0
)
if
((
ver
=
props
.
getInteger
(
Utils
.
COM_PREFIX
+
"min.class.majver"
))
!=
0
)
pkg
.
min_class_majver
=
(
short
)
ver
;
pkg
.
min_class_majver
=
(
short
)
ver
;
if
((
ver
=
_
props
.
getInteger
(
Utils
.
COM_PREFIX
+
"min.class.minver"
))
!=
0
)
if
((
ver
=
props
.
getInteger
(
Utils
.
COM_PREFIX
+
"min.class.minver"
))
!=
0
)
pkg
.
min_class_minver
=
(
short
)
ver
;
pkg
.
min_class_minver
=
(
short
)
ver
;
if
((
ver
=
_
props
.
getInteger
(
Utils
.
COM_PREFIX
+
"max.class.majver"
))
!=
0
)
if
((
ver
=
props
.
getInteger
(
Utils
.
COM_PREFIX
+
"max.class.majver"
))
!=
0
)
pkg
.
max_class_majver
=
(
short
)
ver
;
pkg
.
max_class_majver
=
(
short
)
ver
;
if
((
ver
=
_
props
.
getInteger
(
Utils
.
COM_PREFIX
+
"max.class.minver"
))
!=
0
)
if
((
ver
=
props
.
getInteger
(
Utils
.
COM_PREFIX
+
"max.class.minver"
))
!=
0
)
pkg
.
max_class_minver
=
(
short
)
ver
;
pkg
.
max_class_minver
=
(
short
)
ver
;
if
((
ver
=
_
props
.
getInteger
(
Utils
.
COM_PREFIX
+
"package.minver"
))
!=
0
)
if
((
ver
=
props
.
getInteger
(
Utils
.
COM_PREFIX
+
"package.minver"
))
!=
0
)
pkg
.
package_minver
=
(
short
)
ver
;
pkg
.
package_minver
=
(
short
)
ver
;
if
((
ver
=
_
props
.
getInteger
(
Utils
.
COM_PREFIX
+
"package.majver"
))
!=
0
)
if
((
ver
=
props
.
getInteger
(
Utils
.
COM_PREFIX
+
"package.majver"
))
!=
0
)
pkg
.
package_majver
=
(
short
)
ver
;
pkg
.
package_majver
=
(
short
)
ver
;
}
}
{
{
// Hook for testing: Forces use of special archive modes.
// Hook for testing: Forces use of special archive modes.
int
opt
=
_
props
.
getInteger
(
Utils
.
COM_PREFIX
+
"archive.options"
);
int
opt
=
props
.
getInteger
(
Utils
.
COM_PREFIX
+
"archive.options"
);
if
(
opt
!=
0
)
if
(
opt
!=
0
)
pkg
.
default_options
|=
opt
;
pkg
.
default_options
|=
opt
;
}
}
// (Done collecting options from
_
props.)
// (Done collecting options from props.)
boolean
isClassFile
(
String
name
)
{
boolean
isClassFile
(
String
name
)
{
if
(!
name
.
endsWith
(
".class"
))
return
false
;
if
(!
name
.
endsWith
(
".class"
))
return
false
;
...
@@ -423,16 +412,18 @@ public class PackerImpl implements Pack200.Packer {
...
@@ -423,16 +412,18 @@ public class PackerImpl implements Pack200.Packer {
Package
.
File
file
=
null
;
Package
.
File
file
=
null
;
// (5078608) : discount the resource files in META-INF
// (5078608) : discount the resource files in META-INF
// from segment computation.
// from segment computation.
long
inflen
=
(
isMetaInfFile
(
name
))
?
0L
:
long
inflen
=
(
isMetaInfFile
(
name
))
inFile
.
getInputLength
();
?
0L
:
inFile
.
getInputLength
();
if
((
segmentSize
+=
inflen
)
>
segmentLimit
)
{
if
((
segmentSize
+=
inflen
)
>
segmentLimit
)
{
segmentSize
-=
inflen
;
segmentSize
-=
inflen
;
int
nextCount
=
-
1
;
// don't know; it's a stream
int
nextCount
=
-
1
;
// don't know; it's a stream
flushPartial
(
out
,
nextCount
);
flushPartial
(
out
,
nextCount
);
}
}
if
(
verbose
>
1
)
if
(
verbose
>
1
)
{
Utils
.
log
.
fine
(
"Reading "
+
name
);
Utils
.
log
.
fine
(
"Reading "
+
name
);
}
assert
(
je
.
isDirectory
()
==
name
.
endsWith
(
"/"
));
assert
(
je
.
isDirectory
()
==
name
.
endsWith
(
"/"
));
...
@@ -450,18 +441,18 @@ public class PackerImpl implements Pack200.Packer {
...
@@ -450,18 +441,18 @@ public class PackerImpl implements Pack200.Packer {
}
}
void
run
(
JarFile
in
,
OutputStream
out
)
throws
IOException
{
void
run
(
JarFile
in
,
OutputStream
out
)
throws
IOException
{
List
inFiles
=
scanJar
(
in
);
List
<
InFile
>
inFiles
=
scanJar
(
in
);
if
(
verbose
>
0
)
if
(
verbose
>
0
)
Utils
.
log
.
info
(
"Reading "
+
inFiles
.
size
()
+
" files..."
);
Utils
.
log
.
info
(
"Reading "
+
inFiles
.
size
()
+
" files..."
);
int
numDone
=
0
;
int
numDone
=
0
;
for
(
Iterator
i
=
inFiles
.
iterator
();
i
.
hasNext
();
)
{
for
(
InFile
inFile
:
inFiles
)
{
InFile
inFile
=
(
InFile
)
i
.
next
();
String
name
=
inFile
.
name
;
String
name
=
inFile
.
name
;
// (5078608) : discount the resource files completely from segmenting
// (5078608) : discount the resource files completely from segmenting
long
inflen
=
(
isMetaInfFile
(
name
))
?
0L
:
long
inflen
=
(
isMetaInfFile
(
name
))
inFile
.
getInputLength
()
;
?
0L
:
inFile
.
getInputLength
()
;
if
((
segmentSize
+=
inflen
)
>
segmentLimit
)
{
if
((
segmentSize
+=
inflen
)
>
segmentLimit
)
{
segmentSize
-=
inflen
;
segmentSize
-=
inflen
;
// Estimate number of remaining segments:
// Estimate number of remaining segments:
...
@@ -530,11 +521,11 @@ public class PackerImpl implements Pack200.Packer {
...
@@ -530,11 +521,11 @@ public class PackerImpl implements Pack200.Packer {
}
}
void
flushPartial
(
OutputStream
out
,
int
nextCount
)
throws
IOException
{
void
flushPartial
(
OutputStream
out
,
int
nextCount
)
throws
IOException
{
if
(
pkg
.
files
.
size
()
==
0
&&
pkg
.
classes
.
size
()
==
0
)
{
if
(
pkg
.
files
.
isEmpty
()
&&
pkg
.
classes
.
isEmpty
()
)
{
return
;
// do not flush an empty segment
return
;
// do not flush an empty segment
}
}
flushPackage
(
out
,
Math
.
max
(
1
,
nextCount
));
flushPackage
(
out
,
Math
.
max
(
1
,
nextCount
));
_
props
.
setInteger
(
Pack200
.
Packer
.
PROGRESS
,
25
);
props
.
setInteger
(
Pack200
.
Packer
.
PROGRESS
,
25
);
// In case there will be another segment:
// In case there will be another segment:
makeNextPackage
();
makeNextPackage
();
segmentCount
+=
1
;
segmentCount
+=
1
;
...
@@ -543,10 +534,10 @@ public class PackerImpl implements Pack200.Packer {
...
@@ -543,10 +534,10 @@ public class PackerImpl implements Pack200.Packer {
}
}
void
flushAll
(
OutputStream
out
)
throws
IOException
{
void
flushAll
(
OutputStream
out
)
throws
IOException
{
_
props
.
setInteger
(
Pack200
.
Packer
.
PROGRESS
,
50
);
props
.
setInteger
(
Pack200
.
Packer
.
PROGRESS
,
50
);
flushPackage
(
out
,
0
);
flushPackage
(
out
,
0
);
out
.
flush
();
out
.
flush
();
_
props
.
setInteger
(
Pack200
.
Packer
.
PROGRESS
,
100
);
props
.
setInteger
(
Pack200
.
Packer
.
PROGRESS
,
100
);
segmentCount
+=
1
;
segmentCount
+=
1
;
segmentTotalSize
+=
segmentSize
;
segmentTotalSize
+=
segmentSize
;
segmentSize
=
0
;
segmentSize
=
0
;
...
@@ -582,11 +573,11 @@ public class PackerImpl implements Pack200.Packer {
...
@@ -582,11 +573,11 @@ public class PackerImpl implements Pack200.Packer {
pkg
.
trimStubs
();
pkg
.
trimStubs
();
// Do some stripping, maybe.
// Do some stripping, maybe.
if
(
_
props
.
getBoolean
(
Utils
.
COM_PREFIX
+
"strip.debug"
))
pkg
.
stripAttributeKind
(
"Debug"
);
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.compile"
))
pkg
.
stripAttributeKind
(
"Compile"
);
if
(
_
props
.
getBoolean
(
Utils
.
COM_PREFIX
+
"strip.constants"
))
pkg
.
stripAttributeKind
(
"Constant"
);
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.exceptions"
))
pkg
.
stripAttributeKind
(
"Exceptions"
);
if
(
_
props
.
getBoolean
(
Utils
.
COM_PREFIX
+
"strip.innerclasses"
))
pkg
.
stripAttributeKind
(
"InnerClasses"
);
if
(
props
.
getBoolean
(
Utils
.
COM_PREFIX
+
"strip.innerclasses"
))
pkg
.
stripAttributeKind
(
"InnerClasses"
);
// Must choose an archive version; PackageWriter does not.
// Must choose an archive version; PackageWriter does not.
if
(
pkg
.
package_majver
<=
0
)
pkg
.
choosePackageVersion
();
if
(
pkg
.
package_majver
<=
0
)
pkg
.
choosePackageVersion
();
...
@@ -606,11 +597,10 @@ public class PackerImpl implements Pack200.Packer {
...
@@ -606,11 +597,10 @@ public class PackerImpl implements Pack200.Packer {
}
}
}
}
List
scanJar
(
JarFile
jf
)
throws
IOException
{
List
<
InFile
>
scanJar
(
JarFile
jf
)
throws
IOException
{
// Collect jar entries, preserving order.
// Collect jar entries, preserving order.
List
inFiles
=
new
ArrayList
();
List
<
InFile
>
inFiles
=
new
ArrayList
<>();
for
(
Enumeration
e
=
jf
.
entries
();
e
.
hasMoreElements
();
)
{
for
(
JarEntry
je
:
Collections
.
list
(
jf
.
entries
()))
{
JarEntry
je
=
(
JarEntry
)
e
.
nextElement
();
InFile
inFile
=
new
InFile
(
jf
,
je
);
InFile
inFile
=
new
InFile
(
jf
,
je
);
assert
(
je
.
isDirectory
()
==
inFile
.
name
.
endsWith
(
"/"
));
assert
(
je
.
isDirectory
()
==
inFile
.
name
.
endsWith
(
"/"
));
inFiles
.
add
(
inFile
);
inFiles
.
add
(
inFile
);
...
...
src/share/classes/com/sun/java/util/jar/pack/PropMap.java
浏览文件 @
130dc864
...
@@ -91,7 +91,7 @@ class PropMap extends TreeMap {
...
@@ -91,7 +91,7 @@ class PropMap extends TreeMap {
String
.
valueOf
(
Boolean
.
getBoolean
(
Utils
.
PACK_DEFAULT_TIMEZONE
)));
String
.
valueOf
(
Boolean
.
getBoolean
(
Utils
.
PACK_DEFAULT_TIMEZONE
)));
// The segment size is unlimited
// The segment size is unlimited
props
.
put
(
Pack200
.
Packer
.
SEGMENT_LIMIT
,
""
);
props
.
put
(
Pack200
.
Packer
.
SEGMENT_LIMIT
,
"
-1
"
);
// Preserve file ordering by default.
// Preserve file ordering by default.
props
.
put
(
Pack200
.
Packer
.
KEEP_FILE_ORDER
,
Pack200
.
Packer
.
TRUE
);
props
.
put
(
Pack200
.
Packer
.
KEEP_FILE_ORDER
,
Pack200
.
Packer
.
TRUE
);
...
...
src/share/classes/com/sun/java/util/jar/pack/TLGlobals.java
0 → 100644
浏览文件 @
130dc864
/*
* 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
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.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
;
TLGlobals
()
{
utf8Entries
=
new
HashMap
<>();
classEntries
=
new
HashMap
<>();
literalEntries
=
new
HashMap
<>();
signatureEntries
=
new
HashMap
<>();
descriptorEntries
=
new
HashMap
<>();
memberEntries
=
new
HashMap
<>();
props
=
new
PropMap
();
}
SortedMap
<
Object
,
Object
>
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
;
}
}
src/share/classes/com/sun/java/util/jar/pack/UnpackerImpl.java
浏览文件 @
130dc864
/*
/*
* Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003,
2010,
Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
*
* This code is free software; you can redistribute it and/or modify it
* This code is free software; you can redistribute it and/or modify it
...
@@ -30,7 +30,6 @@ import java.util.jar.*;
...
@@ -30,7 +30,6 @@ import java.util.jar.*;
import
java.util.zip.*
;
import
java.util.zip.*
;
import
java.io.*
;
import
java.io.*
;
import
java.beans.PropertyChangeListener
;
import
java.beans.PropertyChangeListener
;
import
java.beans.PropertyChangeEvent
;
/*
/*
* Implementation of the Pack provider.
* Implementation of the Pack provider.
...
@@ -40,7 +39,7 @@ import java.beans.PropertyChangeEvent;
...
@@ -40,7 +39,7 @@ import java.beans.PropertyChangeEvent;
*/
*/
public
class
UnpackerImpl
implements
Pack200
.
Unpacker
{
public
class
UnpackerImpl
extends
TLGlobals
implements
Pack200
.
Unpacker
{
/**
/**
...
@@ -48,7 +47,7 @@ public class UnpackerImpl implements Pack200.Unpacker {
...
@@ -48,7 +47,7 @@ public class UnpackerImpl implements Pack200.Unpacker {
* @param listener An object to be invoked when a property is changed.
* @param listener An object to be invoked when a property is changed.
*/
*/
public
void
addPropertyChangeListener
(
PropertyChangeListener
listener
)
{
public
void
addPropertyChangeListener
(
PropertyChangeListener
listener
)
{
_
props
.
addListener
(
listener
);
props
.
addListener
(
listener
);
}
}
...
@@ -57,25 +56,19 @@ public class UnpackerImpl implements Pack200.Unpacker {
...
@@ -57,25 +56,19 @@ public class UnpackerImpl implements Pack200.Unpacker {
* @param listener The PropertyChange listener to be removed.
* @param listener The PropertyChange listener to be removed.
*/
*/
public
void
removePropertyChangeListener
(
PropertyChangeListener
listener
)
{
public
void
removePropertyChangeListener
(
PropertyChangeListener
listener
)
{
_
props
.
removeListener
(
listener
);
props
.
removeListener
(
listener
);
}
}
public
UnpackerImpl
()
{
public
UnpackerImpl
()
{}
_props
=
new
PropMap
();
//_props.getProperty() consults defaultProps invisibly.
//_props.putAll(defaultProps);
}
// Private stuff.
final
PropMap
_props
;
/**
/**
* Get the set of options for the pack and unpack engines.
* Get the set of options for the pack and unpack engines.
* @return A sorted association of option key strings to option values.
* @return A sorted association of option key strings to option values.
*/
*/
public
SortedMap
properties
()
{
public
SortedMap
<
String
,
String
>
properties
()
{
return
_
props
;
return
props
;
}
}
// Back-pointer to NativeUnpacker, when active.
// Back-pointer to NativeUnpacker, when active.
...
@@ -101,19 +94,20 @@ public class UnpackerImpl implements Pack200.Unpacker {
...
@@ -101,19 +94,20 @@ public class UnpackerImpl implements Pack200.Unpacker {
*/
*/
public
void
unpack
(
InputStream
in0
,
JarOutputStream
out
)
throws
IOException
{
public
void
unpack
(
InputStream
in0
,
JarOutputStream
out
)
throws
IOException
{
assert
(
Utils
.
currentInstance
.
get
()
==
null
);
assert
(
Utils
.
currentInstance
.
get
()
==
null
);
TimeZone
tz
=
(
_props
.
getBoolean
(
Utils
.
PACK_DEFAULT_TIMEZONE
))
?
null
:
TimeZone
tz
=
(
props
.
getBoolean
(
Utils
.
PACK_DEFAULT_TIMEZONE
))
TimeZone
.
getDefault
();
?
null
:
TimeZone
.
getDefault
();
try
{
try
{
Utils
.
currentInstance
.
set
(
this
);
Utils
.
currentInstance
.
set
(
this
);
if
(
tz
!=
null
)
TimeZone
.
setDefault
(
TimeZone
.
getTimeZone
(
"UTC"
));
if
(
tz
!=
null
)
TimeZone
.
setDefault
(
TimeZone
.
getTimeZone
(
"UTC"
));
final
int
verbose
=
_
props
.
getInteger
(
Utils
.
DEBUG_VERBOSE
);
final
int
verbose
=
props
.
getInteger
(
Utils
.
DEBUG_VERBOSE
);
BufferedInputStream
in
=
new
BufferedInputStream
(
in0
);
BufferedInputStream
in
=
new
BufferedInputStream
(
in0
);
if
(
Utils
.
isJarMagic
(
Utils
.
readMagic
(
in
)))
{
if
(
Utils
.
isJarMagic
(
Utils
.
readMagic
(
in
)))
{
if
(
verbose
>
0
)
if
(
verbose
>
0
)
Utils
.
log
.
info
(
"Copying unpacked JAR file..."
);
Utils
.
log
.
info
(
"Copying unpacked JAR file..."
);
Utils
.
copyJarFile
(
new
JarInputStream
(
in
),
out
);
Utils
.
copyJarFile
(
new
JarInputStream
(
in
),
out
);
}
else
if
(
_
props
.
getBoolean
(
Utils
.
DEBUG_DISABLE_NATIVE
))
{
}
else
if
(
props
.
getBoolean
(
Utils
.
DEBUG_DISABLE_NATIVE
))
{
(
new
DoUnpack
()).
run
(
in
,
out
);
(
new
DoUnpack
()).
run
(
in
,
out
);
in
.
close
();
in
.
close
();
Utils
.
markJarFile
(
out
);
Utils
.
markJarFile
(
out
);
...
@@ -142,36 +136,38 @@ public class UnpackerImpl implements Pack200.Unpacker {
...
@@ -142,36 +136,38 @@ public class UnpackerImpl implements Pack200.Unpacker {
// %%% Reconsider if native unpacker learns to memory-map the file.
// %%% Reconsider if native unpacker learns to memory-map the file.
FileInputStream
instr
=
new
FileInputStream
(
in
);
FileInputStream
instr
=
new
FileInputStream
(
in
);
unpack
(
instr
,
out
);
unpack
(
instr
,
out
);
if
(
_
props
.
getBoolean
(
Utils
.
UNPACK_REMOVE_PACKFILE
))
{
if
(
props
.
getBoolean
(
Utils
.
UNPACK_REMOVE_PACKFILE
))
{
in
.
delete
();
in
.
delete
();
}
}
}
}
private
class
DoUnpack
{
private
class
DoUnpack
{
final
int
verbose
=
_
props
.
getInteger
(
Utils
.
DEBUG_VERBOSE
);
final
int
verbose
=
props
.
getInteger
(
Utils
.
DEBUG_VERBOSE
);
{
{
_
props
.
setInteger
(
Pack200
.
Unpacker
.
PROGRESS
,
0
);
props
.
setInteger
(
Pack200
.
Unpacker
.
PROGRESS
,
0
);
}
}
// Here's where the bits are read from disk:
// Here's where the bits are read from disk:
final
Package
pkg
=
new
Package
();
final
Package
pkg
=
new
Package
();
final
boolean
keepModtime
final
boolean
keepModtime
=
Pack200
.
Packer
.
KEEP
.
equals
(
_props
.
getProperty
(
Utils
.
UNPACK_MODIFICATION_TIME
,
Pack200
.
Packer
.
KEEP
));
=
Pack200
.
Packer
.
KEEP
.
equals
(
props
.
getProperty
(
Utils
.
UNPACK_MODIFICATION_TIME
,
Pack200
.
Packer
.
KEEP
));
final
boolean
keepDeflateHint
final
boolean
keepDeflateHint
=
Pack200
.
Packer
.
KEEP
.
equals
(
_props
.
getProperty
(
Pack200
.
Unpacker
.
DEFLATE_HINT
,
Pack200
.
Packer
.
KEEP
));
=
Pack200
.
Packer
.
KEEP
.
equals
(
props
.
getProperty
(
Pack200
.
Unpacker
.
DEFLATE_HINT
,
Pack200
.
Packer
.
KEEP
));
final
int
modtime
;
final
int
modtime
;
final
boolean
deflateHint
;
final
boolean
deflateHint
;
{
{
if
(!
keepModtime
)
{
if
(!
keepModtime
)
{
modtime
=
_
props
.
getTime
(
Utils
.
UNPACK_MODIFICATION_TIME
);
modtime
=
props
.
getTime
(
Utils
.
UNPACK_MODIFICATION_TIME
);
}
else
{
}
else
{
modtime
=
pkg
.
default_modtime
;
modtime
=
pkg
.
default_modtime
;
}
}
deflateHint
=
(
keepDeflateHint
)
?
false
:
deflateHint
=
(
keepDeflateHint
)
?
false
:
_
props
.
getBoolean
(
java
.
util
.
jar
.
Pack200
.
Unpacker
.
DEFLATE_HINT
);
props
.
getBoolean
(
java
.
util
.
jar
.
Pack200
.
Unpacker
.
DEFLATE_HINT
);
}
}
// Checksum apparatus.
// Checksum apparatus.
...
@@ -181,7 +177,7 @@ public class UnpackerImpl implements Pack200.Unpacker {
...
@@ -181,7 +177,7 @@ public class UnpackerImpl implements Pack200.Unpacker {
public
void
run
(
BufferedInputStream
in
,
JarOutputStream
out
)
throws
IOException
{
public
void
run
(
BufferedInputStream
in
,
JarOutputStream
out
)
throws
IOException
{
if
(
verbose
>
0
)
{
if
(
verbose
>
0
)
{
_
props
.
list
(
System
.
out
);
props
.
list
(
System
.
out
);
}
}
for
(
int
seg
=
1
;
;
seg
++)
{
for
(
int
seg
=
1
;
;
seg
++)
{
unpackSegment
(
in
,
out
);
unpackSegment
(
in
,
out
);
...
@@ -194,25 +190,26 @@ public class UnpackerImpl implements Pack200.Unpacker {
...
@@ -194,25 +190,26 @@ public class UnpackerImpl implements Pack200.Unpacker {
}
}
private
void
unpackSegment
(
InputStream
in
,
JarOutputStream
out
)
throws
IOException
{
private
void
unpackSegment
(
InputStream
in
,
JarOutputStream
out
)
throws
IOException
{
_
props
.
setProperty
(
java
.
util
.
jar
.
Pack200
.
Unpacker
.
PROGRESS
,
"0"
);
props
.
setProperty
(
java
.
util
.
jar
.
Pack200
.
Unpacker
.
PROGRESS
,
"0"
);
// Process the output directory or jar output.
// Process the output directory or jar output.
new
PackageReader
(
pkg
,
in
).
read
();
new
PackageReader
(
pkg
,
in
).
read
();
if
(
_
props
.
getBoolean
(
"unpack.strip.debug"
))
pkg
.
stripAttributeKind
(
"Debug"
);
if
(
props
.
getBoolean
(
"unpack.strip.debug"
))
pkg
.
stripAttributeKind
(
"Debug"
);
if
(
_
props
.
getBoolean
(
"unpack.strip.compile"
))
pkg
.
stripAttributeKind
(
"Compile"
);
if
(
props
.
getBoolean
(
"unpack.strip.compile"
))
pkg
.
stripAttributeKind
(
"Compile"
);
_
props
.
setProperty
(
java
.
util
.
jar
.
Pack200
.
Unpacker
.
PROGRESS
,
"50"
);
props
.
setProperty
(
java
.
util
.
jar
.
Pack200
.
Unpacker
.
PROGRESS
,
"50"
);
pkg
.
ensureAllClassFiles
();
pkg
.
ensureAllClassFiles
();
// Now write out the files.
// Now write out the files.
HashSet
classesToWrite
=
new
HashSet
(
pkg
.
getClasses
());
HashSet
<
Package
.
Class
>
classesToWrite
=
new
HashSet
<>
(
pkg
.
getClasses
());
for
(
Iterator
i
=
pkg
.
getFiles
().
iterator
();
i
.
hasNext
();
)
{
for
(
Iterator
i
=
pkg
.
getFiles
().
iterator
();
i
.
hasNext
();
)
{
Package
.
File
file
=
(
Package
.
File
)
i
.
next
();
Package
.
File
file
=
(
Package
.
File
)
i
.
next
();
String
name
=
file
.
nameString
;
String
name
=
file
.
nameString
;
JarEntry
je
=
new
JarEntry
(
Utils
.
getJarEntryName
(
name
));
JarEntry
je
=
new
JarEntry
(
Utils
.
getJarEntryName
(
name
));
boolean
deflate
;
boolean
deflate
;
deflate
=
(
keepDeflateHint
)
?
(((
file
.
options
&
Constants
.
FO_DEFLATE_HINT
)
!=
0
)
||
deflate
=
(
keepDeflateHint
)
((
pkg
.
default_options
&
Constants
.
AO_DEFLATE_HINT
)
!=
0
))
:
?
(((
file
.
options
&
Constants
.
FO_DEFLATE_HINT
)
!=
0
)
||
deflateHint
;
((
pkg
.
default_options
&
Constants
.
AO_DEFLATE_HINT
)
!=
0
))
:
deflateHint
;
boolean
needCRC
=
!
deflate
;
// STORE mode requires CRC
boolean
needCRC
=
!
deflate
;
// STORE mode requires CRC
...
@@ -250,7 +247,7 @@ public class UnpackerImpl implements Pack200.Unpacker {
...
@@ -250,7 +247,7 @@ public class UnpackerImpl implements Pack200.Unpacker {
Utils
.
log
.
info
(
"Writing "
+
Utils
.
zeString
((
ZipEntry
)
je
));
Utils
.
log
.
info
(
"Writing "
+
Utils
.
zeString
((
ZipEntry
)
je
));
}
}
assert
(
classesToWrite
.
isEmpty
());
assert
(
classesToWrite
.
isEmpty
());
_
props
.
setProperty
(
java
.
util
.
jar
.
Pack200
.
Unpacker
.
PROGRESS
,
"100"
);
props
.
setProperty
(
java
.
util
.
jar
.
Pack200
.
Unpacker
.
PROGRESS
,
"100"
);
pkg
.
reset
();
// reset for the next segment, if any
pkg
.
reset
();
// reset for the next segment, if any
}
}
}
}
...
...
src/share/classes/com/sun/java/util/jar/pack/Utils.java
浏览文件 @
130dc864
/*
/*
* Copyright (c) 2003, 20
05
, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 20
10
, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
*
* This code is free software; you can redistribute it and/or modify it
* This code is free software; you can redistribute it and/or modify it
...
@@ -25,6 +25,13 @@
...
@@ -25,6 +25,13 @@
package
com.sun.java.util.jar.pack
;
package
com.sun.java.util.jar.pack
;
import
com.sun.java.util.jar.pack.Attribute.Layout
;
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.SignatureEntry
;
import
com.sun.java.util.jar.pack.ConstantPool.Utf8Entry
;
import
java.util.*
;
import
java.util.*
;
import
java.util.jar.*
;
import
java.util.jar.*
;
import
java.util.zip.*
;
import
java.util.zip.*
;
...
@@ -113,17 +120,46 @@ class Utils {
...
@@ -113,17 +120,46 @@ class Utils {
*/
*/
static
final
String
PACK_ZIP_ARCHIVE_MARKER_COMMENT
=
"PACK200"
;
static
final
String
PACK_ZIP_ARCHIVE_MARKER_COMMENT
=
"PACK200"
;
// Keep a TLS point to the current Packer or Unpacker
.
// Keep a TLS point to the global data and environment
.
// This makes it simpler to supply environmental options
// This makes it simpler to supply environmental options
// to the engine code, especially the native code.
// to the engine code, especially the native code.
static
final
ThreadLocal
currentInstance
=
new
ThreadLocal
();
static
final
ThreadLocal
<
TLGlobals
>
currentInstance
=
new
ThreadLocal
<>();
// convenience methods to access the TL globals
static
TLGlobals
getTLGlobals
()
{
return
currentInstance
.
get
();
}
static
Map
<
String
,
Utf8Entry
>
getUtf8Entries
()
{
return
getTLGlobals
().
getUtf8Entries
();
}
static
Map
<
String
,
ClassEntry
>
getClassEntries
()
{
return
getTLGlobals
().
getClassEntries
();
}
static
Map
<
Object
,
LiteralEntry
>
getLiteralEntries
()
{
return
getTLGlobals
().
getLiteralEntries
();
}
static
Map
<
String
,
DescriptorEntry
>
getDescriptorEntries
()
{
return
getTLGlobals
().
getDescriptorEntries
();
}
static
Map
<
String
,
SignatureEntry
>
getSignatureEntries
()
{
return
getTLGlobals
().
getSignatureEntries
();
}
static
Map
<
String
,
MemberEntry
>
getMemberEntries
()
{
return
getTLGlobals
().
getMemberEntries
();
}
static
PropMap
currentPropMap
()
{
static
PropMap
currentPropMap
()
{
Object
obj
=
currentInstance
.
get
();
Object
obj
=
currentInstance
.
get
();
if
(
obj
instanceof
PackerImpl
)
if
(
obj
instanceof
PackerImpl
)
return
((
PackerImpl
)
obj
).
_
props
;
return
((
PackerImpl
)
obj
).
props
;
if
(
obj
instanceof
UnpackerImpl
)
if
(
obj
instanceof
UnpackerImpl
)
return
((
UnpackerImpl
)
obj
).
_
props
;
return
((
UnpackerImpl
)
obj
).
props
;
return
null
;
return
null
;
}
}
...
...
src/share/classes/com/sun/jndi/ldap/Connection.java
浏览文件 @
130dc864
...
@@ -813,7 +813,8 @@ public final class Connection implements Runnable {
...
@@ -813,7 +813,8 @@ public final class Connection implements Runnable {
try
{
try
{
while
(
true
)
{
while
(
true
)
{
try
{
try
{
inbuf
=
new
byte
[
10
];
// type and length (at most 128 octets for long form)
inbuf
=
new
byte
[
129
];
offset
=
0
;
offset
=
0
;
seqlen
=
0
;
seqlen
=
0
;
...
...
src/share/classes/java/lang/AbstractStringBuilder.java
浏览文件 @
130dc864
...
@@ -470,7 +470,7 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
...
@@ -470,7 +470,7 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
public
AbstractStringBuilder
append
(
CharSequence
s
,
int
start
,
int
end
)
{
public
AbstractStringBuilder
append
(
CharSequence
s
,
int
start
,
int
end
)
{
if
(
s
==
null
)
if
(
s
==
null
)
s
=
"null"
;
s
=
"null"
;
if
((
start
<
0
)
||
(
end
<
0
)
||
(
start
>
end
)
||
(
end
>
s
.
length
()))
if
((
start
<
0
)
||
(
start
>
end
)
||
(
end
>
s
.
length
()))
throw
new
IndexOutOfBoundsException
(
throw
new
IndexOutOfBoundsException
(
"start "
+
start
+
", end "
+
end
+
", s.length() "
"start "
+
start
+
", end "
+
end
+
", s.length() "
+
s
.
length
());
+
s
.
length
());
...
@@ -529,7 +529,8 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
...
@@ -529,7 +529,8 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
* or {@code offset+len > str.length}
* or {@code offset+len > str.length}
*/
*/
public
AbstractStringBuilder
append
(
char
str
[],
int
offset
,
int
len
)
{
public
AbstractStringBuilder
append
(
char
str
[],
int
offset
,
int
len
)
{
ensureCapacityInternal
(
count
+
len
);
if
(
len
>
0
)
// let arraycopy report AIOOBE for len < 0
ensureCapacityInternal
(
count
+
len
);
System
.
arraycopy
(
str
,
offset
,
value
,
count
,
len
);
System
.
arraycopy
(
str
,
offset
,
value
,
count
,
len
);
count
+=
len
;
count
+=
len
;
return
this
;
return
this
;
...
...
src/share/classes/java/lang/Thread.java
浏览文件 @
130dc864
...
@@ -413,6 +413,18 @@ class Thread implements Runnable {
...
@@ -413,6 +413,18 @@ class Thread implements Runnable {
tid
=
nextThreadID
();
tid
=
nextThreadID
();
}
}
/**
* Throws CloneNotSupportedException as a Thread can not be meaningfully
* cloned. Construct a new Thread instead.
*
* @throws CloneNotSupportedException
* always
*/
@Override
protected
Object
clone
()
throws
CloneNotSupportedException
{
throw
new
CloneNotSupportedException
();
}
/**
/**
* Allocates a new {@code Thread} object. This constructor has the same
* Allocates a new {@code Thread} object. This constructor has the same
* effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
* effect as {@linkplain #Thread(ThreadGroup,Runnable,String) Thread}
...
...
src/share/classes/java/lang/Throwable.java
浏览文件 @
130dc864
...
@@ -200,7 +200,16 @@ public class Throwable implements Serializable {
...
@@ -200,7 +200,16 @@ public class Throwable implements Serializable {
* @serial
* @serial
* @since 1.7
* @since 1.7
*/
*/
private
List
<
Throwable
>
suppressedExceptions
=
Collections
.
emptyList
();
private
List
<
Throwable
>
suppressedExceptions
=
null
;
/*
* This field is lazily initialized when the first suppressed
* exception is added.
*
* OutOfMemoryError is preallocated in the VM for better OOM
* diagnosability during VM initialization. Constructor can't
* be not invoked. If a new field to be added in the future must
* be initialized to non-null, it requires a synchronized VM change.
*/
/** Message for trying to suppress a null exception. */
/** Message for trying to suppress a null exception. */
private
static
final
String
NULL_CAUSE_MESSAGE
=
"Cannot suppress a null exception."
;
private
static
final
String
NULL_CAUSE_MESSAGE
=
"Cannot suppress a null exception."
;
...
@@ -329,7 +338,7 @@ public class Throwable implements Serializable {
...
@@ -329,7 +338,7 @@ public class Throwable implements Serializable {
* cause is nonexistent or unknown.
* cause is nonexistent or unknown.
* @since 1.4
* @since 1.4
*/
*/
public
Throwable
getCause
()
{
public
synchronized
Throwable
getCause
()
{
return
(
cause
==
this
?
null
:
cause
);
return
(
cause
==
this
?
null
:
cause
);
}
}
...
@@ -563,7 +572,7 @@ public class Throwable implements Serializable {
...
@@ -563,7 +572,7 @@ public class Throwable implements Serializable {
s
.
println
(
"\tat "
+
traceElement
);
s
.
println
(
"\tat "
+
traceElement
);
// Print suppressed exceptions, if any
// Print suppressed exceptions, if any
for
(
Throwable
se
:
suppressedExceptions
)
for
(
Throwable
se
:
getSuppressedExceptions
()
)
se
.
printEnclosedStackTrace
(
s
,
trace
,
SUPPRESSED_CAPTION
,
"\t"
,
dejaVu
);
se
.
printEnclosedStackTrace
(
s
,
trace
,
SUPPRESSED_CAPTION
,
"\t"
,
dejaVu
);
// Print cause, if any
// Print cause, if any
...
@@ -604,7 +613,7 @@ public class Throwable implements Serializable {
...
@@ -604,7 +613,7 @@ public class Throwable implements Serializable {
s
.
println
(
prefix
+
"\t... "
+
framesInCommon
+
" more"
);
s
.
println
(
prefix
+
"\t... "
+
framesInCommon
+
" more"
);
// Print suppressed exceptions, if any
// Print suppressed exceptions, if any
for
(
Throwable
se
:
suppressedExceptions
)
for
(
Throwable
se
:
getSuppressedExceptions
()
)
se
.
printEnclosedStackTrace
(
s
,
trace
,
SUPPRESSED_CAPTION
,
se
.
printEnclosedStackTrace
(
s
,
trace
,
SUPPRESSED_CAPTION
,
prefix
+
"\t"
,
dejaVu
);
prefix
+
"\t"
,
dejaVu
);
...
@@ -747,7 +756,9 @@ public class Throwable implements Serializable {
...
@@ -747,7 +756,9 @@ public class Throwable implements Serializable {
if
(
defensiveCopy
[
i
]
==
null
)
if
(
defensiveCopy
[
i
]
==
null
)
throw
new
NullPointerException
(
"stackTrace["
+
i
+
"]"
);
throw
new
NullPointerException
(
"stackTrace["
+
i
+
"]"
);
this
.
stackTrace
=
defensiveCopy
;
synchronized
(
this
)
{
this
.
stackTrace
=
defensiveCopy
;
}
}
}
/**
/**
...
@@ -772,11 +783,11 @@ public class Throwable implements Serializable {
...
@@ -772,11 +783,11 @@ public class Throwable implements Serializable {
private
void
readObject
(
ObjectInputStream
s
)
private
void
readObject
(
ObjectInputStream
s
)
throws
IOException
,
ClassNotFoundException
{
throws
IOException
,
ClassNotFoundException
{
s
.
defaultReadObject
();
// read in all fields
s
.
defaultReadObject
();
// read in all fields
List
<
Throwable
>
suppressed
=
Collections
.
emptyList
()
;
List
<
Throwable
>
suppressed
=
null
;
if
(
suppressedExceptions
!=
null
&&
if
(
suppressedExceptions
!=
null
&&
!
suppressedExceptions
.
isEmpty
())
{
// Copy Throwables to new list
!
suppressedExceptions
.
isEmpty
())
{
// Copy Throwables to new list
suppressed
=
new
ArrayList
<
Throwable
>();
suppressed
=
new
ArrayList
<
Throwable
>();
for
(
Throwable
t
:
suppressedExceptions
)
{
for
(
Throwable
t
:
suppressedExceptions
)
{
if
(
t
==
null
)
if
(
t
==
null
)
throw
new
NullPointerException
(
NULL_CAUSE_MESSAGE
);
throw
new
NullPointerException
(
NULL_CAUSE_MESSAGE
);
suppressed
.
add
(
t
);
suppressed
.
add
(
t
);
...
@@ -819,7 +830,7 @@ public class Throwable implements Serializable {
...
@@ -819,7 +830,7 @@ public class Throwable implements Serializable {
if
(
exception
==
this
)
if
(
exception
==
this
)
throw
new
IllegalArgumentException
(
"Self-suppression not permitted"
);
throw
new
IllegalArgumentException
(
"Self-suppression not permitted"
);
if
(
suppressedExceptions
.
size
()
==
0
)
if
(
suppressedExceptions
==
null
)
suppressedExceptions
=
new
ArrayList
<
Throwable
>();
suppressedExceptions
=
new
ArrayList
<
Throwable
>();
suppressedExceptions
.
add
(
exception
);
suppressedExceptions
.
add
(
exception
);
}
}
...
@@ -835,7 +846,10 @@ public class Throwable implements Serializable {
...
@@ -835,7 +846,10 @@ public class Throwable implements Serializable {
* suppressed to deliver this exception.
* suppressed to deliver this exception.
* @since 1.7
* @since 1.7
*/
*/
public
Throwable
[]
getSuppressedExceptions
()
{
public
synchronized
Throwable
[]
getSuppressedExceptions
()
{
return
suppressedExceptions
.
toArray
(
EMPTY_THROWABLE_ARRAY
);
if
(
suppressedExceptions
==
null
)
return
EMPTY_THROWABLE_ARRAY
;
else
return
suppressedExceptions
.
toArray
(
EMPTY_THROWABLE_ARRAY
);
}
}
}
}
src/share/classes/java/net/HttpCookie.java
浏览文件 @
130dc864
...
@@ -1093,14 +1093,8 @@ public final class HttpCookie implements Cloneable {
...
@@ -1093,14 +1093,8 @@ public final class HttpCookie implements Cloneable {
return
sb
.
toString
();
return
sb
.
toString
();
}
}
private
static
SimpleDateFormat
[]
cDateFormats
=
null
;
static
final
TimeZone
GMT
=
TimeZone
.
getTimeZone
(
"GMT"
);
static
{
cDateFormats
=
new
SimpleDateFormat
[
COOKIE_DATE_FORMATS
.
length
];
for
(
int
i
=
0
;
i
<
COOKIE_DATE_FORMATS
.
length
;
i
++)
{
cDateFormats
[
i
]
=
new
SimpleDateFormat
(
COOKIE_DATE_FORMATS
[
i
],
Locale
.
US
);
cDateFormats
[
i
].
setTimeZone
(
TimeZone
.
getTimeZone
(
"GMT"
));
}
}
/*
/*
* @param dateString a date string in one of the formats
* @param dateString a date string in one of the formats
* defined in Netscape cookie spec
* defined in Netscape cookie spec
...
@@ -1109,12 +1103,14 @@ public final class HttpCookie implements Cloneable {
...
@@ -1109,12 +1103,14 @@ public final class HttpCookie implements Cloneable {
* time and the time specified by dateString
* time and the time specified by dateString
*/
*/
private
long
expiryDate2DeltaSeconds
(
String
dateString
)
{
private
long
expiryDate2DeltaSeconds
(
String
dateString
)
{
for
(
SimpleDateFormat
df
:
cDateFormats
)
{
for
(
int
i
=
0
;
i
<
COOKIE_DATE_FORMATS
.
length
;
i
++)
{
SimpleDateFormat
df
=
new
SimpleDateFormat
(
COOKIE_DATE_FORMATS
[
i
],
Locale
.
US
);
df
.
setTimeZone
(
GMT
);
try
{
try
{
Date
date
=
df
.
parse
(
dateString
);
Date
date
=
df
.
parse
(
dateString
);
return
(
date
.
getTime
()
-
whenCreated
)
/
1000
;
return
(
date
.
getTime
()
-
whenCreated
)
/
1000
;
}
catch
(
Exception
e
)
{
}
catch
(
Exception
e
)
{
// Ignore, try the next date format
}
}
}
}
return
0
;
return
0
;
...
...
src/share/classes/java/net/URI.java
浏览文件 @
130dc864
...
@@ -856,9 +856,7 @@ public final class URI
...
@@ -856,9 +856,7 @@ public final class URI
try
{
try
{
return
new
URI
(
str
);
return
new
URI
(
str
);
}
catch
(
URISyntaxException
x
)
{
}
catch
(
URISyntaxException
x
)
{
IllegalArgumentException
y
=
new
IllegalArgumentException
();
throw
new
IllegalArgumentException
(
x
.
getMessage
(),
x
);
y
.
initCause
(
x
);
throw
y
;
}
}
}
}
...
...
src/share/classes/java/security/KeyStore.java
浏览文件 @
130dc864
/*
/*
* Copyright (c) 1997, 20
08
, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 20
10
, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
*
* This code is free software; you can redistribute it and/or modify it
* This code is free software; you can redistribute it and/or modify it
...
@@ -131,17 +131,19 @@ import javax.security.auth.callback.*;
...
@@ -131,17 +131,19 @@ import javax.security.auth.callback.*;
* to read existing entries from the keystore, or to write new entries
* to read existing entries from the keystore, or to write new entries
* into the keystore:
* into the keystore:
* <pre>
* <pre>
* KeyStore.ProtectionParameter protParam =
* new KeyStore.PasswordProtection(password);
*
* // get my private key
* // get my private key
* KeyStore.PrivateKeyEntry pkEntry = (KeyStore.PrivateKeyEntry)
* KeyStore.PrivateKeyEntry pkEntry = (KeyStore.PrivateKeyEntry)
* ks.getEntry("privateKeyAlias", p
assword
);
* ks.getEntry("privateKeyAlias", p
rotParam
);
* PrivateKey myPrivateKey = pkEntry.getPrivateKey();
* PrivateKey myPrivateKey = pkEntry.getPrivateKey();
*
*
* // save my secret key
* // save my secret key
* javax.crypto.SecretKey mySecretKey;
* javax.crypto.SecretKey mySecretKey;
* KeyStore.SecretKeyEntry skEntry =
* KeyStore.SecretKeyEntry skEntry =
* new KeyStore.SecretKeyEntry(mySecretKey);
* new KeyStore.SecretKeyEntry(mySecretKey);
* ks.setEntry("secretKeyAlias", skEntry,
* ks.setEntry("secretKeyAlias", skEntry, protParam);
* new KeyStore.PasswordProtection(password));
*
*
* // store away the keystore
* // store away the keystore
* java.io.FileOutputStream fos = null;
* java.io.FileOutputStream fos = null;
...
...
src/share/classes/java/sql/Date.java
浏览文件 @
130dc864
...
@@ -103,27 +103,46 @@ public class Date extends java.util.Date {
...
@@ -103,27 +103,46 @@ public class Date extends java.util.Date {
* JDBC date escape format (yyyy-mm-dd)
* JDBC date escape format (yyyy-mm-dd)
*/
*/
public
static
Date
valueOf
(
String
s
)
{
public
static
Date
valueOf
(
String
s
)
{
int
year
;
final
int
YEAR_LENGTH
=
4
;
int
month
;
final
int
MONTH_LENGTH
=
2
;
int
day
;
final
int
DAY_LENGTH
=
2
;
final
int
MAX_MONTH
=
12
;
final
int
MAX_DAY
=
31
;
int
firstDash
;
int
firstDash
;
int
secondDash
;
int
secondDash
;
Date
d
=
null
;
if
(
s
==
null
)
throw
new
java
.
lang
.
IllegalArgumentException
();
if
(
s
==
null
)
{
throw
new
java
.
lang
.
IllegalArgumentException
();
}
firstDash
=
s
.
indexOf
(
'-'
);
firstDash
=
s
.
indexOf
(
'-'
);
secondDash
=
s
.
indexOf
(
'-'
,
firstDash
+
1
);
secondDash
=
s
.
indexOf
(
'-'
,
firstDash
+
1
);
if
((
firstDash
>
0
)
&
(
secondDash
>
0
)
&
(
secondDash
<
s
.
length
()-
1
))
{
year
=
Integer
.
parseInt
(
s
.
substring
(
0
,
firstDash
))
-
1900
;
if
((
firstDash
>
0
)
&&
(
secondDash
>
0
)
&&
(
secondDash
<
s
.
length
()
-
1
))
{
month
=
Integer
.
parseInt
(
s
.
substring
(
firstDash
+
1
,
secondDash
))
-
1
;
String
yyyy
=
s
.
substring
(
0
,
firstDash
);
day
=
Integer
.
parseInt
(
s
.
substring
(
secondDash
+
1
));
String
mm
=
s
.
substring
(
firstDash
+
1
,
secondDash
);
}
else
{
String
dd
=
s
.
substring
(
secondDash
+
1
);
if
(
yyyy
.
length
()
==
YEAR_LENGTH
&&
mm
.
length
()
==
MONTH_LENGTH
&&
dd
.
length
()
==
DAY_LENGTH
)
{
int
year
=
Integer
.
parseInt
(
yyyy
);
int
month
=
Integer
.
parseInt
(
mm
);
int
day
=
Integer
.
parseInt
(
dd
);
if
((
month
>=
1
&&
month
<=
MAX_MONTH
)
&&
(
day
>=
1
&&
day
<=
MAX_DAY
))
{
d
=
new
Date
(
year
-
1900
,
month
-
1
,
day
);
}
}
}
if
(
d
==
null
)
{
throw
new
java
.
lang
.
IllegalArgumentException
();
throw
new
java
.
lang
.
IllegalArgumentException
();
}
}
return
new
Date
(
year
,
month
,
day
);
return
d
;
}
}
/**
/**
* Formats a date in the date escape format yyyy-mm-dd.
* Formats a date in the date escape format yyyy-mm-dd.
* <P>
* <P>
...
...
src/share/classes/sun/net/www/protocol/file/FileURLConnection.java
浏览文件 @
130dc864
...
@@ -59,7 +59,7 @@ public class FileURLConnection extends URLConnection {
...
@@ -59,7 +59,7 @@ public class FileURLConnection extends URLConnection {
String
filename
;
String
filename
;
boolean
isDirectory
=
false
;
boolean
isDirectory
=
false
;
boolean
exists
=
false
;
boolean
exists
=
false
;
List
files
;
List
<
String
>
files
;
long
length
=
-
1
;
long
length
=
-
1
;
long
lastModified
=
0
;
long
lastModified
=
0
;
...
@@ -81,7 +81,10 @@ public class FileURLConnection extends URLConnection {
...
@@ -81,7 +81,10 @@ public class FileURLConnection extends URLConnection {
filename
=
file
.
toString
();
filename
=
file
.
toString
();
isDirectory
=
file
.
isDirectory
();
isDirectory
=
file
.
isDirectory
();
if
(
isDirectory
)
{
if
(
isDirectory
)
{
files
=
(
List
)
Arrays
.
asList
(
file
.
list
());
String
[]
fileList
=
file
.
list
();
if
(
fileList
==
null
)
throw
new
FileNotFoundException
(
filename
+
" exists, but is not accessible"
);
files
=
Arrays
.<
String
>
asList
(
fileList
);
}
else
{
}
else
{
is
=
new
BufferedInputStream
(
new
FileInputStream
(
filename
));
is
=
new
BufferedInputStream
(
new
FileInputStream
(
filename
));
...
@@ -197,7 +200,7 @@ public class FileURLConnection extends URLConnection {
...
@@ -197,7 +200,7 @@ public class FileURLConnection extends URLConnection {
Collections
.
sort
(
files
,
Collator
.
getInstance
());
Collections
.
sort
(
files
,
Collator
.
getInstance
());
for
(
int
i
=
0
;
i
<
files
.
size
()
;
i
++)
{
for
(
int
i
=
0
;
i
<
files
.
size
()
;
i
++)
{
String
fileName
=
(
String
)
files
.
get
(
i
);
String
fileName
=
files
.
get
(
i
);
buf
.
append
(
fileName
);
buf
.
append
(
fileName
);
buf
.
append
(
"\n"
);
buf
.
append
(
"\n"
);
}
}
...
...
src/share/classes/sun/net/www/protocol/http/HttpURLConnection.java
浏览文件 @
130dc864
...
@@ -1768,6 +1768,10 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
...
@@ -1768,6 +1768,10 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
// Not really necessary for a tunnel, but can't hurt
// Not really necessary for a tunnel, but can't hurt
requests
.
setIfNotSet
(
"Accept"
,
acceptString
);
requests
.
setIfNotSet
(
"Accept"
,
acceptString
);
if
(
http
.
getHttpKeepAliveSet
())
{
requests
.
setIfNotSet
(
"Proxy-Connection"
,
"keep-alive"
);
}
setPreemptiveProxyAuthentication
(
requests
);
setPreemptiveProxyAuthentication
(
requests
);
/* Log the CONNECT request */
/* Log the CONNECT request */
...
...
src/share/classes/sun/nio/ch/DatagramChannelImpl.java
浏览文件 @
130dc864
...
@@ -536,9 +536,11 @@ class DatagramChannelImpl
...
@@ -536,9 +536,11 @@ class DatagramChannelImpl
}
}
}
}
private
long
read0
(
ByteBuffer
[]
bufs
)
throws
IOException
{
public
long
read
(
ByteBuffer
[]
dsts
,
int
offset
,
int
length
)
if
(
bufs
==
null
)
throws
IOException
throw
new
NullPointerException
();
{
if
((
offset
<
0
)
||
(
length
<
0
)
||
(
offset
>
dsts
.
length
-
length
))
throw
new
IndexOutOfBoundsException
();
synchronized
(
readLock
)
{
synchronized
(
readLock
)
{
synchronized
(
stateLock
)
{
synchronized
(
stateLock
)
{
ensureOpen
();
ensureOpen
();
...
@@ -552,7 +554,7 @@ class DatagramChannelImpl
...
@@ -552,7 +554,7 @@ class DatagramChannelImpl
return
0
;
return
0
;
readerThread
=
NativeThread
.
current
();
readerThread
=
NativeThread
.
current
();
do
{
do
{
n
=
IOUtil
.
read
(
fd
,
bufs
,
nd
);
n
=
IOUtil
.
read
(
fd
,
dsts
,
offset
,
length
,
nd
);
}
while
((
n
==
IOStatus
.
INTERRUPTED
)
&&
isOpen
());
}
while
((
n
==
IOStatus
.
INTERRUPTED
)
&&
isOpen
());
return
IOStatus
.
normalize
(
n
);
return
IOStatus
.
normalize
(
n
);
}
finally
{
}
finally
{
...
@@ -563,15 +565,6 @@ class DatagramChannelImpl
...
@@ -563,15 +565,6 @@ class DatagramChannelImpl
}
}
}
}
public
long
read
(
ByteBuffer
[]
dsts
,
int
offset
,
int
length
)
throws
IOException
{
if
((
offset
<
0
)
||
(
length
<
0
)
||
(
offset
>
dsts
.
length
-
length
))
throw
new
IndexOutOfBoundsException
();
// ## Fix IOUtil.write so that we can avoid this array copy
return
read0
(
Util
.
subsequence
(
dsts
,
offset
,
length
));
}
public
int
write
(
ByteBuffer
buf
)
throws
IOException
{
public
int
write
(
ByteBuffer
buf
)
throws
IOException
{
if
(
buf
==
null
)
if
(
buf
==
null
)
throw
new
NullPointerException
();
throw
new
NullPointerException
();
...
@@ -599,9 +592,11 @@ class DatagramChannelImpl
...
@@ -599,9 +592,11 @@ class DatagramChannelImpl
}
}
}
}
private
long
write0
(
ByteBuffer
[]
bufs
)
throws
IOException
{
public
long
write
(
ByteBuffer
[]
srcs
,
int
offset
,
int
length
)
if
(
bufs
==
null
)
throws
IOException
throw
new
NullPointerException
();
{
if
((
offset
<
0
)
||
(
length
<
0
)
||
(
offset
>
srcs
.
length
-
length
))
throw
new
IndexOutOfBoundsException
();
synchronized
(
writeLock
)
{
synchronized
(
writeLock
)
{
synchronized
(
stateLock
)
{
synchronized
(
stateLock
)
{
ensureOpen
();
ensureOpen
();
...
@@ -615,7 +610,7 @@ class DatagramChannelImpl
...
@@ -615,7 +610,7 @@ class DatagramChannelImpl
return
0
;
return
0
;
writerThread
=
NativeThread
.
current
();
writerThread
=
NativeThread
.
current
();
do
{
do
{
n
=
IOUtil
.
write
(
fd
,
bufs
,
nd
);
n
=
IOUtil
.
write
(
fd
,
srcs
,
offset
,
length
,
nd
);
}
while
((
n
==
IOStatus
.
INTERRUPTED
)
&&
isOpen
());
}
while
((
n
==
IOStatus
.
INTERRUPTED
)
&&
isOpen
());
return
IOStatus
.
normalize
(
n
);
return
IOStatus
.
normalize
(
n
);
}
finally
{
}
finally
{
...
@@ -626,15 +621,6 @@ class DatagramChannelImpl
...
@@ -626,15 +621,6 @@ class DatagramChannelImpl
}
}
}
}
public
long
write
(
ByteBuffer
[]
srcs
,
int
offset
,
int
length
)
throws
IOException
{
if
((
offset
<
0
)
||
(
length
<
0
)
||
(
offset
>
srcs
.
length
-
length
))
throw
new
IndexOutOfBoundsException
();
// ## Fix IOUtil.write so that we can avoid this array copy
return
write0
(
Util
.
subsequence
(
srcs
,
offset
,
length
));
}
protected
void
implConfigureBlocking
(
boolean
block
)
throws
IOException
{
protected
void
implConfigureBlocking
(
boolean
block
)
throws
IOException
{
IOUtil
.
configureBlocking
(
fd
,
block
);
IOUtil
.
configureBlocking
(
fd
,
block
);
}
}
...
...
src/share/classes/sun/nio/ch/FileChannelImpl.java
浏览文件 @
130dc864
...
@@ -143,7 +143,11 @@ public class FileChannelImpl
...
@@ -143,7 +143,11 @@ public class FileChannelImpl
}
}
}
}
private
long
read0
(
ByteBuffer
[]
dsts
)
throws
IOException
{
public
long
read
(
ByteBuffer
[]
dsts
,
int
offset
,
int
length
)
throws
IOException
{
if
((
offset
<
0
)
||
(
length
<
0
)
||
(
offset
>
dsts
.
length
-
length
))
throw
new
IndexOutOfBoundsException
();
ensureOpen
();
ensureOpen
();
if
(!
readable
)
if
(!
readable
)
throw
new
NonReadableChannelException
();
throw
new
NonReadableChannelException
();
...
@@ -156,7 +160,7 @@ public class FileChannelImpl
...
@@ -156,7 +160,7 @@ public class FileChannelImpl
if
(!
isOpen
())
if
(!
isOpen
())
return
0
;
return
0
;
do
{
do
{
n
=
IOUtil
.
read
(
fd
,
dsts
,
nd
);
n
=
IOUtil
.
read
(
fd
,
dsts
,
offset
,
length
,
nd
);
}
while
((
n
==
IOStatus
.
INTERRUPTED
)
&&
isOpen
());
}
while
((
n
==
IOStatus
.
INTERRUPTED
)
&&
isOpen
());
return
IOStatus
.
normalize
(
n
);
return
IOStatus
.
normalize
(
n
);
}
finally
{
}
finally
{
...
@@ -167,15 +171,6 @@ public class FileChannelImpl
...
@@ -167,15 +171,6 @@ public class FileChannelImpl
}
}
}
}
public
long
read
(
ByteBuffer
[]
dsts
,
int
offset
,
int
length
)
throws
IOException
{
if
((
offset
<
0
)
||
(
length
<
0
)
||
(
offset
>
dsts
.
length
-
length
))
throw
new
IndexOutOfBoundsException
();
// ## Fix IOUtil.write so that we can avoid this array copy
return
read0
(
Util
.
subsequence
(
dsts
,
offset
,
length
));
}
public
int
write
(
ByteBuffer
src
)
throws
IOException
{
public
int
write
(
ByteBuffer
src
)
throws
IOException
{
ensureOpen
();
ensureOpen
();
if
(!
writable
)
if
(!
writable
)
...
@@ -200,7 +195,11 @@ public class FileChannelImpl
...
@@ -200,7 +195,11 @@ public class FileChannelImpl
}
}
}
}
private
long
write0
(
ByteBuffer
[]
srcs
)
throws
IOException
{
public
long
write
(
ByteBuffer
[]
srcs
,
int
offset
,
int
length
)
throws
IOException
{
if
((
offset
<
0
)
||
(
length
<
0
)
||
(
offset
>
srcs
.
length
-
length
))
throw
new
IndexOutOfBoundsException
();
ensureOpen
();
ensureOpen
();
if
(!
writable
)
if
(!
writable
)
throw
new
NonWritableChannelException
();
throw
new
NonWritableChannelException
();
...
@@ -213,7 +212,7 @@ public class FileChannelImpl
...
@@ -213,7 +212,7 @@ public class FileChannelImpl
if
(!
isOpen
())
if
(!
isOpen
())
return
0
;
return
0
;
do
{
do
{
n
=
IOUtil
.
write
(
fd
,
srcs
,
nd
);
n
=
IOUtil
.
write
(
fd
,
srcs
,
offset
,
length
,
nd
);
}
while
((
n
==
IOStatus
.
INTERRUPTED
)
&&
isOpen
());
}
while
((
n
==
IOStatus
.
INTERRUPTED
)
&&
isOpen
());
return
IOStatus
.
normalize
(
n
);
return
IOStatus
.
normalize
(
n
);
}
finally
{
}
finally
{
...
@@ -224,16 +223,6 @@ public class FileChannelImpl
...
@@ -224,16 +223,6 @@ public class FileChannelImpl
}
}
}
}
public
long
write
(
ByteBuffer
[]
srcs
,
int
offset
,
int
length
)
throws
IOException
{
if
((
offset
<
0
)
||
(
length
<
0
)
||
(
offset
>
srcs
.
length
-
length
))
throw
new
IndexOutOfBoundsException
();
// ## Fix IOUtil.write so that we can avoid this array copy
return
write0
(
Util
.
subsequence
(
srcs
,
offset
,
length
));
}
// -- Other operations --
// -- Other operations --
public
long
position
()
throws
IOException
{
public
long
position
()
throws
IOException
{
...
@@ -440,24 +429,45 @@ public class FileChannelImpl
...
@@ -440,24 +429,45 @@ public class FileChannelImpl
}
}
}
}
private
long
transferToTrustedChannel
(
long
position
,
int
icount
,
// Maximum size to map when using a mapped buffer
private
static
final
long
MAPPED_TRANSFER_SIZE
=
8L
*
1024L
*
1024L
;
private
long
transferToTrustedChannel
(
long
position
,
long
count
,
WritableByteChannel
target
)
WritableByteChannel
target
)
throws
IOException
throws
IOException
{
{
if
(
!((
target
instanceof
FileChannelImpl
)
boolean
isSelChImpl
=
(
target
instanceof
SelChImpl
);
||
(
target
instanceof
SelChImpl
)
))
if
(!((
target
instanceof
FileChannelImpl
)
||
isSelChImpl
))
return
IOStatus
.
UNSUPPORTED
;
return
IOStatus
.
UNSUPPORTED
;
// Trusted target: Use a mapped buffer
// Trusted target: Use a mapped buffer
MappedByteBuffer
dbb
=
null
;
long
remaining
=
count
;
try
{
while
(
remaining
>
0L
)
{
dbb
=
map
(
MapMode
.
READ_ONLY
,
position
,
icount
);
long
size
=
Math
.
min
(
remaining
,
MAPPED_TRANSFER_SIZE
);
// ## Bug: Closing this channel will not terminate the write
try
{
return
target
.
write
(
dbb
);
MappedByteBuffer
dbb
=
map
(
MapMode
.
READ_ONLY
,
position
,
size
);
}
finally
{
try
{
if
(
dbb
!=
null
)
// ## Bug: Closing this channel will not terminate the write
unmap
(
dbb
);
int
n
=
target
.
write
(
dbb
);
assert
n
>=
0
;
remaining
-=
n
;
if
(
isSelChImpl
)
{
// one attempt to write to selectable channel
break
;
}
assert
n
>
0
;
position
+=
n
;
}
finally
{
unmap
(
dbb
);
}
}
catch
(
IOException
ioe
)
{
// Only throw exception if no bytes have been written
if
(
remaining
==
count
)
throw
ioe
;
break
;
}
}
}
return
count
-
remaining
;
}
}
private
long
transferToArbitraryChannel
(
long
position
,
int
icount
,
private
long
transferToArbitraryChannel
(
long
position
,
int
icount
,
...
@@ -535,20 +545,34 @@ public class FileChannelImpl
...
@@ -535,20 +545,34 @@ public class FileChannelImpl
long
position
,
long
count
)
long
position
,
long
count
)
throws
IOException
throws
IOException
{
{
// Note we could loop here to accumulate more at once
synchronized
(
src
.
positionLock
)
{
synchronized
(
src
.
positionLock
)
{
long
p
=
src
.
position
();
long
pos
=
src
.
position
();
int
icount
=
(
int
)
Math
.
min
(
Math
.
min
(
count
,
Integer
.
MAX_VALUE
),
long
max
=
Math
.
min
(
count
,
src
.
size
()
-
pos
);
src
.
size
()
-
p
);
// ## Bug: Closing this channel will not terminate the write
long
remaining
=
max
;
MappedByteBuffer
bb
=
src
.
map
(
MapMode
.
READ_ONLY
,
p
,
icount
);
long
p
=
pos
;
try
{
while
(
remaining
>
0L
)
{
long
n
=
write
(
bb
,
position
);
long
size
=
Math
.
min
(
remaining
,
MAPPED_TRANSFER_SIZE
);
src
.
position
(
p
+
n
);
// ## Bug: Closing this channel will not terminate the write
return
n
;
MappedByteBuffer
bb
=
src
.
map
(
MapMode
.
READ_ONLY
,
p
,
size
);
}
finally
{
try
{
unmap
(
bb
);
long
n
=
write
(
bb
,
position
);
assert
n
>
0
;
p
+=
n
;
position
+=
n
;
remaining
-=
n
;
}
catch
(
IOException
ioe
)
{
// Only throw exception if no bytes have been written
if
(
remaining
==
max
)
throw
ioe
;
break
;
}
finally
{
unmap
(
bb
);
}
}
}
long
nwritten
=
max
-
remaining
;
src
.
position
(
pos
+
nwritten
);
return
nwritten
;
}
}
}
}
...
...
src/share/classes/sun/nio/ch/IOUtil.java
浏览文件 @
130dc864
...
@@ -38,34 +38,6 @@ class IOUtil {
...
@@ -38,34 +38,6 @@ class IOUtil {
private
IOUtil
()
{
}
// No instantiation
private
IOUtil
()
{
}
// No instantiation
/*
* Returns the index of first buffer in bufs with remaining,
* or -1 if there is nothing left
*/
private
static
int
remaining
(
ByteBuffer
[]
bufs
)
{
int
numBufs
=
bufs
.
length
;
for
(
int
i
=
0
;
i
<
numBufs
;
i
++)
{
if
(
bufs
[
i
].
hasRemaining
())
{
return
i
;
}
}
return
-
1
;
}
/*
* Returns a new ByteBuffer array with only unfinished buffers in it
*/
private
static
ByteBuffer
[]
skipBufs
(
ByteBuffer
[]
bufs
,
int
nextWithRemaining
)
{
int
newSize
=
bufs
.
length
-
nextWithRemaining
;
ByteBuffer
[]
temp
=
new
ByteBuffer
[
newSize
];
for
(
int
i
=
0
;
i
<
newSize
;
i
++)
{
temp
[
i
]
=
bufs
[
i
+
nextWithRemaining
];
}
return
temp
;
}
static
int
write
(
FileDescriptor
fd
,
ByteBuffer
src
,
long
position
,
static
int
write
(
FileDescriptor
fd
,
ByteBuffer
src
,
long
position
,
NativeDispatcher
nd
,
Object
lock
)
NativeDispatcher
nd
,
Object
lock
)
throws
IOException
throws
IOException
...
@@ -93,7 +65,7 @@ class IOUtil {
...
@@ -93,7 +65,7 @@ class IOUtil {
}
}
return
n
;
return
n
;
}
finally
{
}
finally
{
Util
.
release
TemporaryDirectBuffer
(
bb
);
Util
.
offerFirst
TemporaryDirectBuffer
(
bb
);
}
}
}
}
...
@@ -125,88 +97,81 @@ class IOUtil {
...
@@ -125,88 +97,81 @@ class IOUtil {
static
long
write
(
FileDescriptor
fd
,
ByteBuffer
[]
bufs
,
NativeDispatcher
nd
)
static
long
write
(
FileDescriptor
fd
,
ByteBuffer
[]
bufs
,
NativeDispatcher
nd
)
throws
IOException
throws
IOException
{
{
int
nextWithRemaining
=
remaining
(
bufs
);
return
write
(
fd
,
bufs
,
0
,
bufs
.
length
,
nd
);
// if all bufs are empty we should return immediately
}
if
(
nextWithRemaining
<
0
)
return
0
;
// If some bufs are empty we should skip them
if
(
nextWithRemaining
>
0
)
bufs
=
skipBufs
(
bufs
,
nextWithRemaining
);
int
numBufs
=
bufs
.
length
;
static
long
write
(
FileDescriptor
fd
,
ByteBuffer
[]
bufs
,
int
offset
,
int
length
,
NativeDispatcher
nd
)
throws
IOException
{
IOVecWrapper
vec
=
IOVecWrapper
.
get
(
length
);
// Create shadow to ensure DirectByteBuffers are used
boolean
completed
=
false
;
ByteBuffer
[]
shadow
=
new
ByteBuffer
[
numBufs
]
;
int
iov_len
=
0
;
try
{
try
{
for
(
int
i
=
0
;
i
<
numBufs
;
i
++)
{
if
(!(
bufs
[
i
]
instanceof
DirectBuffer
))
{
int
pos
=
bufs
[
i
].
position
();
int
lim
=
bufs
[
i
].
limit
();
assert
(
pos
<=
lim
);
int
rem
=
(
pos
<=
lim
?
lim
-
pos
:
0
);
ByteBuffer
bb
=
Util
.
getTemporaryDirectBuffer
(
rem
);
shadow
[
i
]
=
bb
;
// Leave slow buffer position untouched; it will be updated
// after we see how many bytes were really written out
bb
.
put
(
bufs
[
i
]);
bufs
[
i
].
position
(
pos
);
bb
.
flip
();
}
else
{
shadow
[
i
]
=
bufs
[
i
];
}
}
IOVecWrapper
vec
=
null
;
// Iterate over buffers to populate native iovec array.
long
bytesWritten
=
0
;
int
count
=
offset
+
length
;
try
{
for
(
int
i
=
offset
;
i
<
count
;
i
++)
{
// Create a native iovec array
ByteBuffer
buf
=
bufs
[
i
];
vec
=
new
IOVecWrapper
(
numBufs
);
int
pos
=
buf
.
position
();
int
lim
=
buf
.
limit
();
// Fill in the iovec array with appropriate data
assert
(
pos
<=
lim
);
for
(
int
i
=
0
;
i
<
numBufs
;
i
++)
{
int
rem
=
(
pos
<=
lim
?
lim
-
pos
:
0
);
ByteBuffer
nextBuffer
=
shadow
[
i
];
if
(
rem
>
0
)
{
// put in the buffer addresses
vec
.
setBuffer
(
iov_len
,
buf
,
pos
,
rem
);
long
pos
=
nextBuffer
.
position
();
long
len
=
nextBuffer
.
limit
()
-
pos
;
// allocate shadow buffer to ensure I/O is done with direct buffer
vec
.
putBase
(
i
,
((
DirectBuffer
)
nextBuffer
).
address
()
+
pos
);
if
(!(
buf
instanceof
DirectBuffer
))
{
vec
.
putLen
(
i
,
len
);
ByteBuffer
shadow
=
Util
.
getTemporaryDirectBuffer
(
rem
);
}
shadow
.
put
(
buf
);
shadow
.
flip
();
vec
.
setShadow
(
iov_len
,
shadow
);
buf
.
position
(
pos
);
// temporarily restore position in user buffer
buf
=
shadow
;
pos
=
shadow
.
position
();
}
// Invoke native call to fill the buffers
vec
.
putBase
(
iov_len
,
((
DirectBuffer
)
buf
).
address
()
+
pos
);
bytesWritten
=
nd
.
writev
(
fd
,
vec
.
address
,
numBufs
);
vec
.
putLen
(
iov_len
,
rem
);
}
finally
{
iov_len
++;
vec
.
free
();
}
}
}
long
returnVal
=
bytesWritten
;
if
(
iov_len
==
0
)
return
0L
;
long
bytesWritten
=
nd
.
writev
(
fd
,
vec
.
address
,
iov_len
);
// Notify the buffers how many bytes were taken
// Notify the buffers how many bytes were taken
for
(
int
i
=
0
;
i
<
numBufs
;
i
++)
{
long
left
=
bytesWritten
;
ByteBuffer
nextBuffer
=
bufs
[
i
];
for
(
int
j
=
0
;
j
<
iov_len
;
j
++)
{
int
pos
=
nextBuffer
.
position
();
if
(
left
>
0
)
{
int
lim
=
nextBuffer
.
limit
();
ByteBuffer
buf
=
vec
.
getBuffer
(
j
);
assert
(
pos
<=
lim
);
int
pos
=
vec
.
getPosition
(
j
);
int
len
=
(
pos
<=
lim
?
lim
-
pos
:
lim
);
int
rem
=
vec
.
getRemaining
(
j
);
if
(
bytesWritten
>=
len
)
{
int
n
=
(
left
>
rem
)
?
rem
:
(
int
)
left
;
bytesWritten
-=
len
;
buf
.
position
(
pos
+
n
);
int
newPosition
=
pos
+
len
;
left
-=
n
;
nextBuffer
.
position
(
newPosition
);
}
else
{
// Buffers not completely filled
if
(
bytesWritten
>
0
)
{
assert
(
pos
+
bytesWritten
<
(
long
)
Integer
.
MAX_VALUE
);
int
newPosition
=
(
int
)(
pos
+
bytesWritten
);
nextBuffer
.
position
(
newPosition
);
}
break
;
}
}
// return shadow buffers to buffer pool
ByteBuffer
shadow
=
vec
.
getShadow
(
j
);
if
(
shadow
!=
null
)
Util
.
offerLastTemporaryDirectBuffer
(
shadow
);
vec
.
clearRefs
(
j
);
}
}
return
returnVal
;
completed
=
true
;
return
bytesWritten
;
}
finally
{
}
finally
{
// return any substituted buffers to cache
// if an error occurred then clear refs to buffers and return any shadow
for
(
int
i
=
0
;
i
<
numBufs
;
i
++)
{
// buffers to cache
ByteBuffer
bb
=
shadow
[
i
];
if
(!
completed
)
{
if
(
bb
!=
null
&&
bb
!=
bufs
[
i
])
{
for
(
int
j
=
0
;
j
<
iov_len
;
j
++)
{
Util
.
releaseTemporaryDirectBuffer
(
bb
);
ByteBuffer
shadow
=
vec
.
getShadow
(
j
);
if
(
shadow
!=
null
)
Util
.
offerLastTemporaryDirectBuffer
(
shadow
);
vec
.
clearRefs
(
j
);
}
}
}
}
}
}
...
@@ -231,7 +196,7 @@ class IOUtil {
...
@@ -231,7 +196,7 @@ class IOUtil {
dst
.
put
(
bb
);
dst
.
put
(
bb
);
return
n
;
return
n
;
}
finally
{
}
finally
{
Util
.
release
TemporaryDirectBuffer
(
bb
);
Util
.
offerFirst
TemporaryDirectBuffer
(
bb
);
}
}
}
}
...
@@ -262,92 +227,85 @@ class IOUtil {
...
@@ -262,92 +227,85 @@ class IOUtil {
static
long
read
(
FileDescriptor
fd
,
ByteBuffer
[]
bufs
,
NativeDispatcher
nd
)
static
long
read
(
FileDescriptor
fd
,
ByteBuffer
[]
bufs
,
NativeDispatcher
nd
)
throws
IOException
throws
IOException
{
{
int
nextWithRemaining
=
remaining
(
bufs
);
return
read
(
fd
,
bufs
,
0
,
bufs
.
length
,
nd
);
// if all bufs are empty we should return immediately
}
if
(
nextWithRemaining
<
0
)
return
0
;
// If some bufs are empty we should skip them
if
(
nextWithRemaining
>
0
)
bufs
=
skipBufs
(
bufs
,
nextWithRemaining
);
int
numBufs
=
bufs
.
length
;
static
long
read
(
FileDescriptor
fd
,
ByteBuffer
[]
bufs
,
int
offset
,
int
length
,
NativeDispatcher
nd
)
throws
IOException
{
IOVecWrapper
vec
=
IOVecWrapper
.
get
(
length
);
// Read into the shadow to ensure DirectByteBuffers are used
boolean
completed
=
false
;
ByteBuffer
[]
shadow
=
new
ByteBuffer
[
numBufs
];
int
iov_len
=
0
;
boolean
usingSlowBuffers
=
false
;
try
{
try
{
for
(
int
i
=
0
;
i
<
numBufs
;
i
++)
{
if
(
bufs
[
i
].
isReadOnly
())
throw
new
IllegalArgumentException
(
"Read-only buffer"
);
if
(!(
bufs
[
i
]
instanceof
DirectBuffer
))
{
shadow
[
i
]
=
Util
.
getTemporaryDirectBuffer
(
bufs
[
i
].
remaining
());
usingSlowBuffers
=
true
;
}
else
{
shadow
[
i
]
=
bufs
[
i
];
}
}
IOVecWrapper
vec
=
null
;
// Iterate over buffers to populate native iovec array.
long
bytesRead
=
0
;
int
count
=
offset
+
length
;
try
{
for
(
int
i
=
offset
;
i
<
count
;
i
++)
{
// Create a native iovec array
ByteBuffer
buf
=
bufs
[
i
];
vec
=
new
IOVecWrapper
(
numBufs
);
if
(
buf
.
isReadOnly
())
throw
new
IllegalArgumentException
(
"Read-only buffer"
);
// Fill in the iovec array with appropriate data
int
pos
=
buf
.
position
();
for
(
int
i
=
0
;
i
<
numBufs
;
i
++)
{
int
lim
=
buf
.
limit
();
ByteBuffer
nextBuffer
=
shadow
[
i
];
assert
(
pos
<=
lim
);
// put in the buffer addresses
int
rem
=
(
pos
<=
lim
?
lim
-
pos
:
0
);
long
pos
=
nextBuffer
.
position
();
long
len
=
nextBuffer
.
remaining
();
vec
.
putBase
(
i
,
((
DirectBuffer
)
nextBuffer
).
address
()
+
pos
);
vec
.
putLen
(
i
,
len
);
}
// Invoke native call to fill the buffers
if
(
rem
>
0
)
{
bytesRead
=
nd
.
readv
(
fd
,
vec
.
address
,
numBufs
);
vec
.
setBuffer
(
iov_len
,
buf
,
pos
,
rem
);
}
finally
{
vec
.
free
();
}
long
returnVal
=
bytesRead
;
// Notify the buffers how many bytes were read
// allocate shadow buffer to ensure I/O is done with direct buffer
for
(
int
i
=
0
;
i
<
numBufs
;
i
++)
{
if
(!(
buf
instanceof
DirectBuffer
))
{
ByteBuffer
nextBuffer
=
shadow
[
i
];
ByteBuffer
shadow
=
Util
.
getTemporaryDirectBuffer
(
rem
);
// Note: should this have been cached from above?
vec
.
setShadow
(
iov_len
,
shadow
);
int
pos
=
nextBuffer
.
position
();
buf
=
shadow
;
int
len
=
nextBuffer
.
remaining
();
pos
=
shadow
.
position
();
if
(
bytesRead
>=
len
)
{
bytesRead
-=
len
;
int
newPosition
=
pos
+
len
;
nextBuffer
.
position
(
newPosition
);
}
else
{
// Buffers not completely filled
if
(
bytesRead
>
0
)
{
assert
(
pos
+
bytesRead
<
(
long
)
Integer
.
MAX_VALUE
);
int
newPosition
=
(
int
)(
pos
+
bytesRead
);
nextBuffer
.
position
(
newPosition
);
}
}
break
;
vec
.
putBase
(
iov_len
,
((
DirectBuffer
)
buf
).
address
()
+
pos
);
vec
.
putLen
(
iov_len
,
rem
);
iov_len
++;
}
}
}
}
if
(
iov_len
==
0
)
return
0L
;
// Put results from shadow into the slow buffers
long
bytesRead
=
nd
.
readv
(
fd
,
vec
.
address
,
iov_len
);
if
(
usingSlowBuffers
)
{
for
(
int
i
=
0
;
i
<
numBufs
;
i
++)
{
// Notify the buffers how many bytes were read
if
(!(
bufs
[
i
]
instanceof
DirectBuffer
))
{
long
left
=
bytesRead
;
shadow
[
i
].
flip
();
for
(
int
j
=
0
;
j
<
iov_len
;
j
++)
{
bufs
[
i
].
put
(
shadow
[
i
]);
ByteBuffer
shadow
=
vec
.
getShadow
(
j
);
if
(
left
>
0
)
{
ByteBuffer
buf
=
vec
.
getBuffer
(
j
);
int
rem
=
vec
.
getRemaining
(
j
);
int
n
=
(
left
>
rem
)
?
rem
:
(
int
)
left
;
if
(
shadow
==
null
)
{
int
pos
=
vec
.
getPosition
(
j
);
buf
.
position
(
pos
+
n
);
}
else
{
shadow
.
limit
(
shadow
.
position
()
+
n
);
buf
.
put
(
shadow
);
}
}
left
-=
n
;
}
}
if
(
shadow
!=
null
)
Util
.
offerLastTemporaryDirectBuffer
(
shadow
);
vec
.
clearRefs
(
j
);
}
}
return
returnVal
;
completed
=
true
;
return
bytesRead
;
}
finally
{
}
finally
{
// return any substituted buffers to cache
// if an error occurred then clear refs to buffers and return any shadow
if
(
usingSlowBuffers
)
{
// buffers to cache
for
(
int
i
=
0
;
i
<
numBufs
;
i
++)
{
if
(!
completed
)
{
ByteBuffer
bb
=
shadow
[
i
];
for
(
int
j
=
0
;
j
<
iov_len
;
j
++)
{
if
(
bb
!=
null
&&
bb
!=
bufs
[
i
])
{
ByteBuffer
shadow
=
vec
.
getShadow
(
j
);
Util
.
releaseTemporaryDirectBuffer
(
bb
);
if
(
shadow
!=
null
)
}
Util
.
offerLastTemporaryDirectBuffer
(
shadow
);
vec
.
clearRefs
(
j
);
}
}
}
}
}
}
...
...
src/share/classes/sun/nio/ch/IOVecWrapper.java
浏览文件 @
130dc864
...
@@ -25,6 +25,7 @@
...
@@ -25,6 +25,7 @@
package
sun.nio.ch
;
package
sun.nio.ch
;
import
java.nio.ByteBuffer
;
import
sun.misc.*
;
import
sun.misc.*
;
...
@@ -43,23 +44,98 @@ import sun.misc.*;
...
@@ -43,23 +44,98 @@ import sun.misc.*;
class
IOVecWrapper
{
class
IOVecWrapper
{
// Miscellaneous constants
// Miscellaneous constants
static
int
BASE_OFFSET
=
0
;
private
static
final
int
BASE_OFFSET
=
0
;
static
int
LEN_OFFSET
;
private
static
final
int
LEN_OFFSET
;
static
int
SIZE_IOVEC
;
private
static
final
int
SIZE_IOVEC
;
// The iovec array
// The iovec array
private
AllocatedNativeObject
vecArray
;
private
final
AllocatedNativeObject
vecArray
;
// Number of elements in iovec array
private
final
int
size
;
// Buffers and position/remaining corresponding to elements in iovec array
private
final
ByteBuffer
[]
buf
;
private
final
int
[]
position
;
private
final
int
[]
remaining
;
// Shadow buffers for cases when original buffer is substituted
private
final
ByteBuffer
[]
shadow
;
// Base address of this array
// Base address of this array
long
address
;
final
long
address
;
// Address size in bytes
// Address size in bytes
static
int
addressSize
;
static
int
addressSize
;
IOVecWrapper
(
int
newSize
)
{
private
static
class
Deallocator
implements
Runnable
{
newSize
=
(
newSize
+
1
)
*
SIZE_IOVEC
;
private
final
AllocatedNativeObject
obj
;
vecArray
=
new
AllocatedNativeObject
(
newSize
,
false
);
Deallocator
(
AllocatedNativeObject
obj
)
{
address
=
vecArray
.
address
();
this
.
obj
=
obj
;
}
public
void
run
()
{
obj
.
free
();
}
}
// per thread IOVecWrapper
private
static
final
ThreadLocal
<
IOVecWrapper
>
cached
=
new
ThreadLocal
<
IOVecWrapper
>();
private
IOVecWrapper
(
int
size
)
{
this
.
size
=
size
;
this
.
buf
=
new
ByteBuffer
[
size
];
this
.
position
=
new
int
[
size
];
this
.
remaining
=
new
int
[
size
];
this
.
shadow
=
new
ByteBuffer
[
size
];
this
.
vecArray
=
new
AllocatedNativeObject
(
size
*
SIZE_IOVEC
,
false
);
this
.
address
=
vecArray
.
address
();
}
static
IOVecWrapper
get
(
int
size
)
{
IOVecWrapper
wrapper
=
cached
.
get
();
if
(
wrapper
!=
null
&&
wrapper
.
size
<
size
)
{
// not big enough; eagerly release memory
wrapper
.
vecArray
.
free
();
wrapper
=
null
;
}
if
(
wrapper
==
null
)
{
wrapper
=
new
IOVecWrapper
(
size
);
Cleaner
.
create
(
wrapper
,
new
Deallocator
(
wrapper
.
vecArray
));
cached
.
set
(
wrapper
);
}
return
wrapper
;
}
void
setBuffer
(
int
i
,
ByteBuffer
buf
,
int
pos
,
int
rem
)
{
this
.
buf
[
i
]
=
buf
;
this
.
position
[
i
]
=
pos
;
this
.
remaining
[
i
]
=
rem
;
}
void
setShadow
(
int
i
,
ByteBuffer
buf
)
{
shadow
[
i
]
=
buf
;
}
ByteBuffer
getBuffer
(
int
i
)
{
return
buf
[
i
];
}
int
getPosition
(
int
i
)
{
return
position
[
i
];
}
int
getRemaining
(
int
i
)
{
return
remaining
[
i
];
}
ByteBuffer
getShadow
(
int
i
)
{
return
shadow
[
i
];
}
void
clearRefs
(
int
i
)
{
buf
[
i
]
=
null
;
shadow
[
i
]
=
null
;
}
}
void
putBase
(
int
i
,
long
base
)
{
void
putBase
(
int
i
,
long
base
)
{
...
@@ -78,10 +154,6 @@ class IOVecWrapper {
...
@@ -78,10 +154,6 @@ class IOVecWrapper {
vecArray
.
putLong
(
offset
,
len
);
vecArray
.
putLong
(
offset
,
len
);
}
}
void
free
()
{
vecArray
.
free
();
}
static
{
static
{
addressSize
=
Util
.
unsafe
().
addressSize
();
addressSize
=
Util
.
unsafe
().
addressSize
();
LEN_OFFSET
=
addressSize
;
LEN_OFFSET
=
addressSize
;
...
...
src/share/classes/sun/nio/ch/SocketChannelImpl.java
浏览文件 @
130dc864
...
@@ -385,9 +385,11 @@ class SocketChannelImpl
...
@@ -385,9 +385,11 @@ class SocketChannelImpl
}
}
}
}
private
long
read0
(
ByteBuffer
[]
bufs
)
throws
IOException
{
public
long
read
(
ByteBuffer
[]
dsts
,
int
offset
,
int
length
)
if
(
bufs
==
null
)
throws
IOException
throw
new
NullPointerException
();
{
if
((
offset
<
0
)
||
(
length
<
0
)
||
(
offset
>
dsts
.
length
-
length
))
throw
new
IndexOutOfBoundsException
();
synchronized
(
readLock
)
{
synchronized
(
readLock
)
{
if
(!
ensureReadOpen
())
if
(!
ensureReadOpen
())
return
-
1
;
return
-
1
;
...
@@ -401,7 +403,7 @@ class SocketChannelImpl
...
@@ -401,7 +403,7 @@ class SocketChannelImpl
}
}
for
(;;)
{
for
(;;)
{
n
=
IOUtil
.
read
(
fd
,
bufs
,
nd
);
n
=
IOUtil
.
read
(
fd
,
dsts
,
offset
,
length
,
nd
);
if
((
n
==
IOStatus
.
INTERRUPTED
)
&&
isOpen
())
if
((
n
==
IOStatus
.
INTERRUPTED
)
&&
isOpen
())
continue
;
continue
;
return
IOStatus
.
normalize
(
n
);
return
IOStatus
.
normalize
(
n
);
...
@@ -418,15 +420,6 @@ class SocketChannelImpl
...
@@ -418,15 +420,6 @@ class SocketChannelImpl
}
}
}
}
public
long
read
(
ByteBuffer
[]
dsts
,
int
offset
,
int
length
)
throws
IOException
{
if
((
offset
<
0
)
||
(
length
<
0
)
||
(
offset
>
dsts
.
length
-
length
))
throw
new
IndexOutOfBoundsException
();
// ## Fix IOUtil.write so that we can avoid this array copy
return
read0
(
Util
.
subsequence
(
dsts
,
offset
,
length
));
}
public
int
write
(
ByteBuffer
buf
)
throws
IOException
{
public
int
write
(
ByteBuffer
buf
)
throws
IOException
{
if
(
buf
==
null
)
if
(
buf
==
null
)
throw
new
NullPointerException
();
throw
new
NullPointerException
();
...
@@ -458,9 +451,11 @@ class SocketChannelImpl
...
@@ -458,9 +451,11 @@ class SocketChannelImpl
}
}
}
}
public
long
write0
(
ByteBuffer
[]
bufs
)
throws
IOException
{
public
long
write
(
ByteBuffer
[]
srcs
,
int
offset
,
int
length
)
if
(
bufs
==
null
)
throws
IOException
throw
new
NullPointerException
();
{
if
((
offset
<
0
)
||
(
length
<
0
)
||
(
offset
>
srcs
.
length
-
length
))
throw
new
IndexOutOfBoundsException
();
synchronized
(
writeLock
)
{
synchronized
(
writeLock
)
{
ensureWriteOpen
();
ensureWriteOpen
();
long
n
=
0
;
long
n
=
0
;
...
@@ -472,7 +467,7 @@ class SocketChannelImpl
...
@@ -472,7 +467,7 @@ class SocketChannelImpl
writerThread
=
NativeThread
.
current
();
writerThread
=
NativeThread
.
current
();
}
}
for
(;;)
{
for
(;;)
{
n
=
IOUtil
.
write
(
fd
,
bufs
,
nd
);
n
=
IOUtil
.
write
(
fd
,
srcs
,
offset
,
length
,
nd
);
if
((
n
==
IOStatus
.
INTERRUPTED
)
&&
isOpen
())
if
((
n
==
IOStatus
.
INTERRUPTED
)
&&
isOpen
())
continue
;
continue
;
return
IOStatus
.
normalize
(
n
);
return
IOStatus
.
normalize
(
n
);
...
@@ -489,15 +484,6 @@ class SocketChannelImpl
...
@@ -489,15 +484,6 @@ class SocketChannelImpl
}
}
}
}
public
long
write
(
ByteBuffer
[]
srcs
,
int
offset
,
int
length
)
throws
IOException
{
if
((
offset
<
0
)
||
(
length
<
0
)
||
(
offset
>
srcs
.
length
-
length
))
throw
new
IndexOutOfBoundsException
();
// ## Fix IOUtil.write so that we can avoid this array copy
return
write0
(
Util
.
subsequence
(
srcs
,
offset
,
length
));
}
// package-private
// package-private
int
sendOutOfBandData
(
byte
b
)
throws
IOException
{
int
sendOutOfBandData
(
byte
b
)
throws
IOException
{
synchronized
(
writeLock
)
{
synchronized
(
writeLock
)
{
...
...
src/share/classes/sun/nio/ch/Util.java
浏览文件 @
130dc864
...
@@ -41,67 +41,180 @@ import sun.security.action.GetPropertyAction;
...
@@ -41,67 +41,180 @@ import sun.security.action.GetPropertyAction;
class
Util
{
class
Util
{
// -- Caches --
// -- Caches --
// The number of temp buffers in our pool
// The number of temp buffers in our pool
private
static
final
int
TEMP_BUF_POOL_SIZE
=
3
;
private
static
final
int
TEMP_BUF_POOL_SIZE
=
8
;
// Per-thread soft cache of the last temporary direct buffer
// Per-thread cache of temporary direct buffers
private
static
ThreadLocal
<
SoftReference
<
ByteBuffer
>>[]
bufferPool
;
private
static
ThreadLocal
<
BufferCache
>
bufferCache
=
new
ThreadLocal
<
BufferCache
>()
{
@Override
protected
BufferCache
initialValue
()
{
return
new
BufferCache
();
}
};
@SuppressWarnings
(
"unchecked"
)
/**
static
ThreadLocal
<
SoftReference
<
ByteBuffer
>>[]
createThreadLocalBufferPool
()
{
* A simple cache of direct buffers.
return
new
ThreadLocal
[
TEMP_BUF_POOL_SIZE
];
*/
}
private
static
class
BufferCache
{
// the array of buffers
private
ByteBuffer
[]
buffers
;
// the number of buffers in the cache
private
int
count
;
// the index of the first valid buffer (undefined if count == 0)
private
int
start
;
private
int
next
(
int
i
)
{
return
(
i
+
1
)
%
TEMP_BUF_POOL_SIZE
;
}
BufferCache
()
{
buffers
=
new
ByteBuffer
[
TEMP_BUF_POOL_SIZE
];
}
static
{
/**
bufferPool
=
createThreadLocalBufferPool
();
* Removes and returns a buffer from the cache of at least the given
for
(
int
i
=
0
;
i
<
TEMP_BUF_POOL_SIZE
;
i
++)
* size (or null if no suitable buffer is found).
bufferPool
[
i
]
=
new
ThreadLocal
<
SoftReference
<
ByteBuffer
>>();
*/
ByteBuffer
get
(
int
size
)
{
if
(
count
==
0
)
return
null
;
// cache is empty
ByteBuffer
[]
buffers
=
this
.
buffers
;
// search for suitable buffer (often the first buffer will do)
ByteBuffer
buf
=
buffers
[
start
];
if
(
buf
.
capacity
()
<
size
)
{
buf
=
null
;
int
i
=
start
;
while
((
i
=
next
(
i
))
!=
start
)
{
ByteBuffer
bb
=
buffers
[
i
];
if
(
bb
==
null
)
break
;
if
(
bb
.
capacity
()
>=
size
)
{
buf
=
bb
;
break
;
}
}
if
(
buf
==
null
)
return
null
;
// move first element to here to avoid re-packing
buffers
[
i
]
=
buffers
[
start
];
}
// remove first element
buffers
[
start
]
=
null
;
start
=
next
(
start
);
count
--;
// prepare the buffer and return it
buf
.
rewind
();
buf
.
limit
(
size
);
return
buf
;
}
boolean
offerFirst
(
ByteBuffer
buf
)
{
if
(
count
>=
TEMP_BUF_POOL_SIZE
)
{
return
false
;
}
else
{
start
=
(
start
+
TEMP_BUF_POOL_SIZE
-
1
)
%
TEMP_BUF_POOL_SIZE
;
buffers
[
start
]
=
buf
;
count
++;
return
true
;
}
}
boolean
offerLast
(
ByteBuffer
buf
)
{
if
(
count
>=
TEMP_BUF_POOL_SIZE
)
{
return
false
;
}
else
{
int
next
=
(
start
+
count
)
%
TEMP_BUF_POOL_SIZE
;
buffers
[
next
]
=
buf
;
count
++;
return
true
;
}
}
boolean
isEmpty
()
{
return
count
==
0
;
}
ByteBuffer
removeFirst
()
{
assert
count
>
0
;
ByteBuffer
buf
=
buffers
[
start
];
buffers
[
start
]
=
null
;
start
=
next
(
start
);
count
--;
return
buf
;
}
}
}
/**
* Returns a temporary buffer of at least the given size
*/
static
ByteBuffer
getTemporaryDirectBuffer
(
int
size
)
{
static
ByteBuffer
getTemporaryDirectBuffer
(
int
size
)
{
ByteBuffer
buf
=
null
;
BufferCache
cache
=
bufferCache
.
get
();
// Grab a buffer if available
ByteBuffer
buf
=
cache
.
get
(
size
);
for
(
int
i
=
0
;
i
<
TEMP_BUF_POOL_SIZE
;
i
++)
{
if
(
buf
!=
null
)
{
SoftReference
<
ByteBuffer
>
ref
=
bufferPool
[
i
].
get
();
return
buf
;
if
((
ref
!=
null
)
&&
((
buf
=
ref
.
get
())
!=
null
)
&&
}
else
{
(
buf
.
capacity
()
>=
size
))
{
// No suitable buffer in the cache so we need to allocate a new
buf
.
rewind
();
// one. To avoid the cache growing then we remove the first
buf
.
limit
(
size
);
// buffer from the cache and free it.
bufferPool
[
i
].
set
(
null
);
if
(!
cache
.
isEmpty
())
{
return
buf
;
buf
=
cache
.
removeFirst
();
free
(
buf
);
}
}
return
ByteBuffer
.
allocateDirect
(
size
);
}
}
// Make a new one
return
ByteBuffer
.
allocateDirect
(
size
);
}
}
/**
* Releases a temporary buffer by returning to the cache or freeing it.
*/
static
void
releaseTemporaryDirectBuffer
(
ByteBuffer
buf
)
{
static
void
releaseTemporaryDirectBuffer
(
ByteBuffer
buf
)
{
if
(
buf
==
null
)
offerFirstTemporaryDirectBuffer
(
buf
);
return
;
}
// Put it in an empty slot if such exists
for
(
int
i
=
0
;
i
<
TEMP_BUF_POOL_SIZE
;
i
++)
{
/**
SoftReference
<
ByteBuffer
>
ref
=
bufferPool
[
i
].
get
();
* Releases a temporary buffer by returning to the cache or freeing it. If
if
((
ref
==
null
)
||
(
ref
.
get
()
==
null
))
{
* returning to the cache then insert it at the start so that it is
bufferPool
[
i
].
set
(
new
SoftReference
<
ByteBuffer
>(
buf
));
* likely to be returned by a subsequent call to getTemporaryDirectBuffer.
return
;
*/
}
static
void
offerFirstTemporaryDirectBuffer
(
ByteBuffer
buf
)
{
assert
buf
!=
null
;
BufferCache
cache
=
bufferCache
.
get
();
if
(!
cache
.
offerFirst
(
buf
))
{
// cache is full
free
(
buf
);
}
}
// Otherwise replace a smaller one in the cache if such exists
}
for
(
int
i
=
0
;
i
<
TEMP_BUF_POOL_SIZE
;
i
++)
{
SoftReference
<
ByteBuffer
>
ref
=
bufferPool
[
i
].
get
();
/**
ByteBuffer
inCacheBuf
=
ref
.
get
();
* Releases a temporary buffer by returning to the cache or freeing it. If
if
((
inCacheBuf
==
null
)
||
(
buf
.
capacity
()
>
inCacheBuf
.
capacity
()))
{
* returning to the cache then insert it at the end. This makes it
bufferPool
[
i
].
set
(
new
SoftReference
<
ByteBuffer
>(
buf
));
* suitable for scatter/gather operations where the buffers are returned to
return
;
* cache in same order that they were obtained.
}
*/
static
void
offerLastTemporaryDirectBuffer
(
ByteBuffer
buf
)
{
assert
buf
!=
null
;
BufferCache
cache
=
bufferCache
.
get
();
if
(!
cache
.
offerLast
(
buf
))
{
// cache is full
free
(
buf
);
}
}
}
// release memory
/**
((
DirectBuffer
)
buf
).
cleaner
().
clean
();
* Frees the memory for the given direct buffer
*/
private
static
void
free
(
ByteBuffer
buf
)
{
((
DirectBuffer
)
buf
).
cleaner
().
clean
();
}
}
private
static
class
SelectorWrapper
{
private
static
class
SelectorWrapper
{
...
...
src/share/lib/security/java.security-solaris
浏览文件 @
130dc864
...
@@ -260,3 +260,30 @@ networkaddress.cache.negative.ttl=10
...
@@ -260,3 +260,30 @@ networkaddress.cache.negative.ttl=10
# Example,
# Example,
# ocsp.responderCertSerialNumber=2A:FF:00
# ocsp.responderCertSerialNumber=2A:FF:00
#
# Policy for failed Kerberos KDC lookups:
#
# When a KDC is unavailable (network error, service failure, etc), it is
# put inside a blacklist and accessed less often for future requests. The
# value (case-insensitive) for this policy can be:
#
# tryLast
# KDCs in the blacklist are always tried after those not on the list.
#
# tryLess[:max_retries,timeout]
# KDCs in the blacklist are still tried by their order in the configuration,
# but with smaller max_retries and timeout values. max_retries and timeout
# are optional numerical parameters (default 1 and 5000, which means once
# and 5 seconds). Please notes that if any of the values defined here is
# more than what is defined in krb5.conf, it will be ignored.
#
# Whenever a KDC is detected as available, it is removed from the blacklist.
# The blacklist is reset when krb5.conf is reloaded. You can add
# refreshKrb5Config=true to a JAAS configuration file so that krb5.conf is
# reloaded whenever a JAAS authentication is attempted.
#
# Example,
# krb5.kdc.bad.policy = tryLast
# krb5.kdc.bad.policy = tryLess:2,2000
krb5.kdc.bad.policy = tryLast
src/share/lib/security/java.security-windows
浏览文件 @
130dc864
...
@@ -260,3 +260,30 @@ networkaddress.cache.negative.ttl=10
...
@@ -260,3 +260,30 @@ networkaddress.cache.negative.ttl=10
# Example,
# Example,
# ocsp.responderCertSerialNumber=2A:FF:00
# ocsp.responderCertSerialNumber=2A:FF:00
#
# Policy for failed Kerberos KDC lookups:
#
# When a KDC is unavailable (network error, service failure, etc), it is
# put inside a blacklist and accessed less often for future requests. The
# value (case-insensitive) for this policy can be:
#
# tryLast
# KDCs in the blacklist are always tried after those not on the list.
#
# tryLess[:max_retries,timeout]
# KDCs in the blacklist are still tried by their order in the configuration,
# but with smaller max_retries and timeout values. max_retries and timeout
# are optional numerical parameters (default 1 and 5000, which means once
# and 5 seconds). Please notes that if any of the values defined here is
# more than what is defined in krb5.conf, it will be ignored.
#
# Whenever a KDC is detected as available, it is removed from the blacklist.
# The blacklist is reset when krb5.conf is reloaded. You can add
# refreshKrb5Config=true to a JAAS configuration file so that krb5.conf is
# reloaded whenever a JAAS authentication is attempted.
#
# Example,
# krb5.kdc.bad.policy = tryLast
# krb5.kdc.bad.policy = tryLess:2,2000
krb5.kdc.bad.policy = tryLast
src/share/native/common/check_code.c
浏览文件 @
130dc864
...
@@ -2730,7 +2730,10 @@ push_stack(context_type *context, unsigned int inumber, stack_info_type *new_sta
...
@@ -2730,7 +2730,10 @@ push_stack(context_type *context, unsigned int inumber, stack_info_type *new_sta
operand
);
operand
);
const
char
*
result_signature
;
const
char
*
result_signature
;
check_and_push
(
context
,
signature
,
VM_STRING_UTF
);
check_and_push
(
context
,
signature
,
VM_STRING_UTF
);
result_signature
=
strchr
(
signature
,
JVM_SIGNATURE_ENDFUNC
)
+
1
;
result_signature
=
strchr
(
signature
,
JVM_SIGNATURE_ENDFUNC
);
if
(
result_signature
++
==
NULL
)
{
CCerror
(
context
,
"Illegal signature %s"
,
signature
);
}
if
(
result_signature
[
0
]
==
JVM_SIGNATURE_VOID
)
{
if
(
result_signature
[
0
]
==
JVM_SIGNATURE_VOID
)
{
stack_results
=
""
;
stack_results
=
""
;
}
else
{
}
else
{
...
@@ -3654,14 +3657,13 @@ signature_to_fieldtype(context_type *context,
...
@@ -3654,14 +3657,13 @@ signature_to_fieldtype(context_type *context,
const
char
**
signature_p
,
fullinfo_type
*
full_info_p
)
const
char
**
signature_p
,
fullinfo_type
*
full_info_p
)
{
{
const
char
*
p
=
*
signature_p
;
const
char
*
p
=
*
signature_p
;
fullinfo_type
full_info
=
MAKE_FULLINFO
(
0
,
0
,
0
);
fullinfo_type
full_info
=
MAKE_FULLINFO
(
ITEM_Bogus
,
0
,
0
);
char
result
;
char
result
;
int
array_depth
=
0
;
int
array_depth
=
0
;
for
(;;)
{
for
(;;)
{
switch
(
*
p
++
)
{
switch
(
*
p
++
)
{
default:
default:
full_info
=
MAKE_FULLINFO
(
ITEM_Bogus
,
0
,
0
);
result
=
0
;
result
=
0
;
break
;
break
;
...
@@ -3714,7 +3716,14 @@ signature_to_fieldtype(context_type *context,
...
@@ -3714,7 +3716,14 @@ signature_to_fieldtype(context_type *context,
char
buffer_space
[
256
];
char
buffer_space
[
256
];
char
*
buffer
=
buffer_space
;
char
*
buffer
=
buffer_space
;
char
*
finish
=
strchr
(
p
,
JVM_SIGNATURE_ENDCLASS
);
char
*
finish
=
strchr
(
p
,
JVM_SIGNATURE_ENDCLASS
);
int
length
=
finish
-
p
;
int
length
;
if
(
finish
==
NULL
)
{
/* Signature must have ';' after the class name.
* If it does not, return 0 and ITEM_Bogus in full_info. */
result
=
0
;
break
;
}
length
=
finish
-
p
;
if
(
length
+
1
>
(
int
)
sizeof
(
buffer_space
))
{
if
(
length
+
1
>
(
int
)
sizeof
(
buffer_space
))
{
buffer
=
malloc
(
length
+
1
);
buffer
=
malloc
(
length
+
1
);
check_and_push
(
context
,
buffer
,
VM_MALLOC_BLK
);
check_and_push
(
context
,
buffer
,
VM_MALLOC_BLK
);
...
...
src/solaris/classes/java/io/UnixFileSystem.java
浏览文件 @
130dc864
...
@@ -187,7 +187,6 @@ class UnixFileSystem extends FileSystem {
...
@@ -187,7 +187,6 @@ class UnixFileSystem extends FileSystem {
}
}
}
}
}
}
assert
canonicalize0
(
path
).
equals
(
res
)
||
path
.
startsWith
(
javaHome
);
return
res
;
return
res
;
}
}
}
}
...
...
src/solaris/classes/sun/nio/fs/UnixPath.java
浏览文件 @
130dc864
...
@@ -1141,6 +1141,13 @@ class UnixPath
...
@@ -1141,6 +1141,13 @@ class UnixPath
}
}
result
=
result
.
resolve
(
element
);
result
=
result
.
resolve
(
element
);
}
}
// check file exists (without following links)
try
{
UnixFileAttributes
.
get
(
result
,
false
);
}
catch
(
UnixException
x
)
{
x
.
rethrowAsIOException
(
result
);
}
return
result
;
return
result
;
}
}
...
...
src/solaris/native/java/net/PlainDatagramSocketImpl.c
浏览文件 @
130dc864
...
@@ -1052,30 +1052,38 @@ JNIEXPORT void JNICALL
...
@@ -1052,30 +1052,38 @@ JNIEXPORT void JNICALL
Java_java_net_PlainDatagramSocketImpl_datagramSocketCreate
(
JNIEnv
*
env
,
Java_java_net_PlainDatagramSocketImpl_datagramSocketCreate
(
JNIEnv
*
env
,
jobject
this
)
{
jobject
this
)
{
jobject
fdObj
=
(
*
env
)
->
GetObjectField
(
env
,
this
,
pdsi_fdID
);
jobject
fdObj
=
(
*
env
)
->
GetObjectField
(
env
,
this
,
pdsi_fdID
);
int
fd
;
int
fd
,
t
=
1
;
#ifdef AF_INET6
int
t
=
1
;
int
domain
=
ipv6_available
()
?
AF_INET6
:
AF_INET
;
#else
int
domain
=
AF_INET
;
#endif
if
(
IS_NULL
(
fdObj
))
{
if
(
IS_NULL
(
fdObj
))
{
JNU_ThrowByName
(
env
,
JNU_JAVANETPKG
"SocketException"
,
JNU_ThrowByName
(
env
,
JNU_JAVANETPKG
"SocketException"
,
"Socket closed"
);
"Socket closed"
);
return
;
return
;
}
else
{
#ifdef AF_INET6
if
(
ipv6_available
())
{
fd
=
JVM_Socket
(
AF_INET6
,
SOCK_DGRAM
,
0
);
}
else
#endif
/* AF_INET6 */
{
fd
=
JVM_Socket
(
AF_INET
,
SOCK_DGRAM
,
0
);
}
}
}
if
(
fd
==
JVM_IO_ERR
)
{
if
((
fd
=
JVM_Socket
(
domain
,
SOCK_DGRAM
,
0
))
==
JVM_IO_ERR
)
{
NET_ThrowByNameWithLastError
(
env
,
JNU_JAVANETPKG
"SocketException"
,
NET_ThrowByNameWithLastError
(
env
,
JNU_JAVANETPKG
"SocketException"
,
"Error creating socket"
);
"Error creating socket"
);
return
;
return
;
}
}
#ifdef AF_INET6
/* Disable IPV6_V6ONLY to ensure dual-socket support */
if
(
domain
==
AF_INET6
)
{
int
arg
=
0
;
if
(
setsockopt
(
fd
,
IPPROTO_IPV6
,
IPV6_V6ONLY
,
(
char
*
)
&
arg
,
sizeof
(
int
))
<
0
)
{
NET_ThrowNew
(
env
,
errno
,
"cannot set IPPROTO_IPV6"
);
close
(
fd
);
return
;
}
}
#endif
/* AF_INET6 */
setsockopt
(
fd
,
SOL_SOCKET
,
SO_BROADCAST
,
(
char
*
)
&
t
,
sizeof
(
int
));
setsockopt
(
fd
,
SOL_SOCKET
,
SO_BROADCAST
,
(
char
*
)
&
t
,
sizeof
(
int
));
#ifdef __linux__
#ifdef __linux__
...
@@ -1088,7 +1096,7 @@ Java_java_net_PlainDatagramSocketImpl_datagramSocketCreate(JNIEnv *env,
...
@@ -1088,7 +1096,7 @@ Java_java_net_PlainDatagramSocketImpl_datagramSocketCreate(JNIEnv *env,
* On Linux for IPv6 sockets we must set the hop limit
* On Linux for IPv6 sockets we must set the hop limit
* to 1 to be compatible with default ttl of 1 for IPv4 sockets.
* to 1 to be compatible with default ttl of 1 for IPv4 sockets.
*/
*/
if
(
ipv6_available
()
)
{
if
(
domain
==
AF_INET6
)
{
int
ttl
=
1
;
int
ttl
=
1
;
setsockopt
(
fd
,
IPPROTO_IPV6
,
IPV6_MULTICAST_HOPS
,
(
char
*
)
&
ttl
,
setsockopt
(
fd
,
IPPROTO_IPV6
,
IPV6_MULTICAST_HOPS
,
(
char
*
)
&
ttl
,
sizeof
(
ttl
));
sizeof
(
ttl
));
...
...
src/solaris/native/java/net/PlainSocketImpl.c
浏览文件 @
130dc864
...
@@ -181,6 +181,12 @@ Java_java_net_PlainSocketImpl_socketCreate(JNIEnv *env, jobject this,
...
@@ -181,6 +181,12 @@ Java_java_net_PlainSocketImpl_socketCreate(JNIEnv *env, jobject this,
jboolean
stream
)
{
jboolean
stream
)
{
jobject
fdObj
,
ssObj
;
jobject
fdObj
,
ssObj
;
int
fd
;
int
fd
;
int
type
=
(
stream
?
SOCK_STREAM
:
SOCK_DGRAM
);
#ifdef AF_INET6
int
domain
=
ipv6_available
()
?
AF_INET6
:
AF_INET
;
#else
int
domain
=
AF_INET
;
#endif
if
(
socketExceptionCls
==
NULL
)
{
if
(
socketExceptionCls
==
NULL
)
{
jclass
c
=
(
*
env
)
->
FindClass
(
env
,
"java/net/SocketException"
);
jclass
c
=
(
*
env
)
->
FindClass
(
env
,
"java/net/SocketException"
);
...
@@ -194,25 +200,29 @@ Java_java_net_PlainSocketImpl_socketCreate(JNIEnv *env, jobject this,
...
@@ -194,25 +200,29 @@ Java_java_net_PlainSocketImpl_socketCreate(JNIEnv *env, jobject this,
(
*
env
)
->
ThrowNew
(
env
,
socketExceptionCls
,
"null fd object"
);
(
*
env
)
->
ThrowNew
(
env
,
socketExceptionCls
,
"null fd object"
);
return
;
return
;
}
}
#ifdef AF_INET6
if
(
ipv6_available
())
{
if
((
fd
=
JVM_Socket
(
domain
,
type
,
0
))
==
JVM_IO_ERR
)
{
fd
=
JVM_Socket
(
AF_INET6
,
(
stream
?
SOCK_STREAM
:
SOCK_DGRAM
),
0
);
}
else
#endif
/* AF_INET6 */
{
fd
=
JVM_Socket
(
AF_INET
,
(
stream
?
SOCK_STREAM
:
SOCK_DGRAM
),
0
);
}
if
(
fd
==
JVM_IO_ERR
)
{
/* note: if you run out of fds, you may not be able to load
/* note: if you run out of fds, you may not be able to load
* the exception class, and get a NoClassDefFoundError
* the exception class, and get a NoClassDefFoundError
* instead.
* instead.
*/
*/
NET_ThrowNew
(
env
,
errno
,
"can't create socket"
);
NET_ThrowNew
(
env
,
errno
,
"can't create socket"
);
return
;
return
;
}
else
{
(
*
env
)
->
SetIntField
(
env
,
fdObj
,
IO_fd_fdID
,
fd
);
}
}
#ifdef AF_INET6
/* Disable IPV6_V6ONLY to ensure dual-socket support */
if
(
domain
==
AF_INET6
)
{
int
arg
=
0
;
if
(
setsockopt
(
fd
,
IPPROTO_IPV6
,
IPV6_V6ONLY
,
(
char
*
)
&
arg
,
sizeof
(
int
))
<
0
)
{
NET_ThrowNew
(
env
,
errno
,
"cannot set IPPROTO_IPV6"
);
close
(
fd
);
return
;
}
}
#endif
/* AF_INET6 */
/*
/*
* If this is a server socket then enable SO_REUSEADDR
* If this is a server socket then enable SO_REUSEADDR
* automatically and set to non blocking.
* automatically and set to non blocking.
...
@@ -221,9 +231,15 @@ Java_java_net_PlainSocketImpl_socketCreate(JNIEnv *env, jobject this,
...
@@ -221,9 +231,15 @@ Java_java_net_PlainSocketImpl_socketCreate(JNIEnv *env, jobject this,
if
(
ssObj
!=
NULL
)
{
if
(
ssObj
!=
NULL
)
{
int
arg
=
1
;
int
arg
=
1
;
SET_NONBLOCKING
(
fd
);
SET_NONBLOCKING
(
fd
);
JVM_SetSockOpt
(
fd
,
SOL_SOCKET
,
SO_REUSEADDR
,
(
char
*
)
&
arg
,
if
(
JVM_SetSockOpt
(
fd
,
SOL_SOCKET
,
SO_REUSEADDR
,
(
char
*
)
&
arg
,
sizeof
(
arg
));
sizeof
(
arg
))
<
0
)
{
NET_ThrowNew
(
env
,
errno
,
"cannot set SO_REUSEADDR"
);
close
(
fd
);
return
;
}
}
}
(
*
env
)
->
SetIntField
(
env
,
fdObj
,
IO_fd_fdID
,
fd
);
}
}
/*
/*
...
...
src/solaris/native/sun/nio/ch/Net.c
浏览文件 @
130dc864
...
@@ -170,6 +170,22 @@ Java_sun_nio_ch_Net_socket0(JNIEnv *env, jclass cl, jboolean preferIPv6,
...
@@ -170,6 +170,22 @@ Java_sun_nio_ch_Net_socket0(JNIEnv *env, jclass cl, jboolean preferIPv6,
if
(
fd
<
0
)
{
if
(
fd
<
0
)
{
return
handleSocketError
(
env
,
errno
);
return
handleSocketError
(
env
,
errno
);
}
}
#ifdef AF_INET6
/* Disable IPV6_V6ONLY to ensure dual-socket support */
if
(
domain
==
AF_INET6
)
{
int
arg
=
0
;
if
(
setsockopt
(
fd
,
IPPROTO_IPV6
,
IPV6_V6ONLY
,
(
char
*
)
&
arg
,
sizeof
(
int
))
<
0
)
{
JNU_ThrowByNameWithLastError
(
env
,
JNU_JAVANETPKG
"SocketException"
,
"sun.nio.ch.Net.setIntOption"
);
close
(
fd
);
return
-
1
;
}
}
#endif
if
(
reuse
)
{
if
(
reuse
)
{
int
arg
=
1
;
int
arg
=
1
;
if
(
setsockopt
(
fd
,
SOL_SOCKET
,
SO_REUSEADDR
,
(
char
*
)
&
arg
,
if
(
setsockopt
(
fd
,
SOL_SOCKET
,
SO_REUSEADDR
,
(
char
*
)
&
arg
,
...
...
src/windows/classes/java/io/Win32FileSystem.java
浏览文件 @
130dc864
...
@@ -424,7 +424,6 @@ class Win32FileSystem extends FileSystem {
...
@@ -424,7 +424,6 @@ class Win32FileSystem extends FileSystem {
}
}
}
}
}
}
assert
canonicalize0
(
path
).
equalsIgnoreCase
(
res
);
return
res
;
return
res
;
}
}
}
}
...
...
test/java/lang/ClassLoader/deadlock/TestCrossDelegate.sh
浏览文件 @
130dc864
...
@@ -55,7 +55,7 @@ case "$OS" in
...
@@ -55,7 +55,7 @@ case "$OS" in
Linux
)
Linux
)
FS
=
"/"
FS
=
"/"
;;
;;
Windows
*
)
Windows
*
|
CYGWIN
*
)
FS
=
"
\\
"
FS
=
"
\\
"
;;
;;
esac
esac
...
...
test/java/net/URI/Test.java
浏览文件 @
130dc864
...
@@ -1536,6 +1536,7 @@ public class Test {
...
@@ -1536,6 +1536,7 @@ public class Test {
serial
();
serial
();
urls
();
urls
();
npes
();
npes
();
bugs
();
}
}
...
@@ -1572,6 +1573,19 @@ public class Test {
...
@@ -1572,6 +1573,19 @@ public class Test {
}
}
// miscellaneous bugs/rfes that don't fit in with the test framework
static
void
bugs
()
{
// 6339649 - include detail message from nested exception
try
{
URI
uri
=
URI
.
create
(
"http://nowhere.net/should not be permitted"
);
}
catch
(
IllegalArgumentException
e
)
{
if
(
""
.
equals
(
e
.
getMessage
())
||
e
.
getMessage
()
==
null
)
{
throw
new
RuntimeException
(
"No detail message"
);
}
}
}
public
static
void
main
(
String
[]
args
)
throws
Exception
{
public
static
void
main
(
String
[]
args
)
throws
Exception
{
switch
(
args
.
length
)
{
switch
(
args
.
length
)
{
...
...
test/java/nio/file/Path/Misc.java
浏览文件 @
130dc864
...
@@ -260,6 +260,21 @@ public class Misc {
...
@@ -260,6 +260,21 @@ public class Misc {
*/
*/
assertTrue
(
file
.
toRealPath
(
true
).
isSameFile
(
file
.
toRealPath
(
false
)));
assertTrue
(
file
.
toRealPath
(
true
).
isSameFile
(
file
.
toRealPath
(
false
)));
/**
* Test: toRealPath should fail if file does not exist
*/
Path
doesNotExist
=
dir
.
resolve
(
"DoesNotExist"
);
try
{
doesNotExist
.
toRealPath
(
true
);
throw
new
RuntimeException
(
"IOException expected"
);
}
catch
(
IOException
expected
)
{
}
try
{
doesNotExist
.
toRealPath
(
false
);
throw
new
RuntimeException
(
"IOException expected"
);
}
catch
(
IOException
expected
)
{
}
/**
/**
* Test: toRealPath(true) should resolve links
* Test: toRealPath(true) should resolve links
*/
*/
...
...
test/sun/jvmstat/monitor/MonitoredVm/MonitorVmStartTerminate.sh
浏览文件 @
130dc864
...
@@ -23,6 +23,7 @@
...
@@ -23,6 +23,7 @@
#
#
# @test
# @test
# @ignore until 6543856 is fixed
# @bug 4990825
# @bug 4990825
# @summary attach to external but local JVM processes
# @summary attach to external but local JVM processes
# @library ../../testlibrary
# @library ../../testlibrary
...
...
test/sun/net/www/protocol/file/DirPermissionDenied.java
0 → 100644
浏览文件 @
130dc864
/*
* 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.
*/
import
java.net.URL
;
import
java.net.URLConnection
;
import
java.io.IOException
;
public
class
DirPermissionDenied
{
public
static
void
main
(
String
[]
args
)
throws
Exception
{
URL
url
=
new
URL
(
"file:"
+
args
[
0
]);
try
{
URLConnection
uc
=
url
.
openConnection
();
uc
.
connect
();
}
catch
(
IOException
e
)
{
// OK
}
catch
(
Exception
e
)
{
throw
new
RuntimeException
(
"Failed "
+
e
);
}
try
{
URLConnection
uc
=
url
.
openConnection
();
uc
.
getInputStream
();
}
catch
(
IOException
e
)
{
// OK
}
catch
(
Exception
e
)
{
throw
new
RuntimeException
(
"Failed "
+
e
);
}
try
{
URLConnection
uc
=
url
.
openConnection
();
uc
.
getContentLengthLong
();
}
catch
(
IOException
e
)
{
// OK
}
catch
(
Exception
e
)
{
throw
new
RuntimeException
(
"Failed "
+
e
);
}
}
}
test/sun/net/www/protocol/file/DirPermissionDenied.sh
0 → 100644
浏览文件 @
130dc864
#
# 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.
#
#
# @test
# @bug 6977851
# @summary NPE from FileURLConnection.connect
# @build DirPermissionDenied
# @run shell DirPermissionDenied.sh
TESTDIR
=
"
${
TESTCLASSES
}
/DirPermissionDeniedDirectory"
echo
${
TESTDIR
}
rm
-rf
${
TESTDIR
}
mkdir
-p
${
TESTDIR
}
chmod
333
${
TESTDIR
}
$TESTJAVA
/bin/java
-classpath
$TESTCLASSES
DirPermissionDenied
${
TESTDIR
}
result
=
$?
rm
-rf
${
TESTDIR
}
exit
$result
test/sun/security/krb5/BadKdcDefaultValue.java
0 → 100644
浏览文件 @
130dc864
/*
* 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.
*/
/*
* @test
* @bug 6976536
* @summary Solaris JREs do not have the krb5.kdc.bad.policy configured by default.
* @run main/othervm BadKdcDefaultValue
*/
import
java.security.Security
;
public
class
BadKdcDefaultValue
{
public
static
void
main
(
String
[]
args
)
throws
Exception
{
if
(!
"tryLast"
.
equalsIgnoreCase
(
Security
.
getProperty
(
"krb5.kdc.bad.policy"
)))
{
throw
new
Exception
(
"Default value not correct"
);
}
}
}
test/sun/security/ssl/sun/net/www/protocol/https/HttpsURLConnection/B6226610.java
浏览文件 @
130dc864
...
@@ -23,7 +23,7 @@
...
@@ -23,7 +23,7 @@
/*
/*
* @test
* @test
* @bug 6226610
* @bug 6226610
6973030
* @run main/othervm B6226610
* @run main/othervm B6226610
* @summary HTTP tunnel connections send user headers to proxy
* @summary HTTP tunnel connections send user headers to proxy
*/
*/
...
@@ -36,45 +36,23 @@
...
@@ -36,45 +36,23 @@
import
java.io.*
;
import
java.io.*
;
import
java.net.*
;
import
java.net.*
;
import
javax.net.ssl.*
;
import
sun.net.www.MessageHeader
;
import
javax.net.ServerSocketFactory
;
import
sun.net.www.*
;
import
java.util.Enumeration
;
public
class
B6226610
{
public
class
B6226610
{
static
HeaderCheckerProxyTunnelServer
proxy
;
static
HeaderCheckerProxyTunnelServer
proxy
;
// it seems there's no proxy ever if a url points to 'localhost',
public
static
void
main
(
String
[]
args
)
throws
Exception
// even if proxy related properties are set. so we need to bind
// our simple http proxy and http server to a non-loopback address
static
InetAddress
firstNonLoAddress
=
null
;
public
static
void
main
(
String
[]
args
)
{
{
try
{
proxy
=
new
HeaderCheckerProxyTunnelServer
();
proxy
=
new
HeaderCheckerProxyTunnelServer
();
proxy
.
start
();
proxy
.
start
();
}
catch
(
Exception
e
)
{
System
.
out
.
println
(
"Cannot create proxy: "
+
e
);
}
try
{
firstNonLoAddress
=
getNonLoAddress
();
if
(
firstNonLoAddress
==
null
)
{
System
.
out
.
println
(
"The test needs at least one non-loopback address to run. Quit now."
);
System
.
exit
(
0
);
}
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
}
System
.
setProperty
(
"https.proxyHost"
,
firstNonLoAddress
.
getHostAddress
());
String
hostname
=
InetAddress
.
getLocalHost
().
getHostName
();
System
.
setProperty
(
"https.proxyPort"
,
(
new
Integer
(
proxy
.
getLocalPort
())).
toString
()
);
try
{
try
{
URL
u
=
new
URL
(
"https://"
+
firstNonLoAddress
.
getHostAddress
());
URL
u
=
new
URL
(
"https://"
+
hostname
+
"/"
);
java
.
net
.
URLConnection
c
=
u
.
openConnection
();
System
.
out
.
println
(
"Connecting to "
+
u
);
InetSocketAddress
proxyAddr
=
new
InetSocketAddress
(
hostname
,
proxy
.
getLocalPort
());
java
.
net
.
URLConnection
c
=
u
.
openConnection
(
new
Proxy
(
Proxy
.
Type
.
HTTP
,
proxyAddr
));
/* I want this header to go to the destination server only, protected
/* I want this header to go to the destination server only, protected
* by SSL
* by SSL
...
@@ -89,33 +67,15 @@ public class B6226610 {
...
@@ -89,33 +67,15 @@ public class B6226610 {
}
}
else
else
System
.
out
.
println
(
e
);
System
.
out
.
println
(
e
);
}
finally
{
if
(
proxy
!=
null
)
proxy
.
shutdown
();
}
}
if
(
HeaderCheckerProxyTunnelServer
.
failed
)
if
(
HeaderCheckerProxyTunnelServer
.
failed
)
throw
new
RuntimeException
(
"Test failed: Proxy should not receive user defined headers for tunneled requests"
);
throw
new
RuntimeException
(
"Test failed; see output"
);
}
public
static
InetAddress
getNonLoAddress
()
throws
Exception
{
NetworkInterface
loNIC
=
NetworkInterface
.
getByInetAddress
(
InetAddress
.
getByName
(
"localhost"
));
Enumeration
<
NetworkInterface
>
nics
=
NetworkInterface
.
getNetworkInterfaces
();
while
(
nics
.
hasMoreElements
())
{
NetworkInterface
nic
=
nics
.
nextElement
();
if
(!
nic
.
getName
().
equalsIgnoreCase
(
loNIC
.
getName
()))
{
Enumeration
<
InetAddress
>
addrs
=
nic
.
getInetAddresses
();
while
(
addrs
.
hasMoreElements
())
{
InetAddress
addr
=
addrs
.
nextElement
();
if
(!
addr
.
isLoopbackAddress
())
return
addr
;
}
}
}
return
null
;
}
}
}
}
class
HeaderCheckerProxyTunnelServer
extends
Thread
class
HeaderCheckerProxyTunnelServer
extends
Thread
{
{
public
static
boolean
failed
=
false
;
public
static
boolean
failed
=
false
;
...
@@ -139,6 +99,10 @@ class HeaderCheckerProxyTunnelServer extends Thread
...
@@ -139,6 +99,10 @@ class HeaderCheckerProxyTunnelServer extends Thread
}
}
}
}
void
shutdown
()
{
try
{
ss
.
close
();
}
catch
(
IOException
e
)
{}
}
public
void
run
()
public
void
run
()
{
{
try
{
try
{
...
@@ -178,6 +142,15 @@ class HeaderCheckerProxyTunnelServer extends Thread
...
@@ -178,6 +142,15 @@ class HeaderCheckerProxyTunnelServer extends Thread
retrieveConnectInfo
(
statusLine
);
retrieveConnectInfo
(
statusLine
);
if
(
mheader
.
findValue
(
"X-TestHeader"
)
!=
null
)
{
if
(
mheader
.
findValue
(
"X-TestHeader"
)
!=
null
)
{
System
.
out
.
println
(
"Proxy should not receive user defined headers for tunneled requests"
);
failed
=
true
;
}
// 6973030
String
value
;
if
((
value
=
mheader
.
findValue
(
"Proxy-Connection"
))
==
null
||
!
value
.
equals
(
"keep-alive"
))
{
System
.
out
.
println
(
"Proxy-Connection:keep-alive not being sent"
);
failed
=
true
;
failed
=
true
;
}
}
...
...
test/tools/jar/JarEntryTime.java
浏览文件 @
130dc864
...
@@ -23,7 +23,7 @@
...
@@ -23,7 +23,7 @@
/**
/**
* @test
* @test
* @bug 4225317
* @bug 4225317
6969651
* @summary Check extracted files have date as per those in the .jar file
* @summary Check extracted files have date as per those in the .jar file
*/
*/
...
@@ -68,17 +68,9 @@ public class JarEntryTime {
...
@@ -68,17 +68,9 @@ public class JarEntryTime {
}
}
public
static
void
realMain
(
String
[]
args
)
throws
Throwable
{
public
static
void
realMain
(
String
[]
args
)
throws
Throwable
{
final
long
now
=
System
.
currentTimeMillis
();
final
long
earlier
=
now
-
(
60L
*
60L
*
6L
*
1000L
);
final
long
yesterday
=
now
-
(
60L
*
60L
*
24L
*
1000L
);
// ZipEntry's mod date has 2 seconds precision: give extra time to
// allow for e.g. rounding/truncation and networked/samba drives.
final
long
PRECISION
=
10000L
;
File
dirOuter
=
new
File
(
"outer"
);
File
dirOuter
=
new
File
(
"outer"
);
File
dirInner
=
new
File
(
dirOuter
,
"inner"
);
File
dirInner
=
new
File
(
dirOuter
,
"inner"
);
File
jarFile
=
new
File
(
"JarEntryTime.jar"
);
File
jarFile
=
new
File
(
"JarEntryTime.jar"
);
// Remove any leftovers from prior run
// Remove any leftovers from prior run
...
@@ -99,6 +91,17 @@ public class JarEntryTime {
...
@@ -99,6 +91,17 @@ public class JarEntryTime {
PrintWriter
pw
=
new
PrintWriter
(
fileInner
);
PrintWriter
pw
=
new
PrintWriter
(
fileInner
);
pw
.
println
(
"hello, world"
);
pw
.
println
(
"hello, world"
);
pw
.
close
();
pw
.
close
();
// Get the "now" from the "last-modified-time" of the last file we
// just created, instead of the "System.currentTimeMillis()", to
// workaround the possible "time difference" due to nfs.
final
long
now
=
fileInner
.
lastModified
();
final
long
earlier
=
now
-
(
60L
*
60L
*
6L
*
1000L
);
final
long
yesterday
=
now
-
(
60L
*
60L
*
24L
*
1000L
);
// ZipEntry's mod date has 2 seconds precision: give extra time to
// allow for e.g. rounding/truncation and networked/samba drives.
final
long
PRECISION
=
10000L
;
dirOuter
.
setLastModified
(
now
);
dirOuter
.
setLastModified
(
now
);
dirInner
.
setLastModified
(
yesterday
);
dirInner
.
setLastModified
(
yesterday
);
fileInner
.
setLastModified
(
earlier
);
fileInner
.
setLastModified
(
earlier
);
...
...
test/tools/pack200/CommandLineTests.java
0 → 100644
浏览文件 @
130dc864
/*
* Copyright (c) 2007, 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.
*/
/*
* @test CommandLineTests.sh
* @bug 6521334 6965836 6965836
* @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
();
}
// 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"
);
ps
.
println
(
"pack.pass.file.5=com/sun/demo/jvmti/hprof/Tracker.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
.
getAbsoluteFile
(),
bakFile
.
getAbsoluteFile
());
}
else
{
// restore
Utils
.
copyFile
(
bakFile
.
getAbsoluteFile
(),
f
.
getAbsoluteFile
());
}
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
();
}
catch
(
IOException
ioe
)
{
throw
new
RuntimeException
(
ioe
);
}
}
}
test/tools/pack200/
SegmentLimit
.java
→
test/tools/pack200/
Pack200Props
.java
浏览文件 @
130dc864
...
@@ -21,113 +21,107 @@
...
@@ -21,113 +21,107 @@
* questions.
* questions.
*/
*/
/*
*
/*
* @test
* @test
* @bug 6575373
* @bug 6575373 6969063
* @summary verify default segment limit
* @summary verify default properties of the packer/unpacker and segment limit
* @compile SegmentLimit.java
* @compile -XDignore.symbol.file Utils.java Pack200Props.java
* @run main SegmentLimit
* @run main Pack200Props
* @author ksrini
*/
*/
import
java.io.BufferedReader
;
import
java.io.Closeable
;
import
java.io.File
;
import
java.io.File
;
import
java.io.FileOutputStream
;
import
java.util.ArrayList
;
import
java.io.IOException
;
import
java.util.HashMap
;
import
java.io.InputStream
;
import
java.util.List
;
import
java.io.InputStreamReader
;
import
java.util.Map
;
import
java.io.PrintStream
;
import
java.util.jar.Pack200
;
import
java.util.jar.Pack200.Packer
;
/*
/*
* Run this against a large jar file, by default the packer should generate only
* 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.
* one segment, parse the output of the packer to verify if this is indeed true.
*/
*/
public
class
SegmentLimit
{
public
class
Pack200Props
{
private
static
final
File
javaHome
=
new
File
(
System
.
getProperty
(
"java.home"
));
public
static
void
main
(
String
...
args
)
{
public
static
void
main
(
String
...
args
)
{
if
(!
javaHome
.
getName
().
endsWith
(
"jre"
))
{
verifyDefaults
();
throw
new
RuntimeException
(
"Error: requires an SDK to run"
);
File
out
=
new
File
(
"test"
+
Utils
.
PACK_FILE_EXT
);
}
File
out
=
new
File
(
"test"
+
Pack200Test
.
PACKEXT
);
out
.
delete
();
out
.
delete
();
runPack200
(
out
);
verifySegmentLimit
(
out
);
}
}
static
void
close
(
Closeable
c
)
{
static
void
verifySegmentLimit
(
File
outFile
)
{
if
(
c
==
null
)
{
File
sdkHome
=
Utils
.
JavaSDK
;
return
;
}
try
{
c
.
close
();
}
catch
(
IOException
ignore
)
{}
}
static
void
runPack200
(
File
outFile
)
{
File
binDir
=
new
File
(
javaHome
,
"bin"
);
File
pack200Exe
=
System
.
getProperty
(
"os.name"
).
startsWith
(
"Windows"
)
?
new
File
(
binDir
,
"pack200.exe"
)
:
new
File
(
binDir
,
"pack200"
);
File
sdkHome
=
javaHome
.
getParentFile
();
File
testJar
=
new
File
(
new
File
(
sdkHome
,
"lib"
),
"tools.jar"
);
File
testJar
=
new
File
(
new
File
(
sdkHome
,
"lib"
),
"tools.jar"
);
System
.
out
.
println
(
"using pack200: "
+
pack200Exe
.
getAbsolutePath
());
System
.
out
.
println
(
"using pack200: "
+
Utils
.
getPack200Cmd
());
String
[]
cmds
=
{
pack200Exe
.
getAbsolutePath
(),
List
<
String
>
cmdsList
=
new
ArrayList
<>();
"--effort=1"
,
cmdsList
.
add
(
Utils
.
getPack200Cmd
());
"--verbose"
,
cmdsList
.
add
(
"--effort=1"
);
"--no-gzip"
,
cmdsList
.
add
(
"--verbose"
);
outFile
.
getName
(),
cmdsList
.
add
(
"--no-gzip"
);
testJar
.
getAbsolutePath
()
cmdsList
.
add
(
outFile
.
getName
());
};
cmdsList
.
add
(
testJar
.
getAbsolutePath
());
InputStream
is
=
null
;
List
<
String
>
outList
=
Utils
.
runExec
(
cmdsList
);
BufferedReader
br
=
null
;
InputStreamReader
ir
=
null
;
int
count
=
0
;
for
(
String
line
:
outList
)
{
FileOutputStream
fos
=
null
;
System
.
out
.
println
(
line
);
PrintStream
ps
=
null
;
if
(
line
.
matches
(
".*Transmitted.*files of.*input bytes in a segment of.*bytes"
))
{
count
++;
try
{
}
ProcessBuilder
pb
=
new
ProcessBuilder
(
cmds
);
}
pb
.
redirectErrorStream
(
true
);
if
(
count
==
0
)
{
Process
p
=
pb
.
start
();
throw
new
RuntimeException
(
"no segments or no output ????"
);
is
=
p
.
getInputStream
();
}
else
if
(
count
>
1
)
{
ir
=
new
InputStreamReader
(
is
);
throw
new
RuntimeException
(
"multiple segments detected, expected 1"
);
br
=
new
BufferedReader
(
ir
);
}
}
File
logFile
=
new
File
(
"pack200.log"
);
fos
=
new
FileOutputStream
(
logFile
);
ps
=
new
PrintStream
(
fos
);
String
line
=
br
.
readLine
();
private
static
void
verifyDefaults
()
{
int
count
=
0
;
Map
<
String
,
String
>
expectedDefaults
=
new
HashMap
<>();
while
(
line
!=
null
)
{
Packer
p
=
Pack200
.
newPacker
();
line
=
line
.
trim
();
expectedDefaults
.
put
(
"com.sun.java.util.jar.pack.default.timezone"
,
if
(
line
.
matches
(
".*Transmitted.*files of.*input bytes in a segment of.*bytes"
))
{
p
.
FALSE
);
count
++;
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
++;
}
}
ps
.
println
(
line
);
line
=
br
.
readLine
();
}
p
.
waitFor
();
if
(
p
.
exitValue
()
!=
0
)
{
throw
new
RuntimeException
(
"pack200 failed"
);
}
}
p
.
destroy
();
}
if
(
count
>
1
)
{
if
(
errors
>
0
)
{
throw
new
Error
(
"test fails: check for multiple segments("
+
throw
new
RuntimeException
(
errors
+
count
+
") in: "
+
logFile
.
getAbsolutePath
());
" error(s) encountered in default properties verification"
);
}
}
catch
(
IOException
ex
)
{
throw
new
RuntimeException
(
ex
.
getMessage
());
}
catch
(
InterruptedException
ignore
){
}
finally
{
close
(
is
);
close
(
ps
);
close
(
fos
);
}
}
}
}
}
}
...
...
test/tools/pack200/Pack200Simple.sh
已删除
100644 → 0
浏览文件 @
7f54b605
#
# Copyright (c) 2003, 2007, 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 Pack200Simple.sh
# @bug 6521334
# @build Pack200Test
# @run shell/timeout=1200 Pack200Simple.sh
# @summary An ad hoc test to verify class-file format.
# @author Kumar Srinivasan
# The goal of this test is to assist javac or other developers
# who modify class file formats, to quickly test those modifications
# without having to build the install workspace. However it must
# be noted that building the install workspace is the only know
# way to prevent build breakages.
# Pack200 developers could use this as a basic smoke-test, however
# please note, there are other more elaborate and thorough tests for
# this very purpose.
# 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.
# print error and exit with a message
errorOut
()
{
if
[
"x
$1
"
=
"x"
]
;
then
printf
"Error: Unknown error
\n
"
else
printf
"Error: %s
\n
"
"
$1
"
fi
exit
1
}
# Verify directory context variables are set
if
[
"
${
TESTJAVA
}
"
=
""
]
;
then
errorOut
"TESTJAVA not set. Test cannot execute. Failed."
fi
if
[
"
${
TESTSRC
}
"
=
""
]
;
then
errorOut
"TESTSRC not set. Test cannot execute. Failed."
fi
if
[
"
${
TESTCLASSES
}
"
=
""
]
;
then
errorOut
"TESTCLASSES not set. Test cannot execute. Failed."
fi
# The common java utils we need
PACK200
=
${
TESTJAVA
}
/bin/pack200
UNPACK200
=
${
TESTJAVA
}
/bin/unpack200
JAR
=
${
TESTJAVA
}
/bin/jar
# For Windows and Linux needs the heap to be set, for others ergonomics
# will do the rest. It is important to use ea, which can expose class
# format errors much earlier than later.
OS
=
`
uname
-s
`
case
"
$OS
"
in
Windows
*
|
CYGWIN
*
)
PackOptions
=
"-J-Xmx512m -J-ea"
break
;;
Linux
)
PackOptions
=
"-J-Xmx512m -J-ea"
break
;;
*
)
PackOptions
=
"-J-ea"
;;
esac
# Creates a packfile of choice expects 1 argument the filename
createConfigFile
()
{
# optimize for speed
printf
"pack.effort=1
\n
"
>
$1
# we DO want to know about new attributes
printf
"pack.unknown.attribute=error
\n
"
>>
$1
# optimize for speed
printf
"pack.deflate.hint=false
\n
"
>>
$1
# keep the ordering for easy compare
printf
"pack.keep.class.order=true
\n
"
>>
$1
}
# Tests a given jar, expects 1 argument the fully qualified
# name to a test jar, it writes all output to the current
# directory which is a scratch area.
testAJar
()
{
PackConf
=
"pack.conf"
createConfigFile
$PackConf
# Try some command line options
CLIPackOptions
=
"
$PackOptions
-v --no-gzip --segment-limit=10000 --config-file=
$PackConf
"
jfName
=
`
basename
$1
`
${
PACK200
}
$CLIPackOptions
${
jfName
}
.pack
$1
>
${
jfName
}
.pack.log 2>&1
if
[
$?
!=
0
]
;
then
errorOut
"
$jfName
packing failed"
fi
# We want to test unpack200, therefore we dont use -r with pack
${
UNPACK200
}
-v
${
jfName
}
.pack
$jfName
>
${
jfName
}
.unpack.log 2>&1
if
[
$?
!=
0
]
;
then
errorOut
"
$jfName
unpacking failed"
fi
# A quick crc compare test to ensure a well formed zip
# archive, this is a critical unpack200 behaviour.
unzip
-t
$jfName
>
${
jfName
}
.unzip.log 2>&1
if
[
$?
!=
0
]
;
then
errorOut
"
$jfName
unzip -t test failed"
fi
# The PACK200 signature should be at the top of the log
# this tag is critical for deployment related tools.
head
-5
${
jfName
}
.unzip.log |
grep
PACK200
>
/dev/null 2>&1
if
[
$?
!=
0
]
;
then
errorOut
"
$jfName
PACK200 signature missing"
fi
# we know the size fields don't match, strip 'em out, its
# extremely important to ensure that the date stamps match up.
# Don't EVER sort the output we are checking for correct ordering.
${
JAR
}
-tvf
$1
|
sed
-e
's/^ *[0-9]* //g'
>
${
jfName
}
.ref.txt
${
JAR
}
-tvf
$jfName
|
sed
-e
's/^ *[0-9]* //g'
>
${
jfName
}
.cmp.txt
diff
${
jfName
}
.ref.txt
${
jfName
}
.cmp.txt
>
${
jfName
}
.diff.log 2>&1
if
[
$?
!=
0
]
;
then
errorOut
"
$jfName
files missing"
fi
}
# These JARs are the largest and also the most likely specimens to
# expose class format issues and stress the packer as well.
JLIST
=
"
${
TESTJAVA
}
/lib/tools.jar
${
TESTJAVA
}
/jre/lib/rt.jar"
# Test the Command Line Interfaces (CLI).
mkdir
cliTestDir
_pwd
=
`
pwd
`
cd
cliTestDir
for
jarfile
in
$JLIST
;
do
if
[
-f
$jarfile
]
;
then
testAJar
$jarfile
else
errorOut
"Error: '
$jarFile
' does not exist
\n
Test requires a j2sdk-image
\n
"
fi
done
cd
$_pwd
# Test the Java APIs.
mkdir
apiTestDir
_pwd
=
`
pwd
`
cd
apiTestDir
# Strip out the -J prefixes.
JavaPackOptions
=
`
printf
%s
"
$PackOptions
"
|
sed
-e
's/-J//g'
`
# Test the Java APIs now.
$TESTJAVA
/bin/java
$JavaPackOptions
-cp
$TESTCLASSES
Pack200Test
$JLIST
||
exit
1
cd
$_pwd
exit
0
test/tools/pack200/Pack200Test.java
浏览文件 @
130dc864
...
@@ -24,111 +24,97 @@
...
@@ -24,111 +24,97 @@
import
java.util.*
;
import
java.util.*
;
import
java.io.*
;
import
java.io.*
;
import
java.lang.management.ManagementFactory
;
import
java.lang.management.MemoryMXBean
;
import
java.util.jar.*
;
import
java.util.jar.*
;
import
java.util.zip.*
;
/*
/*
* Pack200Test.java
* @test
*
* @bug 6521334 6712743
* @author ksrini
* @summary check for memory leaks, test general packer/unpacker functionality\
*/
* using native and java unpackers
* @compile -XDignore.symbol.file Utils.java Pack200Test.java
* @run main/othervm/timeout=1200 -Xmx512m Pack200Test
* @author ksrini
*/
/**
/**
* These tests are very rudimentary smoke tests to ensure that the packing
* Tests the packing/unpacking via the APIs.
* unpacking process works on a select set of JARs.
*/
*/
public
class
Pack200Test
{
public
class
Pack200Test
{
private
static
ArrayList
<
File
>
jarList
=
new
ArrayList
<
File
>();
private
static
ArrayList
<
File
>
jarList
=
new
ArrayList
<
File
>();
static
final
String
PACKEXT
=
".pack"
;
static
final
MemoryMXBean
mmxbean
=
ManagementFactory
.
getMemoryMXBean
();
static
final
long
m0
=
getUsedMemory
();
static
final
int
LEAK_TOLERANCE
=
20000
;
// OS and GC related variations.
/** Creates a new instance of Pack200Test */
/** Creates a new instance of Pack200Test */
private
Pack200Test
()
{}
private
Pack200Test
()
{}
static
long
getUsedMemory
()
{
mmxbean
.
gc
();
mmxbean
.
gc
();
mmxbean
.
gc
();
return
mmxbean
.
getHeapMemoryUsage
().
getUsed
()/
1024
;
}
private
static
void
leakCheck
()
throws
Exception
{
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
()
{
private
static
void
doPackUnpack
()
{
for
(
File
in
:
jarList
)
{
for
(
File
in
:
jarList
)
{
Pack200
.
Packer
packer
=
Pack200
.
newPacker
();
JarOutputStream
javaUnpackerStream
=
null
;
Map
<
String
,
String
>
p
=
packer
.
properties
();
JarOutputStream
nativeUnpackerStream
=
null
;
// Take the time optimization vs. space
JarFile
jarFile
=
null
;
p
.
put
(
packer
.
EFFORT
,
"1"
);
// CAUTION: do not use 0.
// Make the memory consumption as effective as possible
p
.
put
(
packer
.
SEGMENT_LIMIT
,
"10000"
);
// throw an error if an attribute is unrecognized
p
.
put
(
packer
.
UNKNOWN_ATTRIBUTE
,
packer
.
ERROR
);
// 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
);
try
{
try
{
JarFile
jarFile
=
new
JarFile
(
in
);
jarFile
=
new
JarFile
(
in
);
// Write out to a jtreg scratch area
// Write out to a jtreg scratch area
File
OutputStream
fos
=
new
FileOutputStream
(
in
.
getName
()
+
PACK
EXT
);
File
packFile
=
new
File
(
in
.
getName
()
+
Utils
.
PACK_FILE_
EXT
);
System
.
out
.
print
(
"Packing ["
+
in
.
toString
()
+
"]...
"
);
System
.
out
.
print
ln
(
"Packing ["
+
in
.
toString
()
+
"]
"
);
// Call the packer
// Call the packer
packer
.
pack
(
jarFile
,
fos
);
Utils
.
pack
(
jarFile
,
packFile
);
jarFile
.
close
();
jarFile
.
close
();
fos
.
close
();
leakCheck
();
System
.
out
.
print
(
"Unpacking..."
);
File
f
=
new
File
(
in
.
getName
()
+
PACKEXT
);
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
// Write out to current directory, jtreg will setup a scratch area
JarOutputStream
jostream
=
new
JarOutputStream
(
new
FileOutputStream
(
in
.
getName
()));
javaUnpackerStream
=
new
JarOutputStream
(
new
FileOutputStream
(
javaUnpackedJar
));
// Unpack the files
Utils
.
unpackj
(
packFile
,
javaUnpackerStream
);
Pack200
.
Unpacker
unpacker
=
Pack200
.
newUnpacker
();
javaUnpackerStream
.
close
();
// Call the unpacker
System
.
out
.
println
(
" Testing...java unpacker"
);
unpacker
.
unpack
(
f
,
jostream
);
leakCheck
();
// Must explicitly close the output.
jostream
.
close
();
System
.
out
.
print
(
"Testing..."
);
// Ok we have unpacked the file, lets test it.
// Ok we have unpacked the file, lets test it.
doTest
(
in
);
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."
);
System
.
out
.
println
(
"Done."
);
}
catch
(
Exception
e
)
{
}
catch
(
Exception
e
)
{
System
.
out
.
println
(
"ERROR: "
+
e
.
getMessage
());
throw
new
RuntimeException
(
e
);
System
.
exit
(
1
);
}
finally
{
}
Utils
.
close
(
nativeUnpackerStream
);
}
Utils
.
close
(
javaUnpackerStream
);
}
Utils
.
close
((
Closeable
)
jarFile
);
private
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
;
}
private
static
void
doTest
(
File
in
)
throws
Exception
{
// make sure all the files in the original jar exists in the other
ArrayList
<
String
>
refList
=
getZipFileEntryNames
(
new
ZipFile
(
in
));
ArrayList
<
String
>
cmpList
=
getZipFileEntryNames
(
new
ZipFile
(
in
.
getName
()));
System
.
out
.
print
(
refList
.
size
()
+
"/"
+
cmpList
.
size
()
+
" entries..."
);
if
(
refList
.
size
()
!=
cmpList
.
size
())
{
throw
new
Exception
(
"Missing: files ?, entries don't match"
);
}
for
(
String
ename:
refList
)
{
if
(!
cmpList
.
contains
(
ename
))
{
throw
new
Exception
(
"Does not contain : "
+
ename
);
}
}
}
private
static
void
doSanity
(
String
[]
args
)
{
for
(
String
s:
args
)
{
File
f
=
new
File
(
s
);
if
(
f
.
exists
())
{
jarList
.
add
(
f
);
}
else
{
System
.
out
.
println
(
"Warning: The JAR file "
+
f
.
toString
()
+
" does not exist,"
);
System
.
out
.
println
(
" this test requires a JDK image, this file will be skipped."
);
}
}
}
}
}
}
...
@@ -137,11 +123,12 @@ public class Pack200Test {
...
@@ -137,11 +123,12 @@ public class Pack200Test {
* @param args the command line arguments
* @param args the command line arguments
*/
*/
public
static
void
main
(
String
[]
args
)
{
public
static
void
main
(
String
[]
args
)
{
if
(
args
.
length
<
1
)
{
// select the jars carefully, adding more jars will increase the
System
.
out
.
println
(
"Usage: jar1 jar2 jar3 ....."
);
// testing time, especially for jprt.
System
.
exit
(
1
);
jarList
.
add
(
Utils
.
locateJar
(
"tools.jar"
));
}
jarList
.
add
(
Utils
.
locateJar
(
"rt.jar"
));
doSanity
(
args
);
jarList
.
add
(
Utils
.
locateJar
(
"golden.jar"
));
System
.
out
.
println
(
jarList
);
doPackUnpack
();
doPackUnpack
();
}
}
}
}
test/tools/pack200/PackageVersionTest.java
浏览文件 @
130dc864
...
@@ -22,13 +22,14 @@
...
@@ -22,13 +22,14 @@
* questions.
* questions.
*/
*/
/**
/*
* @test
* @test
* @bug 6712743
* @bug 6712743
* @summary verify package versioning
* @summary verify package versions
* @compile -XDignore.symbol.file PackageVersionTest.java
* @compile -XDignore.symbol.file Utils.java PackageVersionTest.java
* @run main PackageVersionTest
* @run main PackageVersionTest
*/
* @author ksrini
*/
import
java.io.ByteArrayOutputStream
;
import
java.io.ByteArrayOutputStream
;
import
java.io.Closeable
;
import
java.io.Closeable
;
...
@@ -74,14 +75,6 @@ public class PackageVersionTest {
...
@@ -74,14 +75,6 @@ public class PackageVersionTest {
JAVA5_PACKAGE_MINOR_VERSION
);
JAVA5_PACKAGE_MINOR_VERSION
);
}
}
static
void
close
(
Closeable
c
)
{
if
(
c
==
null
)
{
return
;
}
try
{
c
.
close
();
}
catch
(
IOException
ignore
)
{}
}
static
void
createClassFile
(
String
name
)
{
static
void
createClassFile
(
String
name
)
{
createJavaFile
(
name
);
createJavaFile
(
name
);
...
@@ -93,7 +86,7 @@ public class PackageVersionTest {
...
@@ -93,7 +86,7 @@ public class PackageVersionTest {
name
.
substring
(
name
.
length
()
-
1
),
name
.
substring
(
name
.
length
()
-
1
),
name
+
".java"
name
+
".java"
};
};
compileJava
(
javacCmds
);
Utils
.
compiler
(
javacCmds
);
}
}
static
void
createJavaFile
(
String
name
)
{
static
void
createJavaFile
(
String
name
)
{
...
@@ -108,22 +101,8 @@ public class PackageVersionTest {
...
@@ -108,22 +101,8 @@ public class PackageVersionTest {
}
catch
(
IOException
ioe
)
{
}
catch
(
IOException
ioe
)
{
throw
new
RuntimeException
(
"creation of test file failed"
);
throw
new
RuntimeException
(
"creation of test file failed"
);
}
finally
{
}
finally
{
close
(
ps
);
Utils
.
close
(
ps
);
close
(
fos
);
Utils
.
close
(
fos
);
}
}
static
void
compileJava
(
String
...
javacCmds
)
{
if
(
com
.
sun
.
tools
.
javac
.
Main
.
compile
(
javacCmds
)
!=
0
)
{
throw
new
RuntimeException
(
"compilation failed"
);
}
}
static
void
makeJar
(
String
...
jargs
)
{
sun
.
tools
.
jar
.
Main
jarTool
=
new
sun
.
tools
.
jar
.
Main
(
System
.
out
,
System
.
err
,
"jartool"
);
if
(!
jarTool
.
run
(
jargs
))
{
throw
new
RuntimeException
(
"jar command failed"
);
}
}
}
}
...
@@ -136,7 +115,7 @@ public class PackageVersionTest {
...
@@ -136,7 +115,7 @@ public class PackageVersionTest {
jarFileName
.
getName
(),
jarFileName
.
getName
(),
filename
filename
};
};
makeJ
ar
(
jargs
);
Utils
.
j
ar
(
jargs
);
JarFile
jfin
=
null
;
JarFile
jfin
=
null
;
try
{
try
{
...
@@ -163,7 +142,7 @@ public class PackageVersionTest {
...
@@ -163,7 +142,7 @@ public class PackageVersionTest {
}
catch
(
IOException
ioe
)
{
}
catch
(
IOException
ioe
)
{
throw
new
RuntimeException
(
ioe
.
getMessage
());
throw
new
RuntimeException
(
ioe
.
getMessage
());
}
finally
{
}
finally
{
close
(
jfin
);
Utils
.
close
((
Closeable
)
jfin
);
}
}
}
}
}
}
test/tools/pack200/TimeStamp.java
0 → 100644
浏览文件 @
130dc864
/*
* 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.
*/
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
.
locateJar
(
"golden.jar"
);
File
goldenFile
=
new
File
(
"golden.jar"
);
Utils
.
copyFile
(
srcFile
,
goldenFile
.
getAbsoluteFile
());
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
();
}
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"
);
}
}
}
test/tools/pack200/UnpackerMemoryTest.java
0 → 100644
浏览文件 @
130dc864
/*
* 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.
*/
/*
* @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
);
}
}
}
}
test/tools/pack200/Utils.java
0 → 100644
浏览文件 @
130dc864
/*
* Copyright (c) 2007, 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.
*/
import
java.io.BufferedReader
;
import
java.io.ByteArrayOutputStream
;
import
java.io.Closeable
;
import
java.io.File
;
import
java.io.FileFilter
;
import
java.io.FileInputStream
;
import
java.io.FileOutputStream
;
import
java.io.IOException
;
import
java.io.InputStream
;
import
java.io.InputStreamReader
;
import
java.io.PrintStream
;
import
java.nio.channels.FileChannel
;
import
java.util.ArrayList
;
import
java.util.Arrays
;
import
java.util.Collections
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.jar.JarFile
;
import
java.util.jar.JarOutputStream
;
import
java.util.jar.Pack200
;
import
java.util.zip.ZipEntry
;
import
java.util.zip.ZipFile
;
/**
*
* @author ksrini
*/
/*
* This class contains all the commonly used utilities used by various tests
* in this directory.
*/
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
).
getParentFile
();
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
String
VERIFIER_DIR_NAME
=
"pack200-verifier"
;
static
final
File
VerifierJar
=
new
File
(
VERIFIER_DIR_NAME
+
JAR_FILE_EXT
);
private
Utils
()
{}
// all static
static
{
if
(!
JavaHome
.
endsWith
(
"jre"
))
{
throw
new
RuntimeException
(
"Error: requires an SDK to run"
);
}
}
private
static
void
init
()
throws
IOException
{
if
(
VerifierJar
.
exists
())
{
return
;
}
File
srcDir
=
new
File
(
TEST_SRC_DIR
,
VERIFIER_DIR_NAME
);
List
<
File
>
javaFileList
=
findFiles
(
srcDir
,
createFilter
(
JAVA_FILE_EXT
));
File
tmpFile
=
File
.
createTempFile
(
"javac"
,
".tmp"
);
File
classesDir
=
new
File
(
"xclasses"
);
classesDir
.
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"
,
"@"
+
tmpFile
.
getAbsolutePath
());
jar
(
"cvfe"
,
VerifierJar
.
getName
(),
"sun.tools.pack.verify.Main"
,
"-C"
,
"xclasses"
,
"."
);
}
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
(
"-jar"
);
cmds
.
add
(
VerifierJar
.
getName
());
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
(
"-jar"
);
cmds
.
add
(
VerifierJar
.
getName
());
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
;
}
};
}
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
;
}
};
private
static
void
setFileAttributes
(
File
src
,
File
dst
)
throws
IOException
{
dst
.
setExecutable
(
src
.
canExecute
());
dst
.
setReadable
(
src
.
canRead
());
dst
.
setWritable
(
src
.
canWrite
());
dst
.
setLastModified
(
src
.
lastModified
());
}
static
void
copyFile
(
File
src
,
File
dst
)
throws
IOException
{
if
(
src
.
isDirectory
())
{
dst
.
mkdirs
();
setFileAttributes
(
src
,
dst
);
return
;
}
else
{
File
baseDirFile
=
dst
.
getParentFile
();
if
(!
baseDirFile
.
exists
())
{
baseDirFile
.
mkdirs
();
}
}
FileInputStream
in
=
null
;
FileOutputStream
out
=
null
;
FileChannel
srcChannel
=
null
;
FileChannel
dstChannel
=
null
;
try
{
in
=
new
FileInputStream
(
src
);
out
=
new
FileOutputStream
(
dst
);
srcChannel
=
in
.
getChannel
();
dstChannel
=
out
.
getChannel
();
long
retval
=
srcChannel
.
transferTo
(
0
,
src
.
length
(),
dstChannel
);
if
(
src
.
length
()
!=
dst
.
length
())
{
throw
new
IOException
(
"file copy failed for "
+
src
);
}
}
finally
{
close
(
srcChannel
);
close
(
dstChannel
);
close
(
in
);
close
(
out
);
}
setFileAttributes
(
src
,
dst
);
}
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
;
}
/*
* 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
);
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
)
{
if
(
com
.
sun
.
tools
.
javac
.
Main
.
compile
(
javacCmds
)
!=
0
)
{
throw
new
RuntimeException
(
"compilation failed"
);
}
}
static
void
jar
(
String
...
jargs
)
{
sun
.
tools
.
jar
.
Main
jarTool
=
new
sun
.
tools
.
jar
.
Main
(
System
.
out
,
System
.
err
,
"jartool"
);
if
(!
jarTool
.
run
(
jargs
))
{
throw
new
RuntimeException
(
"jar command failed"
);
}
}
// 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
(
List
<
String
>
cmdsList
)
{
return
runExec
(
cmdsList
,
null
);
}
static
List
<
String
>
runExec
(
List
<
String
>
cmdsList
,
Map
<
String
,
String
>
penv
)
{
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
(
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
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
;
}
private
static
List
<
File
>
locaterCache
=
null
;
// search the source dir and jdk dir for requested file and returns
// the first location it finds.
static
File
locateJar
(
String
name
)
{
try
{
if
(
locaterCache
==
null
)
{
locaterCache
=
new
ArrayList
<
File
>();
locaterCache
.
addAll
(
findFiles
(
TEST_SRC_DIR
,
createFilter
(
JAR_FILE_EXT
)));
locaterCache
.
addAll
(
findFiles
(
JavaSDK
,
createFilter
(
JAR_FILE_EXT
)));
}
for
(
File
f
:
locaterCache
)
{
if
(
f
.
getName
().
equals
(
name
))
{
return
f
;
}
}
throw
new
IOException
(
"file not found: "
+
name
);
}
catch
(
IOException
e
)
{
throw
new
RuntimeException
(
e
);
}
}
}
test/tools/pack200/pack200-verifier/data/README
0 → 100644
浏览文件 @
130dc864
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,
1. maximizing the test coverage.
2. exercising all the Bands in the pack200 specification.
2. testing the behavior of the packer with invalid classes.
3. 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.
2. 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:
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 inspect the directory to ensure all of the bands are being
generated. Familiarity of the Pack200 specification is suggested.
\ No newline at end of file
test/tools/pack200/pack200-verifier/data/golden.jar
0 → 100644
浏览文件 @
130dc864
文件已添加
test/tools/pack200/pack200-verifier/make/build.xml
0 → 100644
浏览文件 @
130dc864
<project
name=
"PackageVerify"
default=
"dist"
basedir=
".."
>
<!-- Requires ant 1.6.1+ and JDK 1.6+-->
<!-- 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.6"
srcdir=
"${src}"
destdir=
"${build}/classes"
verbose=
"no"
debug=
"on"
/>
</target>
<target
name=
"doc"
depends=
"init, compile"
>
<javadoc
source=
"1.6"
sourcepath=
"${src}"
destdir=
"${api}"
/>
</target>
<target
name=
"dist"
depends=
"compile, doc"
>
<!-- 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>
<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>
test/tools/pack200/pack200-verifier/src/sun/tools/pack/verify/ClassCompare.java
0 → 100644
浏览文件 @
130dc864
/*
* 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
);
}
}
test/tools/pack200/pack200-verifier/src/sun/tools/pack/verify/Globals.java
0 → 100644
浏览文件 @
130dc864
/*
* 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
(
"\tjava.ext.dirs="
+
System
.
getProperty
(
"java.ext.dirs"
));
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
);
}
}
test/tools/pack200/pack200-verifier/src/sun/tools/pack/verify/JarFileCompare.java
0 → 100644
浏览文件 @
130dc864
/*
* 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
);
}
}
}
test/tools/pack200/pack200-verifier/src/sun/tools/pack/verify/Main.java
0 → 100644
浏览文件 @
130dc864
/*
* 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
());
}
}
test/tools/pack200/pack200-verifier/src/sun/tools/pack/verify/VerifyTreeSet.java
0 → 100644
浏览文件 @
130dc864
/*
* 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
;
}
}
test/tools/pack200/pack200-verifier/src/xmlkit/ClassReader.java
0 → 100644
浏览文件 @
130dc864
/*
* 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
xmlkit
;
// -*- mode: java; indent-tabs-mode: nil -*-
import
java.util.*
;
import
java.util.jar.*
;
import
java.lang.reflect.*
;
import
java.io.*
;
import
xmlkit.XMLKit.Element
;
/*
* @author jrose
*/
public
class
ClassReader
extends
ClassSyntax
{
private
static
final
CommandLineParser
CLP
=
new
CommandLineParser
(
""
+
"-source: +> = \n"
+
"-dest: +> = \n"
+
"-encoding: +> = \n"
+
"-jcov $ \n -nojcov !-jcov \n"
+
"-verbose $ \n -noverbose !-verbose \n"
+
"-pretty $ \n -nopretty !-pretty \n"
+
"-keepPath $ \n -nokeepPath !-keepPath \n"
+
"-keepCP $ \n -nokeepCP !-keepCP \n"
+
"-keepBytes $ \n -nokeepBytes !-keepBytes \n"
+
"-parseBytes $ \n -noparseBytes !-parseBytes \n"
+
"-resolveRefs $ \n -noresolveRefs !-resolveRefs \n"
+
"-keepOrder $ \n -nokeepOrder !-keepOrder \n"
+
"-keepSizes $ \n -nokeepSizes !-keepSizes \n"
+
"-continue $ \n -nocontinue !-continue \n"
+
"-attrDef & \n"
+
"-@ >-@ . \n"
+
"- +? \n"
+
"\n"
);
public
static
void
main
(
String
[]
ava
)
throws
IOException
{
ArrayList
<
String
>
av
=
new
ArrayList
<
String
>(
Arrays
.
asList
(
ava
));
HashMap
<
String
,
String
>
props
=
new
HashMap
<
String
,
String
>();
props
.
put
(
"-encoding:"
,
"UTF8"
);
// default
props
.
put
(
"-keepOrder"
,
null
);
// CLI default
props
.
put
(
"-pretty"
,
"1"
);
// CLI default
props
.
put
(
"-continue"
,
"1"
);
// CLI default
CLP
.
parse
(
av
,
props
);
//System.out.println(props+" ++ "+av);
File
source
=
asFile
(
props
.
get
(
"-source:"
));
File
dest
=
asFile
(
props
.
get
(
"-dest:"
));
String
encoding
=
props
.
get
(
"-encoding:"
);
boolean
contError
=
props
.
containsKey
(
"-continue"
);
ClassReader
options
=
new
ClassReader
();
options
.
copyOptionsFrom
(
props
);
/*
if (dest == null && av.size() > 1) {
dest = File.createTempFile("TestOut", ".dir", new File("."));
dest.delete();
if (!dest.mkdir())
throw new RuntimeException("Cannot create "+dest);
System.out.println("Writing results to "+dest);
}
*/
if
(
av
.
isEmpty
())
{
av
.
add
(
"doit"
);
//to enter this loop
}
boolean
readList
=
false
;
for
(
String
a
:
av
)
{
if
(
readList
)
{
readList
=
false
;
InputStream
fin
;
if
(
a
.
equals
(
"-"
))
{
fin
=
System
.
in
;
}
else
{
fin
=
new
FileInputStream
(
a
);
}
BufferedReader
files
=
makeReader
(
fin
,
encoding
);
for
(
String
file
;
(
file
=
files
.
readLine
())
!=
null
;)
{
doFile
(
file
,
source
,
dest
,
options
,
encoding
,
contError
);
}
if
(
fin
!=
System
.
in
)
{
fin
.
close
();
}
}
else
if
(
a
.
equals
(
"-@"
))
{
readList
=
true
;
}
else
if
(
a
.
startsWith
(
"-"
))
{
throw
new
RuntimeException
(
"Bad flag argument: "
+
a
);
}
else
if
(
source
.
getName
().
endsWith
(
".jar"
))
{
doJar
(
a
,
source
,
dest
,
options
,
encoding
,
contError
);
}
else
{
doFile
(
a
,
source
,
dest
,
options
,
encoding
,
contError
);
}
}
}
private
static
File
asFile
(
String
str
)
{
return
(
str
==
null
)
?
null
:
new
File
(
str
);
}
private
static
void
doFile
(
String
a
,
File
source
,
File
dest
,
ClassReader
options
,
String
encoding
,
boolean
contError
)
throws
IOException
{
if
(!
contError
)
{
doFile
(
a
,
source
,
dest
,
options
,
encoding
);
}
else
{
try
{
doFile
(
a
,
source
,
dest
,
options
,
encoding
);
}
catch
(
Exception
ee
)
{
System
.
out
.
println
(
"Error processing "
+
source
+
": "
+
ee
);
}
}
}
private
static
void
doJar
(
String
a
,
File
source
,
File
dest
,
ClassReader
options
,
String
encoding
,
Boolean
contError
)
throws
IOException
{
try
{
JarFile
jf
=
new
JarFile
(
source
);
for
(
JarEntry
je
:
Collections
.
list
((
Enumeration
<
JarEntry
>)
jf
.
entries
()))
{
String
name
=
je
.
getName
();
if
(!
name
.
endsWith
(
".class"
))
{
continue
;
}
doStream
(
name
,
jf
.
getInputStream
(
je
),
dest
,
options
,
encoding
);
}
}
catch
(
IOException
ioe
)
{
if
(
contError
)
{
System
.
out
.
println
(
"Error processing "
+
source
+
": "
+
ioe
);
}
else
{
throw
ioe
;
}
}
}
private
static
void
doStream
(
String
a
,
InputStream
in
,
File
dest
,
ClassReader
options
,
String
encoding
)
throws
IOException
{
File
f
=
new
File
(
a
);
ClassReader
cr
=
new
ClassReader
(
options
);
Element
e
=
cr
.
readFrom
(
in
);
OutputStream
out
;
if
(
dest
==
null
)
{
//System.out.println(e.prettyString());
out
=
System
.
out
;
}
else
{
File
outf
=
new
File
(
dest
,
f
.
isAbsolute
()
?
f
.
getName
()
:
f
.
getPath
());
String
outName
=
outf
.
getName
();
File
outSubdir
=
outf
.
getParentFile
();
outSubdir
.
mkdirs
();
int
extPos
=
outName
.
lastIndexOf
(
'.'
);
if
(
extPos
>
0
)
{
outf
=
new
File
(
outSubdir
,
outName
.
substring
(
0
,
extPos
)
+
".xml"
);
}
out
=
new
FileOutputStream
(
outf
);
}
Writer
outw
=
makeWriter
(
out
,
encoding
);
if
(
options
.
pretty
||
!
options
.
keepOrder
)
{
e
.
writePrettyTo
(
outw
);
}
else
{
e
.
writeTo
(
outw
);
}
if
(
out
==
System
.
out
)
{
outw
.
write
(
"\n"
);
outw
.
flush
();
}
else
{
outw
.
close
();
}
}
private
static
void
doFile
(
String
a
,
File
source
,
File
dest
,
ClassReader
options
,
String
encoding
)
throws
IOException
{
File
inf
=
new
File
(
source
,
a
);
if
(
dest
!=
null
&&
options
.
verbose
)
{
System
.
out
.
println
(
"Reading "
+
inf
);
}
BufferedInputStream
in
=
new
BufferedInputStream
(
new
FileInputStream
(
inf
));
doStream
(
a
,
in
,
dest
,
options
,
encoding
);
}
public
static
BufferedReader
makeReader
(
InputStream
in
,
String
encoding
)
throws
IOException
{
// encoding in DEFAULT, '', UTF8, 8BIT, , or any valid encoding name
if
(
encoding
.
equals
(
"8BIT"
))
{
encoding
=
EIGHT_BIT_CHAR_ENCODING
;
}
if
(
encoding
.
equals
(
"UTF8"
))
{
encoding
=
UTF8_ENCODING
;
}
if
(
encoding
.
equals
(
"DEFAULT"
))
{
encoding
=
null
;
}
if
(
encoding
.
equals
(
"-"
))
{
encoding
=
null
;
}
Reader
inw
;
in
=
new
BufferedInputStream
(
in
);
// add buffering
if
(
encoding
==
null
)
{
inw
=
new
InputStreamReader
(
in
);
}
else
{
inw
=
new
InputStreamReader
(
in
,
encoding
);
}
return
new
BufferedReader
(
inw
);
// add buffering
}
public
static
Writer
makeWriter
(
OutputStream
out
,
String
encoding
)
throws
IOException
{
// encoding in DEFAULT, '', UTF8, 8BIT, , or any valid encoding name
if
(
encoding
.
equals
(
"8BIT"
))
{
encoding
=
EIGHT_BIT_CHAR_ENCODING
;
}
if
(
encoding
.
equals
(
"UTF8"
))
{
encoding
=
UTF8_ENCODING
;
}
if
(
encoding
.
equals
(
"DEFAULT"
))
{
encoding
=
null
;
}
if
(
encoding
.
equals
(
"-"
))
{
encoding
=
null
;
}
Writer
outw
;
if
(
encoding
==
null
)
{
outw
=
new
OutputStreamWriter
(
out
);
}
else
{
outw
=
new
OutputStreamWriter
(
out
,
encoding
);
}
return
new
BufferedWriter
(
outw
);
// add buffering
}
public
Element
result
()
{
return
cfile
;
}
protected
InputStream
in
;
protected
ByteArrayOutputStream
buf
=
new
ByteArrayOutputStream
(
1024
);
protected
byte
cpTag
[];
protected
String
cpName
[];
protected
String
[]
callables
;
// varies
public
static
final
String
REF_PREFIX
=
"#"
;
// input options
public
boolean
pretty
=
false
;
public
boolean
verbose
=
false
;
public
boolean
keepPath
=
false
;
public
boolean
keepCP
=
false
;
public
boolean
keepBytes
=
false
;
public
boolean
parseBytes
=
true
;
public
boolean
resolveRefs
=
true
;
public
boolean
keepOrder
=
true
;
public
boolean
keepSizes
=
false
;
public
ClassReader
()
{
super
.
cfile
=
new
Element
(
"ClassFile"
);
}
public
ClassReader
(
ClassReader
options
)
{
this
();
copyOptionsFrom
(
options
);
}
public
void
copyOptionsFrom
(
ClassReader
options
)
{
pretty
=
options
.
pretty
;
verbose
=
options
.
verbose
;
keepPath
=
options
.
keepPath
;
keepCP
=
options
.
keepCP
;
keepBytes
=
options
.
keepBytes
;
parseBytes
=
options
.
parseBytes
;
resolveRefs
=
options
.
resolveRefs
;
keepSizes
=
options
.
keepSizes
;
keepOrder
=
options
.
keepOrder
;
attrTypes
=
options
.
attrTypes
;
}
public
void
copyOptionsFrom
(
Map
<
String
,
String
>
options
)
{
if
(
options
.
containsKey
(
"-pretty"
))
{
pretty
=
(
options
.
get
(
"-pretty"
)
!=
null
);
}
if
(
options
.
containsKey
(
"-verbose"
))
{
verbose
=
(
options
.
get
(
"-verbose"
)
!=
null
);
}
if
(
options
.
containsKey
(
"-keepPath"
))
{
keepPath
=
(
options
.
get
(
"-keepPath"
)
!=
null
);
}
if
(
options
.
containsKey
(
"-keepCP"
))
{
keepCP
=
(
options
.
get
(
"-keepCP"
)
!=
null
);
}
if
(
options
.
containsKey
(
"-keepBytes"
))
{
keepBytes
=
(
options
.
get
(
"-keepBytes"
)
!=
null
);
}
if
(
options
.
containsKey
(
"-parseBytes"
))
{
parseBytes
=
(
options
.
get
(
"-parseBytes"
)
!=
null
);
}
if
(
options
.
containsKey
(
"-resolveRefs"
))
{
resolveRefs
=
(
options
.
get
(
"-resolveRefs"
)
!=
null
);
}
if
(
options
.
containsKey
(
"-keepSizes"
))
{
keepSizes
=
(
options
.
get
(
"-keepSizes"
)
!=
null
);
}
if
(
options
.
containsKey
(
"-keepOrder"
))
{
keepOrder
=
(
options
.
get
(
"-keepOrder"
)
!=
null
);
}
if
(
options
.
containsKey
(
"-attrDef"
))
{
addAttrTypes
(
options
.
get
(
"-attrDef"
).
split
(
" "
));
}
if
(
options
.
get
(
"-jcov"
)
!=
null
)
{
addJcovAttrTypes
();
}
}
public
Element
readFrom
(
InputStream
in
)
throws
IOException
{
this
.
in
=
in
;
// read the file header
int
magic
=
u4
();
if
(
magic
!=
0xCAFEBABE
)
{
throw
new
RuntimeException
(
"bad magic number "
+
Integer
.
toHexString
(
magic
));
}
cfile
.
setAttr
(
"magic"
,
""
+
magic
);
int
minver
=
u2
();
int
majver
=
u2
();
cfile
.
setAttr
(
"minver"
,
""
+
minver
);
cfile
.
setAttr
(
"majver"
,
""
+
majver
);
readCP
();
readClass
();
return
result
();
}
public
Element
readFrom
(
File
file
)
throws
IOException
{
InputStream
in
=
null
;
try
{
in
=
new
FileInputStream
(
file
);
Element
e
=
readFrom
(
new
BufferedInputStream
(
in
));
if
(
keepPath
)
{
e
.
setAttr
(
"path"
,
file
.
toString
());
}
return
e
;
}
finally
{
if
(
in
!=
null
)
{
in
.
close
();
}
}
}
private
void
readClass
()
throws
IOException
{
klass
=
new
Element
(
"Class"
);
cfile
.
add
(
klass
);
int
flags
=
u2
();
String
thisk
=
cpRef
();
String
superk
=
cpRef
();
klass
.
setAttr
(
"name"
,
thisk
);
boolean
flagsSync
=
((
flags
&
Modifier
.
SYNCHRONIZED
)
!=
0
);
flags
&=
~
Modifier
.
SYNCHRONIZED
;
String
flagString
=
flagString
(
flags
,
klass
);
if
(!
flagsSync
)
{
if
(
flagString
.
length
()
>
0
)
{
flagString
+=
" "
;
}
flagString
+=
"!synchronized"
;
}
klass
.
setAttr
(
"flags"
,
flagString
);
klass
.
setAttr
(
"super"
,
superk
);
for
(
int
len
=
u2
(),
i
=
0
;
i
<
len
;
i
++)
{
String
interk
=
cpRef
();
klass
.
add
(
new
Element
(
"Interface"
,
"name"
,
interk
));
}
Element
fields
=
readMembers
(
"Field"
);
klass
.
addAll
(
fields
);
Element
methods
=
readMembers
(
"Method"
);
if
(!
keepOrder
)
{
methods
.
sort
();
}
klass
.
addAll
(
methods
);
readAttributesFor
(
klass
);
klass
.
trimToSize
();
if
(
keepSizes
)
{
attachTo
(
cfile
,
formatAttrSizes
());
}
if
(
paddingSize
!=
0
)
{
cfile
.
setAttr
(
"padding"
,
""
+
paddingSize
);
}
}
private
Element
readMembers
(
String
kind
)
throws
IOException
{
int
len
=
u2
();
Element
members
=
new
Element
(
len
);
for
(
int
i
=
0
;
i
<
len
;
i
++)
{
Element
member
=
new
Element
(
kind
);
int
flags
=
u2
();
String
name
=
cpRef
();
String
type
=
cpRef
();
member
.
setAttr
(
"name"
,
name
);
member
.
setAttr
(
"type"
,
type
);
member
.
setAttr
(
"flags"
,
flagString
(
flags
,
member
));
readAttributesFor
(
member
);
member
.
trimToSize
();
members
.
add
(
member
);
}
return
members
;
}
protected
String
flagString
(
int
flags
,
Element
holder
)
{
// Superset of Modifier.toString.
int
kind
=
0
;
if
(
holder
.
getName
()
==
"Field"
)
{
kind
=
1
;
}
if
(
holder
.
getName
()
==
"Method"
)
{
kind
=
2
;
}
StringBuffer
sb
=
new
StringBuffer
();
for
(
int
i
=
0
;
flags
!=
0
;
i
++,
flags
>>>=
1
)
{
if
((
flags
&
1
)
!=
0
)
{
if
(
sb
.
length
()
>
0
)
{
sb
.
append
(
' '
);
}
if
(
i
<
modifierNames
.
length
)
{
String
[]
names
=
modifierNames
[
i
];
String
name
=
(
kind
<
names
.
length
)
?
names
[
kind
]
:
null
;
for
(
String
name2
:
names
)
{
if
(
name
!=
null
)
{
break
;
}
name
=
name2
;
}
sb
.
append
(
name
);
}
else
{
sb
.
append
(
"#"
).
append
(
1
<<
i
);
}
}
}
return
sb
.
toString
();
}
private
void
readAttributesFor
(
Element
x
)
throws
IOException
{
Element
prevCurrent
;
Element
y
=
new
Element
();
if
(
x
.
getName
()
==
"Code"
)
{
prevCurrent
=
currentCode
;
currentCode
=
x
;
}
else
{
prevCurrent
=
currentMember
;
currentMember
=
x
;
}
for
(
int
len
=
u2
(),
i
=
0
;
i
<
len
;
i
++)
{
int
ref
=
u2
();
String
uname
=
cpName
(
ref
).
intern
();
String
refName
=
uname
;
if
(!
resolveRefs
)
{
refName
=
(
REF_PREFIX
+
ref
).
intern
();
}
String
qname
=
(
x
.
getName
()
+
"."
+
uname
).
intern
();
String
wname
=
(
"*."
+
uname
).
intern
();
String
type
=
attrTypes
.
get
(
qname
);
if
(
type
==
null
||
""
.
equals
(
type
))
{
type
=
attrTypes
.
get
(
wname
);
}
if
(
""
.
equals
(
type
))
{
type
=
null
;
}
int
size
=
u4
();
int
[]
countVar
=
attrSizes
.
get
(
qname
);
if
(
countVar
==
null
)
{
attrSizes
.
put
(
qname
,
countVar
=
new
int
[
2
]);
}
countVar
[
0
]
+=
1
;
countVar
[
1
]
+=
size
;
buf
.
reset
();
for
(
int
j
=
0
;
j
<
size
;
j
++)
{
buf
.
write
(
u1
());
}
if
(
type
==
null
&&
size
==
0
)
{
y
.
add
(
new
Element
(
uname
));
// <Bridge>, etc.
}
else
if
(
type
==
null
)
{
//System.out.println("Warning: No attribute type description: "+qname);
// write cdata attribute
Element
a
=
new
Element
(
"Attribute"
,
new
String
[]{
"Name"
,
refName
},
buf
.
toString
(
EIGHT_BIT_CHAR_ENCODING
));
a
.
addContent
(
getCPDigest
());
y
.
add
(
a
);
}
else
if
(
type
.
equals
(
""
))
{
// ignore this attribute...
}
else
{
InputStream
in0
=
in
;
int
fileSize0
=
fileSize
;
ByteArrayInputStream
in1
=
new
ByteArrayInputStream
(
buf
.
toByteArray
());
boolean
ok
=
false
;
try
{
in
=
in1
;
// parse according to type desc.
Element
aval
;
if
(
type
.
equals
(
"<Code>..."
))
{
// delve into Code attribute
aval
=
readCode
();
}
else
if
(
type
.
equals
(
"<Frame>..."
))
{
// delve into StackMap attribute
aval
=
readStackMap
(
false
);
}
else
if
(
type
.
equals
(
"<FrameX>..."
))
{
// delve into StackMap attribute
aval
=
readStackMap
(
true
);
}
else
if
(
type
.
startsWith
(
"["
))
{
aval
=
readAttributeCallables
(
type
);
}
else
{
aval
=
readAttribute
(
type
);
}
//System.out.println("attachTo 1 "+y+" <- "+aval);
attachTo
(
y
,
aval
);
if
(
false
&&
in1
.
available
()
!=
0
)
{
throw
new
RuntimeException
(
"extra bytes in "
+
qname
+
" :"
+
in1
.
available
());
}
ok
=
true
;
}
finally
{
in
=
in0
;
fileSize
=
fileSize0
;
if
(!
ok
)
{
System
.
out
.
println
(
"*** Failed to read "
+
type
);
}
}
}
}
if
(
x
.
getName
()
==
"Code"
)
{
currentCode
=
prevCurrent
;
}
else
{
currentMember
=
prevCurrent
;
}
if
(!
keepOrder
)
{
y
.
sort
();
y
.
sortAttrs
();
}
//System.out.println("attachTo 2 "+x+" <- "+y);
attachTo
(
x
,
y
);
}
private
int
fileSize
=
0
;
private
int
paddingSize
=
0
;
private
HashMap
<
String
,
int
[]>
attrSizes
=
new
HashMap
<
String
,
int
[]>();
private
Element
formatAttrSizes
()
{
Element
e
=
new
Element
(
"Sizes"
);
e
.
setAttr
(
"fileSize"
,
""
+
fileSize
);
for
(
Map
.
Entry
<
String
,
int
[]>
ie
:
attrSizes
.
entrySet
())
{
int
[]
countVar
=
ie
.
getValue
();
e
.
add
(
new
Element
(
"AttrSize"
,
"name"
,
ie
.
getKey
().
toString
(),
"count"
,
""
+
countVar
[
0
],
"size"
,
""
+
countVar
[
1
]));
}
return
e
;
}
private
void
attachTo
(
Element
x
,
Object
aval0
)
{
if
(
aval0
==
null
)
{
return
;
}
//System.out.println("attachTo "+x+" : "+aval0);
if
(!(
aval0
instanceof
Element
))
{
x
.
add
(
aval0
);
return
;
}
Element
aval
=
(
Element
)
aval0
;
if
(!
aval
.
isAnonymous
())
{
x
.
add
(
aval
);
return
;
}
for
(
int
imax
=
aval
.
attrSize
(),
i
=
0
;
i
<
imax
;
i
++)
{
//%%
attachAttrTo
(
x
,
aval
.
getAttrName
(
i
),
aval
.
getAttr
(
i
));
}
x
.
addAll
(
aval
);
}
private
void
attachAttrTo
(
Element
x
,
String
aname
,
String
aval
)
{
//System.out.println("attachAttrTo "+x+" : "+aname+"="+aval);
String
aval0
=
x
.
getAttr
(
aname
);
if
(
aval0
!=
null
)
{
aval
=
aval0
+
" "
+
aval
;
}
x
.
setAttr
(
aname
,
aval
);
}
private
Element
readAttributeCallables
(
String
type
)
throws
IOException
{
assert
(
callables
==
null
);
callables
=
getBodies
(
type
);
Element
res
=
readAttribute
(
callables
[
0
]);
callables
=
null
;
return
res
;
}
private
Element
readAttribute
(
String
type
)
throws
IOException
{
//System.out.println("readAttribute "+type);
Element
aval
=
new
Element
();
String
nextAttrName
=
null
;
for
(
int
len
=
type
.
length
(),
next
,
i
=
0
;
i
<
len
;
i
=
next
)
{
String
value
;
switch
(
type
.
charAt
(
i
))
{
case
'<'
:
assert
(
nextAttrName
==
null
);
next
=
type
.
indexOf
(
'>'
,
++
i
);
String
form
=
type
.
substring
(
i
,
next
++);
if
(
form
.
indexOf
(
'='
)
<
0
)
{
// elem_placement = '<' elemname '>'
assert
(
aval
.
attrSize
()
==
0
);
assert
(
aval
.
isAnonymous
());
aval
.
setName
(
form
.
intern
());
}
else
{
// attr_placement = '<' attrname '=' (value)? '>'
int
eqPos
=
form
.
indexOf
(
'='
);
nextAttrName
=
form
.
substring
(
0
,
eqPos
).
intern
();
if
(
eqPos
!=
form
.
length
()
-
1
)
{
value
=
form
.
substring
(
eqPos
+
1
);
attachAttrTo
(
aval
,
nextAttrName
,
value
);
nextAttrName
=
null
;
}
// ...else subsequent type parsing will find the attr value
// and add it as "nextAttrName".
}
continue
;
case
'('
:
next
=
type
.
indexOf
(
')'
,
++
i
);
int
callee
=
Integer
.
parseInt
(
type
.
substring
(
i
,
next
++));
attachTo
(
aval
,
readAttribute
(
callables
[
callee
]));
continue
;
case
'N'
:
// replication = 'N' int '[' type ... ']'
{
int
count
=
getInt
(
type
.
charAt
(
i
+
1
),
false
);
assert
(
count
>=
0
);
next
=
i
+
2
;
String
type1
=
getBody
(
type
,
next
);
next
+=
type1
.
length
()
+
2
;
// skip body and brackets
for
(
int
j
=
0
;
j
<
count
;
j
++)
{
attachTo
(
aval
,
readAttribute
(
type1
));
}
}
continue
;
case
'T'
:
// union = 'T' any_int union_case* '(' ')' '[' body ']'
int
tagValue
;
if
(
type
.
charAt
(++
i
)
==
'S'
)
{
tagValue
=
getInt
(
type
.
charAt
(++
i
),
true
);
}
else
{
tagValue
=
getInt
(
type
.
charAt
(
i
),
false
);
}
attachAttrTo
(
aval
,
"tag"
,
""
+
tagValue
);
// always named "tag"
++
i
;
// skip the int type char
// union_case = '(' uc_tag (',' uc_tag)* ')' '[' body ']'
// uc_tag = ('-')? digit+
for
(
boolean
foundCase
=
false
;;
i
=
next
)
{
assert
(
type
.
charAt
(
i
)
==
'('
);
next
=
type
.
indexOf
(
')'
,
++
i
);
assert
(
next
>=
i
);
if
(
type
.
charAt
(
next
-
1
)
==
'\\'
&&
type
.
charAt
(
next
-
2
)
!=
'\\'
)
// Skip an escaped paren.
{
next
=
type
.
indexOf
(
')'
,
next
+
1
);
}
String
caseStr
=
type
.
substring
(
i
,
next
++);
String
type1
=
getBody
(
type
,
next
);
next
+=
type1
.
length
()
+
2
;
// skip body and brackets
boolean
lastCase
=
(
caseStr
.
length
()
==
0
);
if
(!
foundCase
&&
(
lastCase
||
matchTag
(
tagValue
,
caseStr
)))
{
foundCase
=
true
;
// Execute this body.
attachTo
(
aval
,
readAttribute
(
type1
));
}
if
(
lastCase
)
{
break
;
}
}
continue
;
case
'B'
:
case
'H'
:
case
'I'
:
// int = oneof "BHI"
next
=
i
+
1
;
value
=
""
+
getInt
(
type
.
charAt
(
i
),
false
);
break
;
case
'K'
:
assert
(
"IJFDLQ"
.
indexOf
(
type
.
charAt
(
i
+
1
))
>=
0
);
assert
(
type
.
charAt
(
i
+
2
)
==
'H'
);
// only H works for now
next
=
i
+
3
;
value
=
cpRef
();
break
;
case
'R'
:
assert
(
"CSDFMIU?"
.
indexOf
(
type
.
charAt
(
i
+
1
))
>=
0
);
assert
(
type
.
charAt
(
i
+
2
)
==
'H'
);
// only H works for now
next
=
i
+
3
;
value
=
cpRef
();
break
;
case
'P'
:
// bci = 'P' int
next
=
i
+
2
;
value
=
""
+
getInt
(
type
.
charAt
(
i
+
1
),
false
);
break
;
case
'S'
:
// signed_int = 'S' int
next
=
i
+
2
;
value
=
""
+
getInt
(
type
.
charAt
(
i
+
1
),
true
);
break
;
case
'F'
:
next
=
i
+
2
;
value
=
flagString
(
getInt
(
type
.
charAt
(
i
+
1
),
false
),
currentMember
);
break
;
default
:
throw
new
RuntimeException
(
"bad attr format '"
+
type
.
charAt
(
i
)
+
"': "
+
type
);
}
// store the value
if
(
nextAttrName
!=
null
)
{
attachAttrTo
(
aval
,
nextAttrName
,
value
);
nextAttrName
=
null
;
}
else
{
attachTo
(
aval
,
value
);
}
}
//System.out.println("readAttribute => "+aval);
assert
(
nextAttrName
==
null
);
return
aval
;
}
private
int
getInt
(
char
ch
,
boolean
signed
)
throws
IOException
{
if
(
signed
)
{
switch
(
ch
)
{
case
'B'
:
return
(
byte
)
u1
();
case
'H'
:
return
(
short
)
u2
();
case
'I'
:
return
(
int
)
u4
();
}
}
else
{
switch
(
ch
)
{
case
'B'
:
return
u1
();
case
'H'
:
return
u2
();
case
'I'
:
return
u4
();
}
}
assert
(
"BHIJ"
.
indexOf
(
ch
)
>=
0
);
return
0
;
}
private
Element
readCode
()
throws
IOException
{
int
stack
=
u2
();
int
local
=
u2
();
int
length
=
u4
();
StringBuilder
sb
=
new
StringBuilder
(
length
);
for
(
int
i
=
0
;
i
<
length
;
i
++)
{
sb
.
append
((
char
)
u1
());
}
String
bytecodes
=
sb
.
toString
();
Element
e
=
new
Element
(
"Code"
,
"stack"
,
""
+
stack
,
"local"
,
""
+
local
);
Element
bytes
=
new
Element
(
"Bytes"
,
(
String
[])
null
,
bytecodes
);
if
(
keepBytes
)
{
e
.
add
(
bytes
);
}
if
(
parseBytes
)
{
e
.
add
(
parseByteCodes
(
bytecodes
));
}
for
(
int
len
=
u2
(),
i
=
0
;
i
<
len
;
i
++)
{
int
start
=
u2
();
int
end
=
u2
();
int
catsh
=
u2
();
String
clasz
=
cpRef
();
e
.
add
(
new
Element
(
"Handler"
,
"start"
,
""
+
start
,
"end"
,
""
+
end
,
"catch"
,
""
+
catsh
,
"class"
,
clasz
));
}
readAttributesFor
(
e
);
e
.
trimToSize
();
return
e
;
}
private
Element
parseByteCodes
(
String
bytecodes
)
{
Element
e
=
InstructionSyntax
.
parse
(
bytecodes
);
for
(
Element
ins
:
e
.
elements
())
{
Number
ref
=
ins
.
getAttrNumber
(
"ref"
);
if
(
ref
!=
null
&&
resolveRefs
)
{
int
id
=
ref
.
intValue
();
String
val
=
cpName
(
id
);
if
(
ins
.
getName
().
startsWith
(
"ldc"
))
{
// Yuck: Arb. string cannot be an XML attribute.
ins
.
add
(
val
);
val
=
""
;
byte
tag
=
(
id
>=
0
&&
id
<
cpTag
.
length
)
?
cpTag
[
id
]
:
0
;
if
(
tag
!=
0
)
{
ins
.
setAttrLong
(
"tag"
,
tag
);
}
}
if
(
ins
.
getName
()
==
"invokeinterface"
&&
computeInterfaceNum
(
val
)
==
ins
.
getAttrLong
(
"num"
))
{
ins
.
setAttr
(
"num"
,
null
);
// garbage bytes
}
ins
.
setAttr
(
"ref"
,
null
);
ins
.
setAttr
(
"val"
,
val
);
}
}
return
e
;
}
private
Element
readStackMap
(
boolean
hasXOption
)
throws
IOException
{
Element
result
=
new
Element
();
Element
bytes
=
currentCode
.
findElement
(
"Bytes"
);
assert
(
bytes
!=
null
&&
bytes
.
size
()
==
1
);
int
byteLength
=
((
String
)
bytes
.
get
(
0
)).
length
();
boolean
uoffsetIsU4
=
(
byteLength
>=
(
1
<<
16
));
boolean
ulocalvarIsU4
=
currentCode
.
getAttrLong
(
"local"
)
>=
(
1
<<
16
);
boolean
ustackIsU4
=
currentCode
.
getAttrLong
(
"stack"
)
>=
(
1
<<
16
);
if
(
hasXOption
||
uoffsetIsU4
||
ulocalvarIsU4
||
ustackIsU4
)
{
Element
flags
=
new
Element
(
"StackMapFlags"
);
if
(
hasXOption
)
{
flags
.
setAttr
(
"hasXOption"
,
"true"
);
}
if
(
uoffsetIsU4
)
{
flags
.
setAttr
(
"uoffsetIsU4"
,
"true"
);
}
if
(
ulocalvarIsU4
)
{
flags
.
setAttr
(
"ulocalvarIsU4"
,
"true"
);
}
if
(
ustackIsU4
)
{
flags
.
setAttr
(
"ustackIsU4"
,
"true"
);
}
currentCode
.
add
(
flags
);
}
int
frame_count
=
(
uoffsetIsU4
?
u4
()
:
u2
());
for
(
int
i
=
0
;
i
<
frame_count
;
i
++)
{
int
bci
=
(
uoffsetIsU4
?
u4
()
:
u2
());
int
flags
=
(
hasXOption
?
u1
()
:
0
);
Element
frame
=
new
Element
(
"Frame"
);
result
.
add
(
frame
);
if
(
flags
!=
0
)
{
frame
.
setAttr
(
"flags"
,
""
+
flags
);
}
frame
.
setAttr
(
"bci"
,
""
+
bci
);
// Scan local and stack types in this frame:
final
int
LOCALS
=
0
,
STACK
=
1
;
for
(
int
j
=
LOCALS
;
j
<=
STACK
;
j
++)
{
int
typeSize
;
if
(
j
==
LOCALS
)
{
typeSize
=
(
ulocalvarIsU4
?
u4
()
:
u2
());
}
else
{
// STACK
typeSize
=
(
ustackIsU4
?
u4
()
:
u2
());
}
Element
types
=
new
Element
(
j
==
LOCALS
?
"Local"
:
"Stack"
);
for
(
int
k
=
0
;
k
<
typeSize
;
k
++)
{
int
tag
=
u1
();
Element
type
=
new
Element
(
itemTagName
(
tag
));
types
.
add
(
type
);
switch
(
tag
)
{
case
ITEM_Object:
type
.
setAttr
(
"class"
,
cpRef
());
break
;
case
ITEM_Uninitialized:
case
ITEM_ReturnAddress:
type
.
setAttr
(
"bci"
,
""
+
(
uoffsetIsU4
?
u4
()
:
u2
()));
break
;
}
}
if
(
types
.
size
()
>
0
)
{
frame
.
add
(
types
);
}
}
}
return
result
;
}
private
void
readCP
()
throws
IOException
{
int
cpLen
=
u2
();
cpTag
=
new
byte
[
cpLen
];
cpName
=
new
String
[
cpLen
];
int
cpTem
[][]
=
new
int
[
cpLen
][];
for
(
int
i
=
1
;
i
<
cpLen
;
i
++)
{
cpTag
[
i
]
=
(
byte
)
u1
();
switch
(
cpTag
[
i
])
{
case
CONSTANT_Utf8:
buf
.
reset
();
for
(
int
len
=
u2
(),
j
=
0
;
j
<
len
;
j
++)
{
buf
.
write
(
u1
());
}
cpName
[
i
]
=
buf
.
toString
(
UTF8_ENCODING
);
break
;
case
CONSTANT_Integer:
cpName
[
i
]
=
String
.
valueOf
((
int
)
u4
());
break
;
case
CONSTANT_Float:
cpName
[
i
]
=
String
.
valueOf
(
Float
.
intBitsToFloat
(
u4
()));
break
;
case
CONSTANT_Long:
cpName
[
i
]
=
String
.
valueOf
(
u8
());
i
+=
1
;
break
;
case
CONSTANT_Double:
cpName
[
i
]
=
String
.
valueOf
(
Double
.
longBitsToDouble
(
u8
()));
i
+=
1
;
break
;
case
CONSTANT_Class:
case
CONSTANT_String:
cpTem
[
i
]
=
new
int
[]{
u2
()};
break
;
case
CONSTANT_Fieldref:
case
CONSTANT_Methodref:
case
CONSTANT_InterfaceMethodref:
case
CONSTANT_NameAndType:
cpTem
[
i
]
=
new
int
[]{
u2
(),
u2
()};
break
;
}
}
for
(
int
i
=
1
;
i
<
cpLen
;
i
++)
{
switch
(
cpTag
[
i
])
{
case
CONSTANT_Class:
case
CONSTANT_String:
cpName
[
i
]
=
cpName
[
cpTem
[
i
][
0
]];
break
;
case
CONSTANT_NameAndType:
cpName
[
i
]
=
cpName
[
cpTem
[
i
][
0
]]
+
" "
+
cpName
[
cpTem
[
i
][
1
]];
break
;
}
}
// do fieldref et al after nameandtype are all resolved
for
(
int
i
=
1
;
i
<
cpLen
;
i
++)
{
switch
(
cpTag
[
i
])
{
case
CONSTANT_Fieldref:
case
CONSTANT_Methodref:
case
CONSTANT_InterfaceMethodref:
cpName
[
i
]
=
cpName
[
cpTem
[
i
][
0
]]
+
" "
+
cpName
[
cpTem
[
i
][
1
]];
break
;
}
}
cpool
=
new
Element
(
"ConstantPool"
,
cpName
.
length
);
for
(
int
i
=
0
;
i
<
cpName
.
length
;
i
++)
{
if
(
cpName
[
i
]
==
null
)
{
continue
;
}
cpool
.
add
(
new
Element
(
cpTagName
(
cpTag
[
i
]),
new
String
[]{
"id"
,
""
+
i
},
cpName
[
i
]));
}
if
(
keepCP
)
{
cfile
.
add
(
cpool
);
}
}
private
String
cpRef
()
throws
IOException
{
int
ref
=
u2
();
if
(
resolveRefs
)
{
return
cpName
(
ref
);
}
else
{
return
REF_PREFIX
+
ref
;
}
}
private
String
cpName
(
int
id
)
{
if
(
id
>=
0
&&
id
<
cpName
.
length
)
{
return
cpName
[
id
];
}
else
{
return
"[CP#"
+
Integer
.
toHexString
(
id
)
+
"]"
;
}
}
private
long
u8
()
throws
IOException
{
return
((
long
)
u4
()
<<
32
)
+
(((
long
)
u4
()
<<
32
)
>>>
32
);
}
private
int
u4
()
throws
IOException
{
return
(
u2
()
<<
16
)
+
u2
();
}
private
int
u2
()
throws
IOException
{
return
(
u1
()
<<
8
)
+
u1
();
}
private
int
u1
()
throws
IOException
{
int
x
=
in
.
read
();
if
(
x
<
0
)
{
paddingSize
++;
return
0
;
// error recovery
}
fileSize
++;
assert
(
x
==
(
x
&
0xFF
));
return
x
;
}
}
test/tools/pack200/pack200-verifier/src/xmlkit/ClassSyntax.java
0 → 100644
浏览文件 @
130dc864
/*
* 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
xmlkit
;
// -*- mode: java; indent-tabs-mode: nil -*-
import
xmlkit.XMLKit.*
;
import
java.util.*
;
import
java.security.MessageDigest
;
import
java.nio.ByteBuffer
;
import
xmlkit.XMLKit.Element
;
/*
* @author jrose
*/
public
abstract
class
ClassSyntax
{
public
interface
GetCPIndex
{
int
getCPIndex
(
int
tag
,
String
name
);
// cp finder
}
public
static
final
int
CONSTANT_Utf8
=
1
,
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
;
private
static
final
String
[]
cpTagName
=
{
/* 0: */
null
,
/* 1: */
"Utf8"
,
/* 2: */
null
,
/* 3: */
"Integer"
,
/* 4: */
"Float"
,
/* 5: */
"Long"
,
/* 6: */
"Double"
,
/* 7: */
"Class"
,
/* 8: */
"String"
,
/* 9: */
"Fieldref"
,
/* 10: */
"Methodref"
,
/* 11: */
"InterfaceMethodref"
,
/* 12: */
"NameAndType"
,
null
};
private
static
final
Set
<
String
>
cpTagNames
;
static
{
Set
<
String
>
set
=
new
HashSet
<
String
>(
Arrays
.
asList
(
cpTagName
));
set
.
remove
(
null
);
cpTagNames
=
Collections
.
unmodifiableSet
(
set
);
}
public
static
final
int
ITEM_Top
=
0
,
// replicates by [1..4,1..4]
ITEM_Integer
=
1
,
// (ditto)
ITEM_Float
=
2
,
ITEM_Double
=
3
,
ITEM_Long
=
4
,
ITEM_Null
=
5
,
ITEM_UninitializedThis
=
6
,
ITEM_Object
=
7
,
ITEM_Uninitialized
=
8
,
ITEM_ReturnAddress
=
9
,
ITEM_LIMIT
=
10
;
private
static
final
String
[]
itemTagName
=
{
"Top"
,
"Integer"
,
"Float"
,
"Double"
,
"Long"
,
"Null"
,
"UninitializedThis"
,
"Object"
,
"Uninitialized"
,
"ReturnAddress"
,};
private
static
final
Set
<
String
>
itemTagNames
;
static
{
Set
<
String
>
set
=
new
HashSet
<
String
>(
Arrays
.
asList
(
itemTagName
));
set
.
remove
(
null
);
itemTagNames
=
Collections
.
unmodifiableSet
(
set
);
}
protected
static
final
HashMap
<
String
,
String
>
attrTypesBacking
;
protected
static
final
Map
<
String
,
String
>
attrTypesInit
;
static
{
HashMap
<
String
,
String
>
at
=
new
HashMap
<
String
,
String
>();
//at.put("*.Deprecated", "<deprecated=true>");
//at.put("*.Synthetic", "<synthetic=true>");
////at.put("Field.ConstantValue", "<constantValue=>KQH");
//at.put("Class.SourceFile", "<sourceFile=>RUH");
at
.
put
(
"Method.Bridge"
,
"<Bridge>"
);
at
.
put
(
"Method.Varargs"
,
"<Varargs>"
);
at
.
put
(
"Class.Enum"
,
"<Enum>"
);
at
.
put
(
"*.Signature"
,
"<Signature>RSH"
);
//at.put("*.Deprecated", "<Deprecated>");
//at.put("*.Synthetic", "<Synthetic>");
at
.
put
(
"Field.ConstantValue"
,
"<ConstantValue>KQH"
);
at
.
put
(
"Class.SourceFile"
,
"<SourceFile>RUH"
);
at
.
put
(
"Class.InnerClasses"
,
"NH[<InnerClass><class=>RCH<outer=>RCH<name=>RUH<flags=>FH]"
);
at
.
put
(
"Code.LineNumberTable"
,
"NH[<LineNumber><bci=>PH<line=>H]"
);
at
.
put
(
"Code.LocalVariableTable"
,
"NH[<LocalVariable><bci=>PH<span=>H<name=>RUH<type=>RSH<slot=>H]"
);
at
.
put
(
"Code.LocalVariableTypeTable"
,
"NH[<LocalVariableType><bci=>PH<span=>H<name=>RUH<type=>RSH<slot=>H]"
);
at
.
put
(
"Method.Exceptions"
,
"NH[<Exception><name=>RCH]"
);
at
.
put
(
"Method.Code"
,
"<Code>..."
);
at
.
put
(
"Code.StackMapTable"
,
"<Frame>..."
);
//at.put("Code.StkMapX", "<FrameX>...");
if
(
true
)
{
at
.
put
(
"Code.StackMapTable"
,
"[NH[<Frame>(1)]]"
+
"[TB"
+
"(64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79"
+
",80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95"
+
",96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111"
+
",112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127"
+
")[<SameLocals1StackItemFrame>(4)]"
+
"(247)[<SameLocals1StackItemExtended>H(4)]"
+
"(248)[<Chop3>H]"
+
"(249)[<Chop2>H]"
+
"(250)[<Chop1>H]"
+
"(251)[<SameFrameExtended>H]"
+
"(252)[<Append1>H(4)]"
+
"(253)[<Append2>H(4)(4)]"
+
"(254)[<Append3>H(4)(4)(4)]"
+
"(255)[<FullFrame>H(2)(3)]"
+
"()[<SameFrame>]]"
+
"[NH[<Local>(4)]]"
+
"[NH[<Stack>(4)]]"
+
"[TB"
+
(
"(0)[<Top>]"
+
"(1)[<ItemInteger>](2)[<ItemFloat>](3)[<ItemDouble>](4)[<ItemLong>]"
+
"(5)[<ItemNull>](6)[<ItemUninitializedThis>]"
+
"(7)[<ItemObject><class=>RCH]"
+
"(8)[<ItemUninitialized><bci=>PH]"
+
"()[<ItemUnknown>]]"
));
}
at
.
put
(
"Class.EnclosingMethod"
,
"<EnclosingMethod><class=>RCH<desc=>RDH"
);
//RDNH
// Layouts of metadata attrs:
String
vpf
=
"[<RuntimeVisibleAnnotation>"
;
String
ipf
=
"[<RuntimeInvisibleAnnotation>"
;
String
apf
=
"[<Annotation>"
;
String
mdanno2
=
""
+
"<type=>RSHNH[<Member><name=>RUH(3)]]"
+
(
"[TB"
+
"(\\B,\\C,\\I,\\S,\\Z)[<value=>KIH]"
+
"(\\D)[<value=>KDH]"
+
"(\\F)[<value=>KFH]"
+
"(\\J)[<value=>KJH]"
+
"(\\c)[<class=>RSH]"
+
"(\\e)[<type=>RSH<name=>RUH]"
+
"(\\s)[<String>RUH]"
+
"(\\@)[(2)]"
+
"(\\[)[NH[<Element>(3)]]"
+
"()[]"
+
"]"
);
String
visanno
=
"[NH[(2)]][(1)]"
+
vpf
+
mdanno2
;
String
invanno
=
"[NH[(2)]][(1)]"
+
ipf
+
mdanno2
;
String
vparamanno
=
""
+
"[NB[<RuntimeVisibleParameterAnnotation>(1)]][NH[(2)]]"
+
apf
+
mdanno2
;
String
iparamanno
=
""
+
"[NB[<RuntimeInvisibleParameterAnnotation>(1)]][NH[(2)]]"
+
apf
+
mdanno2
;
String
mdannodef
=
"[<AnnotationDefault>(3)][(1)]"
+
apf
+
mdanno2
;
String
[]
mdplaces
=
{
"Class"
,
"Field"
,
"Method"
};
for
(
String
place
:
mdplaces
)
{
at
.
put
(
place
+
".RuntimeVisibleAnnotations"
,
visanno
);
at
.
put
(
place
+
".RuntimeInvisibleAnnotations"
,
invanno
);
}
at
.
put
(
"Method.RuntimeVisibleParameterAnnotations"
,
vparamanno
);
at
.
put
(
"Method.RuntimeInvisibleParameterAnnotations"
,
iparamanno
);
at
.
put
(
"Method.AnnotationDefault"
,
mdannodef
);
attrTypesBacking
=
at
;
attrTypesInit
=
Collections
.
unmodifiableMap
(
at
);
}
;
private
static
final
String
[]
jcovAttrTypes
=
{
"Code.CoverageTable=NH[<Coverage><bci=>PH<type=>H<line=>I<pos=>I]"
,
"Code.CharacterRangeTable=NH[<CharacterRange><bci=>PH<endbci=>POH<from=>I<to=>I<flag=>H]"
,
"Class.SourceID=<SourceID><id=>RUH"
,
"Class.CompilationID=<CompilationID><id=>RUH"
};
protected
static
final
String
[][]
modifierNames
=
{
{
"public"
},
{
"private"
},
{
"protected"
},
{
"static"
},
{
"final"
},
{
"synchronized"
},
{
null
,
"volatile"
,
"bridge"
},
{
null
,
"transient"
,
"varargs"
},
{
null
,
null
,
"native"
},
{
"interface"
},
{
"abstract"
},
{
"strictfp"
},
{
"synthetic"
},
{
"annotation"
},
{
"enum"
},};
protected
static
final
String
EIGHT_BIT_CHAR_ENCODING
=
"ISO8859_1"
;
protected
static
final
String
UTF8_ENCODING
=
"UTF8"
;
// What XML tags are used by this syntax, apart from attributes?
protected
static
final
Set
<
String
>
nonAttrTags
;
static
{
HashSet
<
String
>
tagSet
=
new
HashSet
<
String
>();
Collections
.
addAll
(
tagSet
,
new
String
[]{
"ConstantPool"
,
// the CP
"Class"
,
// the class
"Interface"
,
// implemented interfaces
"Method"
,
// methods
"Field"
,
// fields
"Handler"
,
// exception handler pseudo-attribute
"Attribute"
,
// unparsed attribute
"Bytes"
,
// bytecodes
"Instructions"
// bytecodes, parsed
});
nonAttrTags
=
Collections
.
unmodifiableSet
(
tagSet
);
}
// Accessors.
public
static
Set
<
String
>
nonAttrTags
()
{
return
nonAttrTags
;
}
public
static
String
cpTagName
(
int
t
)
{
t
&=
0xFF
;
String
ts
=
null
;
if
(
t
<
cpTagName
.
length
)
{
ts
=
cpTagName
[
t
];
}
if
(
ts
!=
null
)
{
return
ts
;
}
return
(
"UnknownTag"
+
(
int
)
t
).
intern
();
}
public
static
int
cpTagValue
(
String
name
)
{
for
(
int
t
=
0
;
t
<
cpTagName
.
length
;
t
++)
{
if
(
name
.
equals
(
cpTagName
[
t
]))
{
return
t
;
}
}
return
0
;
}
public
static
String
itemTagName
(
int
t
)
{
t
&=
0xFF
;
String
ts
=
null
;
if
(
t
<
itemTagName
.
length
)
{
ts
=
itemTagName
[
t
];
}
if
(
ts
!=
null
)
{
return
ts
;
}
return
(
"UnknownItem"
+
(
int
)
t
).
intern
();
}
public
static
int
itemTagValue
(
String
name
)
{
for
(
int
t
=
0
;
t
<
itemTagName
.
length
;
t
++)
{
if
(
name
.
equals
(
itemTagName
[
t
]))
{
return
t
;
}
}
return
-
1
;
}
public
void
addJcovAttrTypes
()
{
addAttrTypes
(
jcovAttrTypes
);
}
// Public methods for declaring attribute types.
protected
Map
<
String
,
String
>
attrTypes
=
attrTypesInit
;
public
void
addAttrType
(
String
opt
)
{
int
eqpos
=
opt
.
indexOf
(
'='
);
addAttrType
(
opt
.
substring
(
0
,
eqpos
),
opt
.
substring
(
eqpos
+
1
));
}
public
void
addAttrTypes
(
String
[]
opts
)
{
for
(
String
opt
:
opts
)
{
addAttrType
(
opt
);
}
}
private
void
checkAttr
(
String
attr
)
{
if
(!
attr
.
startsWith
(
"Class."
)
&&
!
attr
.
startsWith
(
"Field."
)
&&
!
attr
.
startsWith
(
"Method."
)
&&
!
attr
.
startsWith
(
"Code."
)
&&
!
attr
.
startsWith
(
"*."
))
{
throw
new
IllegalArgumentException
(
"attr name must start with 'Class.', etc."
);
}
String
uattr
=
attr
.
substring
(
attr
.
indexOf
(
'.'
)
+
1
);
if
(
nonAttrTags
.
contains
(
uattr
))
{
throw
new
IllegalArgumentException
(
"attr name must not be one of "
+
nonAttrTags
);
}
}
private
void
checkAttrs
(
Map
<
String
,
String
>
at
)
{
for
(
String
attr
:
at
.
keySet
())
{
checkAttr
(
attr
);
}
}
private
void
modAttrs
()
{
if
(
attrTypes
==
attrTypesInit
)
{
// Make modifiable.
attrTypes
=
new
HashMap
<
String
,
String
>(
attrTypesBacking
);
}
}
public
void
addAttrType
(
String
attr
,
String
fmt
)
{
checkAttr
(
attr
);
modAttrs
();
attrTypes
.
put
(
attr
,
fmt
);
}
public
void
addAttrTypes
(
Map
<
String
,
String
>
at
)
{
checkAttrs
(
at
);
modAttrs
();
attrTypes
.
putAll
(
at
);
}
public
Map
<
String
,
String
>
getAttrTypes
()
{
if
(
attrTypes
==
attrTypesInit
)
{
return
attrTypes
;
}
return
Collections
.
unmodifiableMap
(
attrTypes
);
}
public
void
setAttrTypes
(
Map
<
String
,
String
>
at
)
{
checkAttrs
(
at
);
modAttrs
();
attrTypes
.
keySet
().
retainAll
(
at
.
keySet
());
attrTypes
.
putAll
(
at
);
}
// attr format helpers
protected
static
boolean
matchTag
(
int
tagValue
,
String
caseStr
)
{
//System.out.println("matchTag "+tagValue+" in "+caseStr);
for
(
int
pos
=
0
,
max
=
caseStr
.
length
(),
comma
;
pos
<
max
;
pos
=
comma
+
1
)
{
int
caseValue
;
if
(
caseStr
.
charAt
(
pos
)
==
'\\'
)
{
caseValue
=
caseStr
.
charAt
(
pos
+
1
);
comma
=
pos
+
2
;
assert
(
comma
==
max
||
caseStr
.
charAt
(
comma
)
==
','
);
}
else
{
comma
=
caseStr
.
indexOf
(
','
,
pos
);
if
(
comma
<
0
)
{
comma
=
max
;
}
caseValue
=
Integer
.
parseInt
(
caseStr
.
substring
(
pos
,
comma
));
}
if
(
tagValue
==
caseValue
)
{
return
true
;
}
}
return
false
;
}
protected
static
String
[]
getBodies
(
String
type
)
{
ArrayList
<
String
>
bodies
=
new
ArrayList
<
String
>();
for
(
int
i
=
0
;
i
<
type
.
length
();)
{
String
body
=
getBody
(
type
,
i
);
bodies
.
add
(
body
);
i
+=
body
.
length
()
+
2
;
// skip body and brackets
}
return
bodies
.
toArray
(
new
String
[
bodies
.
size
()]);
}
protected
static
String
getBody
(
String
type
,
int
i
)
{
assert
(
type
.
charAt
(
i
)
==
'['
);
int
next
=
++
i
;
// skip bracket
for
(
int
depth
=
1
;
depth
>
0
;
next
++)
{
switch
(
type
.
charAt
(
next
))
{
case
'['
:
depth
++;
break
;
case
']'
:
depth
--;
break
;
case
'('
:
next
=
type
.
indexOf
(
')'
,
next
);
break
;
case
'<'
:
next
=
type
.
indexOf
(
'>'
,
next
);
break
;
}
assert
(
next
>
0
);
}
--
next
;
// get before bracket
assert
(
type
.
charAt
(
next
)
==
']'
);
return
type
.
substring
(
i
,
next
);
}
public
Element
makeCPDigest
(
int
length
)
{
MessageDigest
md
;
try
{
md
=
MessageDigest
.
getInstance
(
"MD5"
);
}
catch
(
java
.
security
.
NoSuchAlgorithmException
ee
)
{
throw
new
Error
(
ee
);
}
int
items
=
0
;
for
(
Element
e
:
cpool
.
elements
())
{
if
(
items
==
length
)
{
break
;
}
if
(
cpTagNames
.
contains
(
e
.
getName
()))
{
items
+=
1
;
md
.
update
((
byte
)
cpTagValue
(
e
.
getName
()));
try
{
md
.
update
(
e
.
getText
().
toString
().
getBytes
(
UTF8_ENCODING
));
}
catch
(
java
.
io
.
UnsupportedEncodingException
ee
)
{
throw
new
Error
(
ee
);
}
}
}
ByteBuffer
bb
=
ByteBuffer
.
wrap
(
md
.
digest
());
String
l0
=
Long
.
toHexString
(
bb
.
getLong
(
0
));
String
l1
=
Long
.
toHexString
(
bb
.
getLong
(
8
));
while
(
l0
.
length
()
<
16
)
{
l0
=
"0"
+
l0
;
}
while
(
l1
.
length
()
<
16
)
{
l1
=
"0"
+
l1
;
}
return
new
Element
(
"Digest"
,
"length"
,
""
+
items
,
"bytes"
,
l0
+
l1
);
}
public
Element
getCPDigest
(
int
length
)
{
if
(
length
==
-
1
)
{
length
=
cpool
.
countAll
(
XMLKit
.
elementFilter
(
cpTagNames
));
}
for
(
Element
md
:
cpool
.
findAllElements
(
"Digest"
).
elements
())
{
if
(
md
.
getAttrLong
(
"length"
)
==
length
)
{
return
md
;
}
}
Element
md
=
makeCPDigest
(
length
);
cpool
.
add
(
md
);
return
md
;
}
public
Element
getCPDigest
()
{
return
getCPDigest
(-
1
);
}
public
boolean
checkCPDigest
(
Element
md
)
{
return
md
.
equals
(
getCPDigest
((
int
)
md
.
getAttrLong
(
"length"
)));
}
public
static
int
computeInterfaceNum
(
String
intMethRef
)
{
intMethRef
=
intMethRef
.
substring
(
1
+
intMethRef
.
lastIndexOf
(
' '
));
if
(!
intMethRef
.
startsWith
(
"("
))
{
return
-
1
;
}
int
signum
=
1
;
// start with one for "this"
scanSig:
for
(
int
i
=
1
;
i
<
intMethRef
.
length
();
i
++)
{
char
ch
=
intMethRef
.
charAt
(
i
);
signum
++;
switch
(
ch
)
{
case
')'
:
--
signum
;
break
scanSig
;
case
'L'
:
i
=
intMethRef
.
indexOf
(
';'
,
i
);
break
;
case
'['
:
while
(
ch
==
'['
)
{
ch
=
intMethRef
.
charAt
(++
i
);
}
if
(
ch
==
'L'
)
{
i
=
intMethRef
.
indexOf
(
';'
,
i
);
}
break
;
}
}
int
num
=
(
signum
<<
8
)
|
0
;
//System.out.println("computeInterfaceNum "+intMethRef+" => "+num);
return
num
;
}
// Protected state for representing the class file.
protected
Element
cfile
;
// <ClassFile ...>
protected
Element
cpool
;
// <ConstantPool ...>
protected
Element
klass
;
// <Class ...>
protected
Element
currentMember
;
// varies during scans
protected
Element
currentCode
;
// varies during scans
}
test/tools/pack200/pack200-verifier/src/xmlkit/ClassWriter.java
0 → 100644
浏览文件 @
130dc864
/*
* 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
xmlkit
;
// -*- mode: java; indent-tabs-mode: nil -*-
import
java.util.*
;
import
java.lang.reflect.*
;
import
java.io.*
;
import
xmlkit.XMLKit.Element
;
/*
* @author jrose
*/
public
class
ClassWriter
extends
ClassSyntax
implements
ClassSyntax
.
GetCPIndex
{
private
static
final
CommandLineParser
CLP
=
new
CommandLineParser
(
""
+
"-source: +> = \n"
+
"-dest: +> = \n"
+
"-encoding: +> = \n"
+
"-parseBytes $ \n"
+
"- *? \n"
+
"\n"
);
public
static
void
main
(
String
[]
ava
)
throws
IOException
{
ArrayList
<
String
>
av
=
new
ArrayList
<
String
>(
Arrays
.
asList
(
ava
));
HashMap
<
String
,
String
>
props
=
new
HashMap
<
String
,
String
>();
props
.
put
(
"-encoding:"
,
"UTF8"
);
// default
CLP
.
parse
(
av
,
props
);
File
source
=
asFile
(
props
.
get
(
"-source:"
));
File
dest
=
asFile
(
props
.
get
(
"-dest:"
));
String
encoding
=
props
.
get
(
"-encoding:"
);
boolean
parseBytes
=
props
.
containsKey
(
"-parseBytes"
);
boolean
destMade
=
false
;
for
(
String
a
:
av
)
{
File
f
;
File
inf
=
new
File
(
source
,
a
);
System
.
out
.
println
(
"Reading "
+
inf
);
Element
e
;
if
(
inf
.
getName
().
endsWith
(
".class"
))
{
ClassReader
cr
=
new
ClassReader
();
cr
.
parseBytes
=
parseBytes
;
e
=
cr
.
readFrom
(
inf
);
f
=
new
File
(
a
);
}
else
if
(
inf
.
getName
().
endsWith
(
".xml"
))
{
InputStream
in
=
new
FileInputStream
(
inf
);
Reader
inw
=
ClassReader
.
makeReader
(
in
,
encoding
);
e
=
XMLKit
.
readFrom
(
inw
);
e
.
findAllInTree
(
XMLKit
.
and
(
XMLKit
.
elementFilter
(
nonAttrTags
()),
XMLKit
.
methodFilter
(
Element
.
method
(
"trimText"
))));
//System.out.println(e);
inw
.
close
();
f
=
new
File
(
a
.
substring
(
0
,
a
.
length
()
-
".xml"
.
length
())
+
".class"
);
}
else
{
System
.
out
.
println
(
"Warning: unknown input "
+
a
);
continue
;
}
// Now write it:
if
(!
destMade
)
{
destMade
=
true
;
if
(
dest
==
null
)
{
dest
=
File
.
createTempFile
(
"TestOut"
,
".dir"
,
new
File
(
"."
));
dest
.
delete
();
System
.
out
.
println
(
"Writing results to "
+
dest
);
}
if
(!(
dest
.
isDirectory
()
||
dest
.
mkdir
()))
{
throw
new
RuntimeException
(
"Cannot create "
+
dest
);
}
}
File
outf
=
new
File
(
dest
,
f
.
isAbsolute
()
?
f
.
getName
()
:
f
.
getPath
());
outf
.
getParentFile
().
mkdirs
();
new
ClassWriter
(
e
).
writeTo
(
outf
);
}
}
private
static
File
asFile
(
String
str
)
{
return
(
str
==
null
)
?
null
:
new
File
(
str
);
}
public
void
writeTo
(
File
file
)
throws
IOException
{
OutputStream
out
=
null
;
try
{
out
=
new
BufferedOutputStream
(
new
FileOutputStream
(
file
));
writeTo
(
out
);
}
finally
{
if
(
out
!=
null
)
{
out
.
close
();
}
}
}
protected
String
[]
callables
;
// varies
protected
int
cpoolSize
=
0
;
protected
HashMap
<
String
,
String
>
attrTypesByTag
;
protected
OutputStream
out
;
protected
HashMap
<
String
,
int
[]>
cpMap
=
new
HashMap
<
String
,
int
[]>();
protected
ArrayList
<
ByteArrayOutputStream
>
attrBufs
=
new
ArrayList
<
ByteArrayOutputStream
>();
private
void
setupAttrTypes
()
{
attrTypesByTag
=
new
HashMap
<
String
,
String
>();
for
(
String
key
:
attrTypes
.
keySet
())
{
String
pfx
=
key
.
substring
(
0
,
key
.
indexOf
(
'.'
)
+
1
);
String
val
=
attrTypes
.
get
(
key
);
int
pos
=
val
.
indexOf
(
'<'
);
if
(
pos
>=
0
)
{
String
tag
=
val
.
substring
(
pos
+
1
,
val
.
indexOf
(
'>'
,
pos
));
attrTypesByTag
.
put
(
pfx
+
tag
,
key
);
}
}
//System.out.println("attrTypesByTag: "+attrTypesByTag);
}
protected
ByteArrayOutputStream
getAttrBuf
()
{
int
nab
=
attrBufs
.
size
();
if
(
nab
==
0
)
{
return
new
ByteArrayOutputStream
(
1024
);
}
ByteArrayOutputStream
ab
=
attrBufs
.
get
(
nab
-
1
);
attrBufs
.
remove
(
nab
-
1
);
return
ab
;
}
protected
void
putAttrBuf
(
ByteArrayOutputStream
ab
)
{
ab
.
reset
();
attrBufs
.
add
(
ab
);
}
public
ClassWriter
(
Element
root
)
{
this
(
root
,
null
);
}
public
ClassWriter
(
Element
root
,
ClassSyntax
cr
)
{
if
(
cr
!=
null
)
{
attrTypes
=
cr
.
attrTypes
;
}
setupAttrTypes
();
if
(
root
.
getName
()
==
"ClassFile"
)
{
cfile
=
root
;
cpool
=
root
.
findElement
(
"ConstantPool"
);
klass
=
root
.
findElement
(
"Class"
);
}
else
if
(
root
.
getName
()
==
"Class"
)
{
cfile
=
new
Element
(
"ClassFile"
,
new
String
[]{
"magic"
,
String
.
valueOf
(
0xCAFEBABE
),
"minver"
,
"0"
,
"majver"
,
"46"
,});
cpool
=
new
Element
(
"ConstantPool"
);
klass
=
root
;
}
else
{
throw
new
IllegalArgumentException
(
"bad element type "
+
root
.
getName
());
}
if
(
cpool
==
null
)
{
cpool
=
new
Element
(
"ConstantPool"
);
}
int
cpLen
=
1
+
cpool
.
size
();
for
(
Element
c
:
cpool
.
elements
())
{
int
id
=
(
int
)
c
.
getAttrLong
(
"id"
);
int
tag
=
cpTagValue
(
c
.
getName
());
setCPIndex
(
tag
,
c
.
getText
().
toString
(),
id
);
switch
(
tag
)
{
case
CONSTANT_Long:
case
CONSTANT_Double:
cpLen
+=
1
;
}
}
cpoolSize
=
cpLen
;
}
public
int
findCPIndex
(
int
tag
,
String
name
)
{
if
(
name
==
null
)
{
return
0
;
}
int
[]
ids
=
cpMap
.
get
(
name
.
toString
());
return
(
ids
==
null
)
?
0
:
ids
[
tag
];
}
public
int
getCPIndex
(
int
tag
,
String
name
)
{
//System.out.println("getCPIndex "+cpTagName(tag)+" "+name);
if
(
name
==
null
)
{
return
0
;
}
int
id
=
findCPIndex
(
tag
,
name
);
if
(
id
==
0
)
{
id
=
cpoolSize
;
cpoolSize
+=
1
;
setCPIndex
(
tag
,
name
,
id
);
cpool
.
add
(
new
Element
(
cpTagName
(
tag
),
new
String
[]{
"id"
,
""
+
id
},
new
Object
[]{
name
}));
int
pos
;
switch
(
tag
)
{
case
CONSTANT_Long:
case
CONSTANT_Double:
cpoolSize
+=
1
;
break
;
case
CONSTANT_Class:
case
CONSTANT_String:
getCPIndex
(
CONSTANT_Utf8
,
name
);
break
;
case
CONSTANT_Fieldref:
case
CONSTANT_Methodref:
case
CONSTANT_InterfaceMethodref:
pos
=
name
.
indexOf
(
' '
);
getCPIndex
(
CONSTANT_Class
,
name
.
substring
(
0
,
pos
));
getCPIndex
(
CONSTANT_NameAndType
,
name
.
substring
(
pos
+
1
));
break
;
case
CONSTANT_NameAndType:
pos
=
name
.
indexOf
(
' '
);
getCPIndex
(
CONSTANT_Utf8
,
name
.
substring
(
0
,
pos
));
getCPIndex
(
CONSTANT_Utf8
,
name
.
substring
(
pos
+
1
));
break
;
}
}
return
id
;
}
public
void
setCPIndex
(
int
tag
,
String
name
,
int
id
)
{
//System.out.println("setCPIndex id="+id+" tag="+tag+" name="+name);
int
[]
ids
=
cpMap
.
get
(
name
);
if
(
ids
==
null
)
{
cpMap
.
put
(
name
,
ids
=
new
int
[
13
]);
}
if
(
ids
[
tag
]
!=
0
&&
ids
[
tag
]
!=
id
)
{
System
.
out
.
println
(
"Warning: Duplicate CP entries for "
+
ids
[
tag
]
+
" and "
+
id
);
}
//assert(ids[tag] == 0 || ids[tag] == id);
ids
[
tag
]
=
id
;
}
public
int
parseFlags
(
String
flagString
)
{
int
flags
=
0
;
int
i
=
-
1
;
for
(
String
[]
names
:
modifierNames
)
{
++
i
;
for
(
String
name
:
names
)
{
if
(
name
==
null
)
{
continue
;
}
int
pos
=
flagString
.
indexOf
(
name
);
if
(
pos
>=
0
)
{
flags
|=
(
1
<<
i
);
}
}
}
return
flags
;
}
public
void
writeTo
(
OutputStream
realOut
)
throws
IOException
{
OutputStream
headOut
=
realOut
;
ByteArrayOutputStream
tailOut
=
new
ByteArrayOutputStream
();
// write the body of the class file first
this
.
out
=
tailOut
;
writeClass
();
// write the file header last
this
.
out
=
headOut
;
u4
((
int
)
cfile
.
getAttrLong
(
"magic"
));
u2
((
int
)
cfile
.
getAttrLong
(
"minver"
));
u2
((
int
)
cfile
.
getAttrLong
(
"majver"
));
writeCP
();
// recopy the file tail
this
.
out
=
null
;
tailOut
.
writeTo
(
realOut
);
}
void
writeClass
()
throws
IOException
{
int
flags
=
parseFlags
(
klass
.
getAttr
(
"flags"
));
flags
^=
Modifier
.
SYNCHRONIZED
;
u2
(
flags
);
cpRef
(
CONSTANT_Class
,
klass
.
getAttr
(
"name"
));
cpRef
(
CONSTANT_Class
,
klass
.
getAttr
(
"super"
));
Element
interfaces
=
klass
.
findAllElements
(
"Interface"
);
u2
(
interfaces
.
size
());
for
(
Element
e
:
interfaces
.
elements
())
{
cpRef
(
CONSTANT_Class
,
e
.
getAttr
(
"name"
));
}
for
(
int
isMethod
=
0
;
isMethod
<=
1
;
isMethod
++)
{
Element
members
=
klass
.
findAllElements
(
isMethod
!=
0
?
"Method"
:
"Field"
);
u2
(
members
.
size
());
for
(
Element
m
:
members
.
elements
())
{
writeMember
(
m
,
isMethod
!=
0
);
}
}
writeAttributesFor
(
klass
);
}
private
void
writeMember
(
Element
member
,
boolean
isMethod
)
throws
IOException
{
//System.out.println("writeMember "+member);
u2
(
parseFlags
(
member
.
getAttr
(
"flags"
)));
cpRef
(
CONSTANT_Utf8
,
member
.
getAttr
(
"name"
));
cpRef
(
CONSTANT_Utf8
,
member
.
getAttr
(
"type"
));
writeAttributesFor
(
member
);
}
protected
void
writeAttributesFor
(
Element
x
)
throws
IOException
{
LinkedHashSet
<
String
>
attrNames
=
new
LinkedHashSet
<
String
>();
for
(
Element
e
:
x
.
elements
())
{
attrNames
.
add
(
e
.
getName
());
// uniquifying
}
attrNames
.
removeAll
(
nonAttrTags
());
u2
(
attrNames
.
size
());
if
(
attrNames
.
isEmpty
())
{
return
;
}
Element
prevCurrent
;
if
(
x
.
getName
()
==
"Code"
)
{
prevCurrent
=
currentCode
;
currentCode
=
x
;
}
else
{
prevCurrent
=
currentMember
;
currentMember
=
x
;
}
OutputStream
realOut
=
this
.
out
;
for
(
String
utag
:
attrNames
)
{
String
qtag
=
x
.
getName
()
+
"."
+
utag
;
String
wtag
=
"*."
+
utag
;
String
key
=
attrTypesByTag
.
get
(
qtag
);
if
(
key
==
null
)
{
key
=
attrTypesByTag
.
get
(
wtag
);
}
String
type
=
attrTypes
.
get
(
key
);
//System.out.println("tag "+qtag+" => key "+key+"; type "+type);
Element
attrs
=
x
.
findAllElements
(
utag
);
ByteArrayOutputStream
attrBuf
=
getAttrBuf
();
if
(
type
==
null
)
{
if
(
attrs
.
size
()
!=
1
||
!
attrs
.
get
(
0
).
equals
(
new
Element
(
utag
)))
{
System
.
out
.
println
(
"Warning: No attribute type description: "
+
qtag
);
}
key
=
wtag
;
}
else
{
try
{
this
.
out
=
attrBuf
;
// unparse according to type desc.
if
(
type
.
equals
(
"<Code>..."
))
{
writeCode
((
Element
)
attrs
.
get
(
0
));
// assume only 1
}
else
if
(
type
.
equals
(
"<Frame>..."
))
{
writeStackMap
(
attrs
,
false
);
}
else
if
(
type
.
equals
(
"<FrameX>..."
))
{
writeStackMap
(
attrs
,
true
);
}
else
if
(
type
.
startsWith
(
"["
))
{
writeAttributeRecursive
(
attrs
,
type
);
}
else
{
writeAttribute
(
attrs
,
type
);
}
}
finally
{
//System.out.println("Attr Bytes = \""+attrBuf.toString(EIGHT_BIT_CHAR_ENCODING).replace('"', (char)('"'|0x80))+"\"");
this
.
out
=
realOut
;
}
}
cpRef
(
CONSTANT_Utf8
,
key
.
substring
(
key
.
indexOf
(
'.'
)
+
1
));
u4
(
attrBuf
.
size
());
attrBuf
.
writeTo
(
out
);
putAttrBuf
(
attrBuf
);
}
if
(
x
.
getName
()
==
"Code"
)
{
currentCode
=
prevCurrent
;
}
else
{
currentMember
=
prevCurrent
;
}
}
private
void
writeAttributeRecursive
(
Element
aval
,
String
type
)
throws
IOException
{
assert
(
callables
==
null
);
callables
=
getBodies
(
type
);
writeAttribute
(
aval
,
callables
[
0
]);
callables
=
null
;
}
private
void
writeAttribute
(
Element
aval
,
String
type
)
throws
IOException
{
//System.out.println("writeAttribute "+aval+" using "+type);
String
nextAttrName
=
null
;
boolean
afterElemHead
=
false
;
for
(
int
len
=
type
.
length
(),
next
,
i
=
0
;
i
<
len
;
i
=
next
)
{
int
value
;
char
intKind
;
int
tag
;
int
sigChar
;
String
attrValue
;
switch
(
type
.
charAt
(
i
))
{
case
'<'
:
assert
(
nextAttrName
==
null
);
next
=
type
.
indexOf
(
'>'
,
i
);
String
form
=
type
.
substring
(
i
+
1
,
next
++);
if
(
form
.
indexOf
(
'='
)
<
0
)
{
// elem_placement = '<' elemname '>'
if
(
aval
.
isAnonymous
())
{
assert
(
aval
.
size
()
==
1
);
aval
=
(
Element
)
aval
.
get
(
0
);
}
assert
(
aval
.
getName
().
equals
(
form
))
:
aval
+
" // "
+
form
;
afterElemHead
=
true
;
}
else
{
// attr_placement = '(' attrname '=' (value)? ')'
int
eqPos
=
form
.
indexOf
(
'='
);
assert
(
eqPos
>=
0
);
nextAttrName
=
form
.
substring
(
0
,
eqPos
).
intern
();
if
(
eqPos
!=
form
.
length
()
-
1
)
{
// value is implicit, not placed in file
nextAttrName
=
null
;
}
afterElemHead
=
false
;
}
continue
;
case
'('
:
next
=
type
.
indexOf
(
')'
,
++
i
);
int
callee
=
Integer
.
parseInt
(
type
.
substring
(
i
,
next
++));
writeAttribute
(
aval
,
callables
[
callee
]);
continue
;
case
'N'
:
// replication = 'N' int '[' type ... ']'
{
assert
(
nextAttrName
==
null
);
afterElemHead
=
false
;
char
countType
=
type
.
charAt
(
i
+
1
);
next
=
i
+
2
;
String
type1
=
getBody
(
type
,
next
);
Element
elems
=
aval
;
if
(
type1
.
startsWith
(
"<"
))
{
// Select only matching members of aval.
String
elemName
=
type1
.
substring
(
1
,
type1
.
indexOf
(
'>'
));
elems
=
aval
.
findAllElements
(
elemName
);
}
putInt
(
elems
.
size
(),
countType
);
next
+=
type1
.
length
()
+
2
;
// skip body and brackets
for
(
Element
elem
:
elems
.
elements
())
{
writeAttribute
(
elem
,
type1
);
}
}
continue
;
case
'T'
:
// union = 'T' any_int union_case* '(' ')' '[' body ']'
// write the value
value
=
(
int
)
aval
.
getAttrLong
(
"tag"
);
assert
(
aval
.
getAttr
(
"tag"
)
!=
null
)
:
aval
;
intKind
=
type
.
charAt
(++
i
);
if
(
intKind
==
'S'
)
{
intKind
=
type
.
charAt
(++
i
);
}
putInt
(
value
,
intKind
);
nextAttrName
=
null
;
afterElemHead
=
false
;
++
i
;
// skip the int type char
// union_case = '(' ('-')? digit+ ')' '[' body ']'
for
(
boolean
foundCase
=
false
;;)
{
assert
(
type
.
charAt
(
i
)
==
'('
);
next
=
type
.
indexOf
(
')'
,
++
i
);
assert
(
next
>=
i
);
String
caseStr
=
type
.
substring
(
i
,
next
++);
String
type1
=
getBody
(
type
,
next
);
next
+=
type1
.
length
()
+
2
;
// skip body and brackets
boolean
lastCase
=
(
caseStr
.
length
()
==
0
);
if
(!
foundCase
&&
(
lastCase
||
matchTag
(
value
,
caseStr
)))
{
foundCase
=
true
;
// Execute this body.
writeAttribute
(
aval
,
type1
);
}
if
(
lastCase
)
{
break
;
}
}
continue
;
case
'B'
:
case
'H'
:
case
'I'
:
// int = oneof "BHI"
value
=
(
int
)
aval
.
getAttrLong
(
nextAttrName
);
intKind
=
type
.
charAt
(
i
);
next
=
i
+
1
;
break
;
case
'K'
:
sigChar
=
type
.
charAt
(
i
+
1
);
if
(
sigChar
==
'Q'
)
{
assert
(
currentMember
.
getName
()
==
"Field"
);
assert
(
aval
.
getName
()
==
"ConstantValue"
);
String
sig
=
currentMember
.
getAttr
(
"type"
);
sigChar
=
sig
.
charAt
(
0
);
switch
(
sigChar
)
{
case
'Z'
:
case
'B'
:
case
'C'
:
case
'S'
:
sigChar
=
'I'
;
break
;
}
}
switch
(
sigChar
)
{
case
'I'
:
tag
=
CONSTANT_Integer
;
break
;
case
'J'
:
tag
=
CONSTANT_Long
;
break
;
case
'F'
:
tag
=
CONSTANT_Float
;
break
;
case
'D'
:
tag
=
CONSTANT_Double
;
break
;
case
'L'
:
tag
=
CONSTANT_String
;
break
;
default
:
assert
(
false
);
tag
=
0
;
}
assert
(
type
.
charAt
(
i
+
2
)
==
'H'
);
// only H works for now
next
=
i
+
3
;
assert
(
afterElemHead
||
nextAttrName
!=
null
);
//System.out.println("get attr "+nextAttrName+" in "+aval);
if
(
nextAttrName
!=
null
)
{
attrValue
=
aval
.
getAttr
(
nextAttrName
);
assert
(
attrValue
!=
null
);
}
else
{
assert
(
aval
.
isText
())
:
aval
;
attrValue
=
aval
.
getText
().
toString
();
}
value
=
getCPIndex
(
tag
,
attrValue
);
intKind
=
'H'
;
//type.charAt(i+2);
break
;
case
'R'
:
sigChar
=
type
.
charAt
(
i
+
1
);
switch
(
sigChar
)
{
case
'C'
:
tag
=
CONSTANT_Class
;
break
;
case
'S'
:
tag
=
CONSTANT_Utf8
;
break
;
case
'D'
:
tag
=
CONSTANT_Class
;
break
;
case
'F'
:
tag
=
CONSTANT_Fieldref
;
break
;
case
'M'
:
tag
=
CONSTANT_Methodref
;
break
;
case
'I'
:
tag
=
CONSTANT_InterfaceMethodref
;
break
;
case
'U'
:
tag
=
CONSTANT_Utf8
;
break
;
//case 'Q': tag = CONSTANT_Class; break;
default
:
assert
(
false
);
tag
=
0
;
}
assert
(
type
.
charAt
(
i
+
2
)
==
'H'
);
// only H works for now
next
=
i
+
3
;
assert
(
afterElemHead
||
nextAttrName
!=
null
);
//System.out.println("get attr "+nextAttrName+" in "+aval);
if
(
nextAttrName
!=
null
)
{
attrValue
=
aval
.
getAttr
(
nextAttrName
);
}
else
if
(
aval
.
hasText
())
{
attrValue
=
aval
.
getText
().
toString
();
}
else
{
attrValue
=
null
;
}
value
=
getCPIndex
(
tag
,
attrValue
);
intKind
=
'H'
;
//type.charAt(i+2);
break
;
case
'P'
:
// bci = 'P' int
case
'S'
:
// signed_int = 'S' int
next
=
i
+
2
;
value
=
(
int
)
aval
.
getAttrLong
(
nextAttrName
);
intKind
=
type
.
charAt
(
i
+
1
);
break
;
case
'F'
:
next
=
i
+
2
;
value
=
parseFlags
(
aval
.
getAttr
(
nextAttrName
));
intKind
=
type
.
charAt
(
i
+
1
);
break
;
default
:
throw
new
RuntimeException
(
"bad attr format '"
+
type
.
charAt
(
i
)
+
"': "
+
type
);
}
// write the value
putInt
(
value
,
intKind
);
nextAttrName
=
null
;
afterElemHead
=
false
;
}
assert
(
nextAttrName
==
null
);
}
private
void
putInt
(
int
x
,
char
ch
)
throws
IOException
{
switch
(
ch
)
{
case
'B'
:
u1
(
x
);
break
;
case
'H'
:
u2
(
x
);
break
;
case
'I'
:
u4
(
x
);
break
;
}
assert
(
"BHI"
.
indexOf
(
ch
)
>=
0
);
}
private
void
writeCode
(
Element
code
)
throws
IOException
{
//System.out.println("writeCode "+code);
//Element m = new Element(currentMember); m.remove(code);
//System.out.println(" in "+m);
int
stack
=
(
int
)
code
.
getAttrLong
(
"stack"
);
int
local
=
(
int
)
code
.
getAttrLong
(
"local"
);
Element
bytes
=
code
.
findElement
(
"Bytes"
);
Element
insns
=
code
.
findElement
(
"Instructions"
);
String
bytecodes
;
if
(
insns
==
null
)
{
bytecodes
=
bytes
.
getText
().
toString
();
}
else
{
bytecodes
=
InstructionSyntax
.
assemble
(
insns
,
this
);
// Cache the assembled bytecodes:
bytes
=
new
Element
(
"Bytes"
,
(
String
[])
null
,
bytecodes
);
code
.
add
(
0
,
bytes
);
}
u2
(
stack
);
u2
(
local
);
int
length
=
bytecodes
.
length
();
u4
(
length
);
for
(
int
i
=
0
;
i
<
length
;
i
++)
{
u1
((
byte
)
bytecodes
.
charAt
(
i
));
}
Element
handlers
=
code
.
findAllElements
(
"Handler"
);
u2
(
handlers
.
size
());
for
(
Element
handler
:
handlers
.
elements
())
{
int
start
=
(
int
)
handler
.
getAttrLong
(
"start"
);
int
end
=
(
int
)
handler
.
getAttrLong
(
"end"
);
int
catsh
=
(
int
)
handler
.
getAttrLong
(
"catch"
);
u2
(
start
);
u2
(
end
);
u2
(
catsh
);
cpRef
(
CONSTANT_Class
,
handler
.
getAttr
(
"class"
));
}
writeAttributesFor
(
code
);
}
protected
void
writeStackMap
(
Element
attrs
,
boolean
hasXOption
)
throws
IOException
{
Element
bytes
=
currentCode
.
findElement
(
"Bytes"
);
assert
(
bytes
!=
null
&&
bytes
.
size
()
==
1
);
int
byteLength
=
((
String
)
bytes
.
get
(
0
)).
length
();
boolean
uoffsetIsU4
=
(
byteLength
>=
(
1
<<
16
));
boolean
ulocalvarIsU4
=
currentCode
.
getAttrLong
(
"local"
)
>=
(
1
<<
16
);
boolean
ustackIsU4
=
currentCode
.
getAttrLong
(
"stack"
)
>=
(
1
<<
16
);
if
(
uoffsetIsU4
)
{
u4
(
attrs
.
size
());
}
else
{
u2
(
attrs
.
size
());
}
for
(
Element
frame
:
attrs
.
elements
())
{
int
bci
=
(
int
)
frame
.
getAttrLong
(
"bci"
);
if
(
uoffsetIsU4
)
{
u4
(
bci
);
}
else
{
u2
(
bci
);
}
if
(
hasXOption
)
{
u1
((
int
)
frame
.
getAttrLong
(
"flags"
));
}
// Scan local and stack types in this frame:
final
int
LOCALS
=
0
,
STACK
=
1
;
for
(
int
j
=
LOCALS
;
j
<=
STACK
;
j
++)
{
Element
types
=
frame
.
findElement
(
j
==
LOCALS
?
"Local"
:
"Stack"
);
int
typeSize
=
(
types
==
null
)
?
0
:
types
.
size
();
if
(
j
==
LOCALS
)
{
if
(
ulocalvarIsU4
)
{
u4
(
typeSize
);
}
else
{
u2
(
typeSize
);
}
}
else
{
// STACK
if
(
ustackIsU4
)
{
u4
(
typeSize
);
}
else
{
u2
(
typeSize
);
}
}
if
(
types
==
null
)
{
continue
;
}
for
(
Element
type
:
types
.
elements
())
{
int
tag
=
itemTagValue
(
type
.
getName
());
u1
(
tag
);
switch
(
tag
)
{
case
ITEM_Object:
cpRef
(
CONSTANT_Class
,
type
.
getAttr
(
"class"
));
break
;
case
ITEM_Uninitialized:
case
ITEM_ReturnAddress:
{
int
offset
=
(
int
)
type
.
getAttrLong
(
"bci"
);
if
(
uoffsetIsU4
)
{
u4
(
offset
);
}
else
{
u2
(
offset
);
}
}
break
;
}
}
}
}
}
public
void
writeCP
()
throws
IOException
{
int
cpLen
=
cpoolSize
;
u2
(
cpLen
);
ByteArrayOutputStream
buf
=
getAttrBuf
();
for
(
Element
c
:
cpool
.
elements
())
{
if
(!
c
.
isText
())
{
System
.
out
.
println
(
"## !isText "
+
c
);
}
int
id
=
(
int
)
c
.
getAttrLong
(
"id"
);
int
tag
=
cpTagValue
(
c
.
getName
());
String
name
=
c
.
getText
().
toString
();
int
pos
;
u1
(
tag
);
switch
(
tag
)
{
case
CONSTANT_Utf8:
{
int
done
=
0
;
buf
.
reset
();
int
nameLen
=
name
.
length
();
while
(
done
<
nameLen
)
{
int
next
=
name
.
indexOf
((
char
)
0
,
done
);
if
(
next
<
0
)
{
next
=
nameLen
;
}
if
(
done
<
next
)
{
buf
.
write
(
name
.
substring
(
done
,
next
).
getBytes
(
UTF8_ENCODING
));
}
if
(
next
<
nameLen
)
{
buf
.
write
(
0300
);
buf
.
write
(
0200
);
next
++;
}
done
=
next
;
}
u2
(
buf
.
size
());
buf
.
writeTo
(
out
);
}
break
;
case
CONSTANT_Integer:
u4
(
Integer
.
parseInt
(
name
));
break
;
case
CONSTANT_Float:
u4
(
Float
.
floatToIntBits
(
Float
.
parseFloat
(
name
)));
break
;
case
CONSTANT_Long:
u8
(
Long
.
parseLong
(
name
));
//i += 1; // no need: extra cp slot is implicit
break
;
case
CONSTANT_Double:
u8
(
Double
.
doubleToLongBits
(
Double
.
parseDouble
(
name
)));
//i += 1; // no need: extra cp slot is implicit
break
;
case
CONSTANT_Class:
case
CONSTANT_String:
u2
(
getCPIndex
(
CONSTANT_Utf8
,
name
));
break
;
case
CONSTANT_Fieldref:
case
CONSTANT_Methodref:
case
CONSTANT_InterfaceMethodref:
pos
=
name
.
indexOf
(
' '
);
u2
(
getCPIndex
(
CONSTANT_Class
,
name
.
substring
(
0
,
pos
)));
u2
(
getCPIndex
(
CONSTANT_NameAndType
,
name
.
substring
(
pos
+
1
)));
break
;
case
CONSTANT_NameAndType:
pos
=
name
.
indexOf
(
' '
);
u2
(
getCPIndex
(
CONSTANT_Utf8
,
name
.
substring
(
0
,
pos
)));
u2
(
getCPIndex
(
CONSTANT_Utf8
,
name
.
substring
(
pos
+
1
)));
break
;
}
}
putAttrBuf
(
buf
);
}
public
void
cpRef
(
int
tag
,
String
name
)
throws
IOException
{
u2
(
getCPIndex
(
tag
,
name
));
}
public
void
u8
(
long
x
)
throws
IOException
{
u4
((
int
)
(
x
>>>
32
));
u4
((
int
)
(
x
>>>
0
));
}
public
void
u4
(
int
x
)
throws
IOException
{
u2
(
x
>>>
16
);
u2
(
x
>>>
0
);
}
public
void
u2
(
int
x
)
throws
IOException
{
u1
(
x
>>>
8
);
u1
(
x
>>>
0
);
}
public
void
u1
(
int
x
)
throws
IOException
{
out
.
write
(
x
&
0xFF
);
}
}
test/tools/pack200/pack200-verifier/src/xmlkit/CommandLineParser.java
0 → 100644
浏览文件 @
130dc864
/*
* 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
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
;
}
}
test/tools/pack200/pack200-verifier/src/xmlkit/InstructionAssembler.java
0 → 100644
浏览文件 @
130dc864
/*
* 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
xmlkit
;
// -*- mode: java; indent-tabs-mode: nil -*-
import
xmlkit.XMLKit.Element
;
import
java.util.HashMap
;
/*
* @author jrose
*/
abstract
class
InstructionAssembler
extends
InstructionSyntax
{
InstructionAssembler
()
{
}
public
static
String
assemble
(
Element
instructions
,
String
pcAttrName
,
ClassSyntax
.
GetCPIndex
getCPI
)
{
int
insCount
=
instructions
.
size
();
Element
[]
insElems
=
new
Element
[
insCount
];
int
[]
elemToIndexMap
;
int
[]
insLocs
;
byte
[]
ops
=
new
byte
[
insCount
];
int
[]
operands
=
new
int
[
insCount
];
boolean
[]
isWide
=
new
boolean
[
insCount
];
int
[]
branches
;
int
[]
branchInsLocs
;
HashMap
<
String
,
String
>
labels
=
new
HashMap
<
String
,
String
>();
final
int
WIDE
=
0xc4
;
final
int
GOTO
=
0xa7
;
final
int
GOTO_W
=
0xc8
;
final
int
GOTO_LEN
=
3
;
final
int
GOTO_W_LEN
=
5
;
assert
(
"wide"
.
equals
(
bcNames
[
WIDE
]));
assert
(
"goto"
.
equals
(
bcNames
[
GOTO
]));
assert
(
"goto_w"
.
equals
(
bcNames
[
GOTO_W
]));
assert
(
bcFormats
[
GOTO
].
length
()
==
GOTO_LEN
);
assert
(
bcFormats
[
GOTO_W
].
length
()
==
GOTO_W_LEN
);
// Unpack instructions into temp. arrays, and find branches and labels.
{
elemToIndexMap
=
(
pcAttrName
!=
null
)
?
new
int
[
insCount
]
:
null
;
int
[]
buffer
=
operands
;
int
id
=
0
;
int
branchCount
=
0
;
for
(
int
i
=
0
;
i
<
insCount
;
i
++)
{
Element
ins
=
(
Element
)
instructions
.
get
(
i
);
if
(
elemToIndexMap
!=
null
)
{
elemToIndexMap
[
i
]
=
(
ins
.
getAttr
(
pcAttrName
)
!=
null
?
id
:
-
1
);
}
String
lab
=
ins
.
getAttr
(
"pc"
);
if
(
lab
!=
null
)
{
labels
.
put
(
lab
,
String
.
valueOf
(
id
));
}
int
op
=
opCode
(
ins
.
getName
());
if
(
op
<
0
)
{
assert
(
ins
.
getAttr
(
pcAttrName
)
!=
null
||
ins
.
getName
().
equals
(
"label"
));
continue
;
// delete PC holder element
}
if
(
op
==
WIDE
)
{
//0xc4
isWide
[
id
]
=
true
;
// force wide format
continue
;
}
if
(
bcFormats
[
op
].
indexOf
(
'o'
)
>=
0
)
{
buffer
[
branchCount
++]
=
id
;
}
if
(
bcFormats
[
op
]
==
bcWideFormats
[
op
])
{
isWide
[
id
]
=
false
;
}
insElems
[
id
]
=
ins
;
ops
[
id
]
=
(
byte
)
op
;
id
++;
}
insCount
=
id
;
// maybe we deleted some wide prefixes, etc.
branches
=
new
int
[
branchCount
+
1
];
System
.
arraycopy
(
buffer
,
0
,
branches
,
0
,
branchCount
);
branches
[
branchCount
]
=
-
1
;
// sentinel
}
// Compute instruction sizes. These sizes are final,
// except for branch instructions, which may need lengthening.
// Some instructions (ldc, bipush, iload, iinc) are automagically widened.
insLocs
=
new
int
[
insCount
+
1
];
int
loc
=
0
;
for
(
int
bn
=
0
,
id
=
0
;
id
<
insCount
;
id
++)
{
insLocs
[
id
]
=
loc
;
Element
ins
=
insElems
[
id
];
int
op
=
ops
[
id
]
&
0xFF
;
String
format
=
opFormat
(
op
,
isWide
[
id
]);
// Make sure operands fit within the given format.
for
(
int
j
=
1
,
jlimit
=
format
.
length
();
j
<
jlimit
;
j
++)
{
char
fc
=
format
.
charAt
(
j
);
int
x
=
0
;
switch
(
fc
)
{
case
'l'
:
x
=
(
int
)
ins
.
getAttrLong
(
"loc"
);
assert
(
x
>=
0
);
if
(
x
>
0xFF
&&
!
isWide
[
id
])
{
isWide
[
id
]
=
true
;
format
=
opFormat
(
op
,
isWide
[
id
]);
}
assert
(
x
<=
0xFFFF
);
break
;
case
'k'
:
char
fc2
=
format
.
charAt
(
Math
.
min
(
j
+
1
,
format
.
length
()
-
1
));
x
=
getCPIndex
(
ins
,
fc2
,
getCPI
);
if
(
x
>
0xFF
&&
j
==
jlimit
-
1
)
{
assert
(
op
==
0x12
);
//ldc
ops
[
id
]
=
(
byte
)
(
op
=
0x13
);
//ldc_w
format
=
opFormat
(
op
);
}
assert
(
x
<=
0xFFFF
);
j
++;
// skip type-of-constant marker
break
;
case
'x'
:
x
=
(
int
)
ins
.
getAttrLong
(
"num"
);
assert
(
x
>=
0
&&
x
<=
((
j
==
jlimit
-
1
)
?
0xFF
:
0xFFFF
));
break
;
case
's'
:
x
=
(
int
)
ins
.
getAttrLong
(
"num"
);
if
(
x
!=
(
byte
)
x
&&
j
==
jlimit
-
1
)
{
switch
(
op
)
{
case
0x10
:
//bipush
ops
[
id
]
=
(
byte
)
(
op
=
0x11
);
//sipush
break
;
case
0x84
:
//iinc
isWide
[
id
]
=
true
;
format
=
opFormat
(
op
,
isWide
[
id
]);
break
;
default
:
assert
(
false
);
// cannot lengthen
}
}
// unsign the value now, to make later steps clearer
if
(
j
==
jlimit
-
1
)
{
assert
(
x
==
(
byte
)
x
);
x
=
x
&
0xFF
;
}
else
{
assert
(
x
==
(
short
)
x
);
x
=
x
&
0xFFFF
;
}
break
;
case
'o'
:
assert
(
branches
[
bn
]
==
id
);
bn
++;
// make local copies of the branches, and fix up labels
insElems
[
id
]
=
ins
=
new
Element
(
ins
);
String
newLab
=
labels
.
get
(
ins
.
getAttr
(
"lab"
));
assert
(
newLab
!=
null
);
ins
.
setAttr
(
"lab"
,
newLab
);
int
prevCas
=
0
;
int
k
=
0
;
for
(
Element
cas
:
ins
.
elements
())
{
assert
(
cas
.
getName
().
equals
(
"Case"
));
ins
.
set
(
k
++,
cas
=
new
Element
(
cas
));
newLab
=
labels
.
get
(
cas
.
getAttr
(
"lab"
));
assert
(
newLab
!=
null
);
cas
.
setAttr
(
"lab"
,
newLab
);
int
thisCas
=
(
int
)
cas
.
getAttrLong
(
"num"
);
assert
(
op
==
0xab
||
op
==
0xaa
&&
(
k
==
0
||
thisCas
==
prevCas
+
1
));
prevCas
=
thisCas
;
}
break
;
case
't'
:
// switch table is represented as Switch.Case sub-elements
break
;
default
:
assert
(
false
);
}
operands
[
id
]
=
x
;
// record operand (last if there are 2)
// skip redundant chars
while
(
j
+
1
<
jlimit
&&
format
.
charAt
(
j
+
1
)
==
fc
)
{
++
j
;
}
}
switch
(
op
)
{
case
0xaa
:
//tableswitch
loc
=
switchBase
(
loc
);
loc
+=
4
*
(
3
+
ins
.
size
());
break
;
case
0xab
:
//lookupswitch
loc
=
switchBase
(
loc
);
loc
+=
4
*
(
2
+
2
*
ins
.
size
());
break
;
default
:
if
(
isWide
[
id
])
{
loc
++;
// 'wide' opcode prefix
}
loc
+=
format
.
length
();
break
;
}
}
insLocs
[
insCount
]
=
loc
;
// compute branch offsets, and see if any branches need expansion
for
(
int
maxTries
=
9
,
tries
=
0
;;
++
tries
)
{
boolean
overflowing
=
false
;
boolean
[]
branchExpansions
=
null
;
for
(
int
bn
=
0
;
bn
<
branches
.
length
-
1
;
bn
++)
{
int
id
=
branches
[
bn
];
Element
ins
=
insElems
[
id
];
int
insSize
=
insLocs
[
id
+
1
]
-
insLocs
[
id
];
int
origin
=
insLocs
[
id
];
int
target
=
insLocs
[(
int
)
ins
.
getAttrLong
(
"lab"
)];
int
offset
=
target
-
origin
;
operands
[
id
]
=
offset
;
//System.out.println("branch id="+id+" len="+insSize+" to="+target+" offset="+offset);
assert
(
insSize
==
GOTO_LEN
||
insSize
==
GOTO_W_LEN
||
ins
.
getName
().
indexOf
(
"switch"
)
>
0
);
boolean
thisOverflow
=
(
insSize
==
GOTO_LEN
&&
(
offset
!=
(
short
)
offset
));
if
(
thisOverflow
&&
!
overflowing
)
{
overflowing
=
true
;
branchExpansions
=
new
boolean
[
branches
.
length
];
}
if
(
thisOverflow
||
tries
==
maxTries
-
1
)
{
// lengthen the branch
assert
(!(
thisOverflow
&&
isWide
[
id
]));
isWide
[
id
]
=
true
;
branchExpansions
[
bn
]
=
true
;
}
}
if
(!
overflowing
)
{
break
;
// done, usually on first try
}
assert
(
tries
<=
maxTries
);
// Walk over all instructions, expanding branches and updating locations.
int
fixup
=
0
;
for
(
int
bn
=
0
,
id
=
0
;
id
<
insCount
;
id
++)
{
insLocs
[
id
]
+=
fixup
;
if
(
branches
[
bn
]
==
id
)
{
int
op
=
ops
[
id
]
&
0xFF
;
int
wop
;
boolean
invert
;
if
(
branchExpansions
[
bn
])
{
switch
(
op
)
{
case
GOTO:
//0xa7
wop
=
GOTO_W
;
//0xc8
invert
=
false
;
break
;
case
0xa8
:
//jsr
wop
=
0xc9
;
//jsr_w
invert
=
false
;
break
;
default
:
wop
=
invertBranchOp
(
op
);
invert
=
true
;
break
;
}
assert
(
op
!=
wop
);
ops
[
id
]
=
(
byte
)
wop
;
isWide
[
id
]
=
invert
;
if
(
invert
)
{
fixup
+=
GOTO_W_LEN
;
//branch around a wide goto
}
else
{
fixup
+=
(
GOTO_W_LEN
-
GOTO_LEN
);
}
// done expanding: ops and isWide reflect the decision
}
bn
++;
}
}
insLocs
[
insCount
]
+=
fixup
;
}
// we know the layout now
// notify the caller of offsets, if requested
if
(
elemToIndexMap
!=
null
)
{
for
(
int
i
=
0
;
i
<
elemToIndexMap
.
length
;
i
++)
{
int
id
=
elemToIndexMap
[
i
];
if
(
id
>=
0
)
{
Element
ins
=
(
Element
)
instructions
.
get
(
i
);
ins
.
setAttr
(
pcAttrName
,
""
+
insLocs
[
id
]);
}
}
elemToIndexMap
=
null
;
// release the pointer
}
// output the bytes
StringBuffer
sbuf
=
new
StringBuffer
(
insLocs
[
insCount
]);
for
(
int
bn
=
0
,
id
=
0
;
id
<
insCount
;
id
++)
{
//System.out.println("output id="+id+" loc="+insLocs[id]+" len="+(insLocs[id+1]-insLocs[id])+" #sbuf="+sbuf.length());
assert
(
sbuf
.
length
()
==
insLocs
[
id
]);
Element
ins
;
int
pc
=
insLocs
[
id
];
int
nextpc
=
insLocs
[
id
+
1
];
int
op
=
ops
[
id
]
&
0xFF
;
int
opnd
=
operands
[
id
];
String
format
;
if
(
branches
[
bn
]
==
id
)
{
bn
++;
sbuf
.
append
((
char
)
op
);
if
(
isWide
[
id
])
{
// emit <ifop lab=1f> <goto_w target> <label pc=1f>
int
target
=
pc
+
opnd
;
putInt
(
sbuf
,
nextpc
-
pc
,
-
2
);
assert
(
sbuf
.
length
()
==
pc
+
GOTO_LEN
);
sbuf
.
append
((
char
)
GOTO_W
);
putInt
(
sbuf
,
target
-
(
pc
+
GOTO_LEN
),
4
);
}
else
if
(
op
==
0xaa
||
//tableswitch
op
==
0xab
)
{
//lookupswitch
ins
=
insElems
[
id
];
for
(
int
pad
=
switchBase
(
pc
)
-
(
pc
+
1
);
pad
>
0
;
pad
--)
{
sbuf
.
append
((
char
)
0
);
}
assert
(
pc
+
opnd
==
insLocs
[(
int
)
ins
.
getAttrLong
(
"lab"
)]);
putInt
(
sbuf
,
opnd
,
4
);
// default label
if
(
op
==
0xaa
)
{
//tableswitch
Element
cas0
=
(
Element
)
ins
.
get
(
0
);
int
lowCase
=
(
int
)
cas0
.
getAttrLong
(
"num"
);
Element
casN
=
(
Element
)
ins
.
get
(
ins
.
size
()
-
1
);
int
highCase
=
(
int
)
casN
.
getAttrLong
(
"num"
);
assert
(
highCase
-
lowCase
+
1
==
ins
.
size
());
putInt
(
sbuf
,
lowCase
,
4
);
putInt
(
sbuf
,
highCase
,
4
);
int
caseForAssert
=
lowCase
;
for
(
Element
cas
:
ins
.
elements
())
{
int
target
=
insLocs
[(
int
)
cas
.
getAttrLong
(
"lab"
)];
assert
(
cas
.
getAttrLong
(
"num"
)
==
caseForAssert
++);
putInt
(
sbuf
,
target
-
pc
,
4
);
}
}
else
{
//lookupswitch
int
caseCount
=
ins
.
size
();
putInt
(
sbuf
,
caseCount
,
4
);
for
(
Element
cas
:
ins
.
elements
())
{
int
target
=
insLocs
[(
int
)
cas
.
getAttrLong
(
"lab"
)];
putInt
(
sbuf
,
(
int
)
cas
.
getAttrLong
(
"num"
),
4
);
putInt
(
sbuf
,
target
-
pc
,
4
);
}
}
assert
(
nextpc
==
sbuf
.
length
());
}
else
{
putInt
(
sbuf
,
opnd
,
-(
nextpc
-
(
pc
+
1
)));
}
}
else
if
(
nextpc
==
pc
+
1
)
{
// a single-byte instruction
sbuf
.
append
((
char
)
op
);
}
else
{
// picky stuff
boolean
wide
=
isWide
[
id
];
if
(
wide
)
{
sbuf
.
append
((
char
)
WIDE
);
pc
++;
}
sbuf
.
append
((
char
)
op
);
int
opnd1
;
int
opnd2
=
opnd
;
switch
(
op
)
{
case
0x84
:
//iinc
ins
=
insElems
[
id
];
opnd1
=
(
int
)
ins
.
getAttrLong
(
"loc"
);
if
(
isWide
[
id
])
{
putInt
(
sbuf
,
opnd1
,
2
);
putInt
(
sbuf
,
opnd2
,
2
);
}
else
{
putInt
(
sbuf
,
opnd1
,
1
);
putInt
(
sbuf
,
opnd2
,
1
);
}
break
;
case
0xc5
:
//multianewarray
ins
=
insElems
[
id
];
opnd1
=
getCPIndex
(
ins
,
'c'
,
getCPI
);
putInt
(
sbuf
,
opnd1
,
2
);
putInt
(
sbuf
,
opnd2
,
1
);
break
;
case
0xb9
:
//invokeinterface
ins
=
insElems
[
id
];
opnd1
=
getCPIndex
(
ins
,
'n'
,
getCPI
);
putInt
(
sbuf
,
opnd1
,
2
);
opnd2
=
(
int
)
ins
.
getAttrLong
(
"num"
);
if
(
opnd2
==
0
)
{
opnd2
=
ClassSyntax
.
computeInterfaceNum
(
ins
.
getAttr
(
"val"
));
}
putInt
(
sbuf
,
opnd2
,
2
);
break
;
default
:
// put the single operand and be done
putInt
(
sbuf
,
opnd
,
nextpc
-
(
pc
+
1
));
break
;
}
}
}
assert
(
sbuf
.
length
()
==
insLocs
[
insCount
]);
return
sbuf
.
toString
();
}
static
int
getCPIndex
(
Element
ins
,
char
ctype
,
ClassSyntax
.
GetCPIndex
getCPI
)
{
int
x
=
(
int
)
ins
.
getAttrLong
(
"ref"
);
if
(
x
==
0
&&
getCPI
!=
null
)
{
String
val
=
ins
.
getAttr
(
"val"
);
if
(
val
==
null
||
val
.
equals
(
""
))
{
val
=
ins
.
getText
().
toString
();
}
byte
tag
;
switch
(
ctype
)
{
case
'k'
:
tag
=
(
byte
)
ins
.
getAttrLong
(
"tag"
);
break
;
case
'c'
:
tag
=
ClassSyntax
.
CONSTANT_Class
;
break
;
case
'f'
:
tag
=
ClassSyntax
.
CONSTANT_Fieldref
;
break
;
case
'm'
:
tag
=
ClassSyntax
.
CONSTANT_Methodref
;
break
;
case
'n'
:
tag
=
ClassSyntax
.
CONSTANT_InterfaceMethodref
;
break
;
default
:
throw
new
Error
(
"bad ctype "
+
ctype
+
" in "
+
ins
);
}
x
=
getCPI
.
getCPIndex
(
tag
,
val
);
//System.out.println("getCPIndex "+ins+" => "+tag+"/"+val+" => "+x);
}
else
{
assert
(
x
>
0
);
}
return
x
;
}
static
void
putInt
(
StringBuffer
sbuf
,
int
x
,
int
len
)
{
//System.out.println("putInt x="+x+" len="+len);
boolean
isSigned
=
false
;
if
(
len
<
0
)
{
len
=
-
len
;
isSigned
=
true
;
}
assert
(
len
==
1
||
len
==
2
||
len
==
4
);
int
insig
=
((
4
-
len
)
*
8
);
// how many insignificant bits?
int
sx
=
x
<<
insig
;
;
assert
(
x
==
(
isSigned
?
(
sx
>>
insig
)
:
(
sx
>>>
insig
)));
for
(
int
i
=
0
;
i
<
len
;
i
++)
{
sbuf
.
append
((
char
)
(
sx
>>>
24
));
sx
<<=
8
;
}
}
}
test/tools/pack200/pack200-verifier/src/xmlkit/InstructionSyntax.java
0 → 100644
浏览文件 @
130dc864
/*
* 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
xmlkit
;
// -*- mode: java; indent-tabs-mode: nil -*-
import
xmlkit.XMLKit.Element
;
import
java.util.HashMap
;
import
java.util.Map
;
/*
* @author jrose
*/
public
abstract
class
InstructionSyntax
{
InstructionSyntax
()
{
}
static
final
String
[]
bcNames
;
static
final
String
[]
bcFormats
;
static
final
String
[]
bcWideFormats
;
static
final
HashMap
<
String
,
Integer
>
bcCodes
;
static
final
HashMap
<
String
,
Element
>
abbrevs
;
static
final
HashMap
<
Element
,
String
>
rabbrevs
;
static
{
TokenList
tl
=
new
TokenList
(
" 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/s sipush/ss ldc/k ldc_w/kk ldc2_w/kk"
+
" iload/wl lload/wl fload/wl dload/wl aload/wl 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/wl lstore/wl fstore/wl dstore/wl astore/wl"
+
" 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/wls i2l i2f i2d l2i l2f"
+
" l2d f2i f2l f2d d2i d2l d2f i2b i2c i2s lcmp fcmpl fcmpg dcmpl"
+
" dcmpg ifeq/oo ifne/oo iflt/oo ifge/oo ifgt/oo ifle/oo"
+
" if_icmpeq/oo if_icmpne/oo if_icmplt/oo if_icmpge/oo if_icmpgt/oo"
+
" if_icmple/oo if_acmpeq/oo if_acmpne/oo goto/oo jsr/oo ret/wl"
+
" tableswitch/oooot lookupswitch/oooot ireturn lreturn freturn dreturn areturn"
+
" return getstatic/kf putstatic/kf getfield/kf putfield/kf"
+
" invokevirtual/km invokespecial/km invokestatic/km"
+
" invokeinterface/knxx xxxunusedxxx new/kc newarray/x anewarray/kc"
+
" arraylength athrow checkcast/kc instanceof/kc monitorenter"
+
" monitorexit wide multianewarray/kcx ifnull/oo ifnonnull/oo"
+
" goto_w/oooo jsr_w/oooo"
);
assert
(
tl
.
size
()
==
202
);
// this many instructions!
HashMap
<
String
,
Integer
>
map
=
new
HashMap
<
String
,
Integer
>(
tl
.
size
());
String
[]
names
=
tl
.
toArray
(
new
String
[
tl
.
size
()]);
String
[]
formats
=
new
String
[
names
.
length
];
String
[]
wideFormats
=
new
String
[
names
.
length
];
StringBuilder
sbuf
=
new
StringBuilder
();
sbuf
.
append
(
'i'
);
// all op formats begin with "i"
int
i
=
0
;
for
(
String
ins
:
names
)
{
assert
(
ins
==
ins
.
trim
());
// no whitespace
int
sfx
=
ins
.
indexOf
(
'/'
);
String
format
=
"i"
;
String
wideFormat
=
null
;
if
(
sfx
>=
0
)
{
format
=
ins
.
substring
(
sfx
+
1
);
ins
=
ins
.
substring
(
0
,
sfx
);
if
(
format
.
charAt
(
0
)
==
'w'
)
{
format
=
format
.
substring
(
1
);
sbuf
.
setLength
(
1
);
for
(
int
j
=
0
;
j
<
format
.
length
();
j
++)
{
// double everything except the initial 'i'
sbuf
.
append
(
format
.
charAt
(
j
));
sbuf
.
append
(
format
.
charAt
(
j
));
}
wideFormat
=
sbuf
.
toString
().
intern
();
}
sbuf
.
setLength
(
1
);
sbuf
.
append
(
format
);
format
=
sbuf
.
toString
().
intern
();
}
ins
=
ins
.
intern
();
names
[
i
]
=
ins
;
formats
[
i
]
=
format
;
wideFormats
[
i
]
=
(
wideFormat
!=
null
)
?
wideFormat
:
format
;
//System.out.println(ins+" "+format+" "+wideFormat);
map
.
put
(
ins
,
i
++);
}
//map = Collections.unmodifiableMap(map);
HashMap
<
String
,
Element
>
abb
=
new
HashMap
<
String
,
Element
>(
tl
.
size
()
/
2
);
abb
.
put
(
"iconst_m1"
,
new
Element
(
"bipush"
,
"num"
,
"-1"
));
for
(
String
ins
:
names
)
{
int
sfx
=
ins
.
indexOf
(
'_'
);
if
(
sfx
>=
0
&&
Character
.
isDigit
(
ins
.
charAt
(
sfx
+
1
)))
{
String
pfx
=
ins
.
substring
(
0
,
sfx
).
intern
();
String
num
=
ins
.
substring
(
sfx
+
1
);
String
att
=
pfx
.
endsWith
(
"const"
)
?
"num"
:
"loc"
;
Element
exp
=
new
Element
(
pfx
,
att
,
num
).
deepFreeze
();
abb
.
put
(
ins
,
exp
);
}
}
//abb = Collections.unmodifiableMap(abb);
HashMap
<
Element
,
String
>
rabb
=
new
HashMap
<
Element
,
String
>(
tl
.
size
()
/
2
);
for
(
Map
.
Entry
<
String
,
Element
>
e
:
abb
.
entrySet
())
{
rabb
.
put
(
e
.
getValue
(),
e
.
getKey
());
}
//rabb = Collections.unmodifiableMap(rabb);
bcNames
=
names
;
bcFormats
=
formats
;
bcWideFormats
=
wideFormats
;
bcCodes
=
map
;
abbrevs
=
abb
;
rabbrevs
=
rabb
;
}
public
static
String
opName
(
int
op
)
{
if
(
op
>=
0
&&
op
<
bcNames
.
length
)
{
return
bcNames
[
op
];
}
return
"unknown#"
+
op
;
}
public
static
String
opFormat
(
int
op
)
{
return
opFormat
(
op
,
false
);
}
public
static
String
opFormat
(
int
op
,
boolean
isWide
)
{
if
(
op
>=
0
&&
op
<
bcFormats
.
length
)
{
return
(
isWide
?
bcWideFormats
[
op
]
:
bcFormats
[
op
]);
}
return
"?"
;
}
public
static
int
opCode
(
String
opName
)
{
Integer
op
=
(
Integer
)
bcCodes
.
get
(
opName
);
if
(
op
!=
null
)
{
return
op
.
intValue
();
}
return
-
1
;
}
public
static
Element
expandAbbrev
(
String
opName
)
{
return
abbrevs
.
get
(
opName
);
}
public
static
String
findAbbrev
(
Element
op
)
{
return
rabbrevs
.
get
(
op
);
}
public
static
int
invertBranchOp
(
int
op
)
{
assert
(
opFormat
(
op
).
indexOf
(
'o'
)
>=
0
);
final
int
IFMIN
=
0x99
;
final
int
IFMAX
=
0xa6
;
final
int
IFMIN2
=
0xc6
;
final
int
IFMAX2
=
0xc7
;
assert
(
bcNames
[
IFMIN
]
==
"ifeq"
);
assert
(
bcNames
[
IFMAX
]
==
"if_acmpne"
);
assert
(
bcNames
[
IFMIN2
]
==
"ifnonnull"
);
assert
(
bcNames
[
IFMAX2
]
==
"ifnull"
);
int
rop
;
if
(
op
>=
IFMIN
&&
op
<=
IFMAX
)
{
rop
=
IFMIN
+
((
op
-
IFMIN
)
^
1
);
}
else
if
(
op
>=
IFMIN2
&&
op
<=
IFMAX2
)
{
rop
=
IFMIN2
+
((
op
-
IFMIN2
)
^
1
);
}
else
{
assert
(
false
);
rop
=
op
;
}
assert
(
opFormat
(
rop
).
indexOf
(
'o'
)
>=
0
);
return
rop
;
}
public
static
Element
parse
(
String
bytes
)
{
Element
e
=
new
Element
(
"Instructions"
,
bytes
.
length
());
boolean
willBeWide
;
boolean
isWide
=
false
;
Element
[]
tempMap
=
new
Element
[
bytes
.
length
()];
for
(
int
pc
=
0
,
nextpc
;
pc
<
bytes
.
length
();
pc
=
nextpc
)
{
int
op
=
bytes
.
charAt
(
pc
);
Element
i
=
new
Element
(
opName
(
op
));
nextpc
=
pc
+
1
;
int
locarg
=
0
;
int
cparg
=
0
;
int
intarg
=
0
;
int
labelarg
=
0
;
willBeWide
=
false
;
switch
(
op
)
{
case
0xc4
:
//wide
willBeWide
=
true
;
break
;
case
0x10
:
//bipush
intarg
=
nextpc
++;
intarg
*=
-
1
;
//mark signed
break
;
case
0x11
:
//sipush
intarg
=
nextpc
;
nextpc
+=
2
;
intarg
*=
-
1
;
//mark signed
break
;
case
0x12
:
//ldc
cparg
=
nextpc
++;
break
;
case
0x13
:
//ldc_w
case
0x14
:
//ldc2_w
case
0xb2
:
//getstatic
case
0xb3
:
//putstatic
case
0xb4
:
//getfield
case
0xb5
:
//putfield
case
0xb6
:
//invokevirtual
case
0xb7
:
//invokespecial
case
0xb8
:
//invokestatic
case
0xbb
:
//new
case
0xbd
:
//anewarray
case
0xc0
:
//checkcast
case
0xc1
:
//instanceof
cparg
=
nextpc
;
nextpc
+=
2
;
break
;
case
0xb9
:
//invokeinterface
cparg
=
nextpc
;
nextpc
+=
2
;
intarg
=
nextpc
;
nextpc
+=
2
;
break
;
case
0xc5
:
//multianewarray
cparg
=
nextpc
;
nextpc
+=
2
;
intarg
=
nextpc
++;
break
;
case
0x15
:
//iload
case
0x16
:
//lload
case
0x17
:
//fload
case
0x18
:
//dload
case
0x19
:
//aload
case
0x36
:
//istore
case
0x37
:
//lstore
case
0x38
:
//fstore
case
0x39
:
//dstore
case
0x3a
:
//astore
case
0xa9
:
//ret
locarg
=
nextpc
++;
if
(
isWide
)
{
nextpc
++;
}
break
;
case
0x84
:
//iinc
locarg
=
nextpc
++;
if
(
isWide
)
{
nextpc
++;
}
intarg
=
nextpc
++;
if
(
isWide
)
{
nextpc
++;
}
intarg
*=
-
1
;
//mark signed
break
;
case
0x99
:
//ifeq
case
0x9a
:
//ifne
case
0x9b
:
//iflt
case
0x9c
:
//ifge
case
0x9d
:
//ifgt
case
0x9e
:
//ifle
case
0x9f
:
//if_icmpeq
case
0xa0
:
//if_icmpne
case
0xa1
:
//if_icmplt
case
0xa2
:
//if_icmpge
case
0xa3
:
//if_icmpgt
case
0xa4
:
//if_icmple
case
0xa5
:
//if_acmpeq
case
0xa6
:
//if_acmpne
case
0xa7
:
//goto
case
0xa8
:
//jsr
labelarg
=
nextpc
;
nextpc
+=
2
;
break
;
case
0xbc
:
//newarray
intarg
=
nextpc
++;
break
;
case
0xc6
:
//ifnull
case
0xc7
:
//ifnonnull
labelarg
=
nextpc
;
nextpc
+=
2
;
break
;
case
0xc8
:
//goto_w
case
0xc9
:
//jsr_w
labelarg
=
nextpc
;
nextpc
+=
4
;
break
;
// save the best for last:
case
0xaa
:
//tableswitch
nextpc
=
parseSwitch
(
bytes
,
pc
,
true
,
i
);
break
;
case
0xab
:
//lookupswitch
nextpc
=
parseSwitch
(
bytes
,
pc
,
false
,
i
);
break
;
}
String
format
=
null
;
assert
((
format
=
opFormat
(
op
,
isWide
))
!=
null
);
//System.out.println("pc="+pc+" len="+(nextpc - pc)+" w="+isWide+" op="+op+" name="+opName(op)+" format="+format);
assert
((
nextpc
-
pc
)
==
format
.
length
()
||
format
.
indexOf
(
't'
)
>=
0
);
// Parse out instruction fields.
if
(
locarg
!=
0
)
{
int
len
=
nextpc
-
locarg
;
if
(
intarg
!=
0
)
{
len
/=
2
;
// split
}
i
.
setAttr
(
"loc"
,
""
+
getInt
(
bytes
,
locarg
,
len
));
assert
(
'l'
==
format
.
charAt
(
locarg
-
pc
+
0
));
assert
(
'l'
==
format
.
charAt
(
locarg
-
pc
+
len
-
1
));
}
if
(
cparg
!=
0
)
{
int
len
=
nextpc
-
cparg
;
if
(
len
>
2
)
{
len
=
2
;
}
i
.
setAttr
(
"ref"
,
""
+
getInt
(
bytes
,
cparg
,
len
));
assert
(
'k'
==
format
.
charAt
(
cparg
-
pc
+
0
));
}
if
(
intarg
!=
0
)
{
boolean
isSigned
=
(
intarg
<
0
);
if
(
isSigned
)
{
intarg
*=
-
1
;
}
int
len
=
nextpc
-
intarg
;
i
.
setAttr
(
"num"
,
""
+
getInt
(
bytes
,
intarg
,
isSigned
?
-
len
:
len
));
assert
((
isSigned
?
's'
:
'x'
)
==
format
.
charAt
(
intarg
-
pc
+
0
));
assert
((
isSigned
?
's'
:
'x'
)
==
format
.
charAt
(
intarg
-
pc
+
len
-
1
));
}
if
(
labelarg
!=
0
)
{
int
len
=
nextpc
-
labelarg
;
int
offset
=
getInt
(
bytes
,
labelarg
,
-
len
);
int
target
=
pc
+
offset
;
i
.
setAttr
(
"lab"
,
""
+
target
);
assert
(
'o'
==
format
.
charAt
(
labelarg
-
pc
+
0
));
assert
(
'o'
==
format
.
charAt
(
labelarg
-
pc
+
len
-
1
));
}
e
.
add
(
i
);
tempMap
[
pc
]
=
i
;
isWide
=
willBeWide
;
}
// Mark targets of branches.
for
(
Element
i
:
e
.
elements
())
{
for
(
int
j
=
-
1
;
j
<
i
.
size
();
j
++)
{
Element
c
=
(
j
<
0
)
?
i
:
(
Element
)
i
.
get
(
j
);
Number
targetNum
=
c
.
getAttrNumber
(
"lab"
);
if
(
targetNum
!=
null
)
{
int
target
=
targetNum
.
intValue
();
Element
ti
=
null
;
if
(
target
>=
0
&&
target
<
tempMap
.
length
)
{
ti
=
tempMap
[
target
];
}
if
(
ti
!=
null
)
{
ti
.
setAttr
(
"pc"
,
""
+
target
);
}
else
{
c
.
setAttr
(
"lab.error"
,
""
);
}
}
}
}
// Shrink to fit:
for
(
Element
i
:
e
.
elements
())
{
i
.
trimToSize
();
}
e
.
trimToSize
();
/*
String assem = assemble(e);
if (!assem.equals(bytes)) {
System.out.println("Bytes: "+bytes);
System.out.println("Insns: "+e);
System.out.println("Assem: "+parse(assem));
}
*/
return
e
;
}
static
int
switchBase
(
int
pc
)
{
int
apc
=
pc
+
1
;
apc
+=
(-
apc
)
&
3
;
return
apc
;
}
static
int
parseSwitch
(
String
s
,
int
pc
,
boolean
isTable
,
Element
i
)
{
int
apc
=
switchBase
(
pc
);
int
defLabel
=
pc
+
getInt
(
s
,
apc
+
4
*
0
,
4
);
i
.
setAttr
(
"lab"
,
""
+
defLabel
);
if
(
isTable
)
{
int
lowCase
=
getInt
(
s
,
apc
+
4
*
1
,
4
);
int
highCase
=
getInt
(
s
,
apc
+
4
*
2
,
4
);
int
caseCount
=
highCase
-
lowCase
+
1
;
for
(
int
n
=
0
;
n
<
caseCount
;
n
++)
{
Element
c
=
new
Element
(
"Case"
,
4
);
int
caseVal
=
lowCase
+
n
;
int
caseLab
=
getInt
(
s
,
apc
+
4
*
(
3
+
n
),
4
)
+
pc
;
c
.
setAttr
(
"num"
,
""
+
caseVal
);
c
.
setAttr
(
"lab"
,
""
+
caseLab
);
assert
(
c
.
getExtraCapacity
()
==
0
);
i
.
add
(
c
);
}
return
apc
+
4
*
(
3
+
caseCount
);
}
else
{
int
caseCount
=
getInt
(
s
,
apc
+
4
*
1
,
4
);
for
(
int
n
=
0
;
n
<
caseCount
;
n
++)
{
Element
c
=
new
Element
(
"Case"
,
4
);
int
caseVal
=
getInt
(
s
,
apc
+
4
*
(
2
+
(
2
*
n
)
+
0
),
4
);
int
caseLab
=
getInt
(
s
,
apc
+
4
*
(
2
+
(
2
*
n
)
+
1
),
4
)
+
pc
;
c
.
setAttr
(
"num"
,
""
+
caseVal
);
c
.
setAttr
(
"lab"
,
""
+
caseLab
);
assert
(
c
.
getExtraCapacity
()
==
0
);
i
.
add
(
c
);
}
return
apc
+
4
*
(
2
+
2
*
caseCount
);
}
}
static
int
getInt
(
String
s
,
int
pc
,
int
len
)
{
//System.out.println("getInt s["+s.length()+"] pc="+pc+" len="+len);
int
result
=
s
.
charAt
(
pc
);
if
(
len
<
0
)
{
len
=
-
len
;
result
=
(
byte
)
result
;
}
if
(!(
len
==
1
||
len
==
2
||
len
==
4
))
{
System
.
out
.
println
(
"len="
+
len
);
}
assert
(
len
==
1
||
len
==
2
||
len
==
4
);
for
(
int
i
=
1
;
i
<
len
;
i
++)
{
result
<<=
8
;
result
+=
s
.
charAt
(
pc
+
i
)
&
0xFF
;
}
return
result
;
}
public
static
String
assemble
(
Element
instructions
)
{
return
InstructionAssembler
.
assemble
(
instructions
,
null
,
null
);
}
public
static
String
assemble
(
Element
instructions
,
String
pcAttrName
)
{
return
InstructionAssembler
.
assemble
(
instructions
,
pcAttrName
,
null
);
}
public
static
String
assemble
(
Element
instructions
,
ClassSyntax
.
GetCPIndex
getCPI
)
{
return
InstructionAssembler
.
assemble
(
instructions
,
null
,
getCPI
);
}
public
static
String
assemble
(
Element
instructions
,
String
pcAttrName
,
ClassSyntax
.
GetCPIndex
getCPI
)
{
return
InstructionAssembler
.
assemble
(
instructions
,
pcAttrName
,
getCPI
);
}
}
test/tools/pack200/pack200-verifier/src/xmlkit/TokenList.java
0 → 100644
浏览文件 @
130dc864
/*
* 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
xmlkit
;
// -*- mode: java; indent-tabs-mode: nil -*-
import
java.util.*
;
/**
* A List of Strings each representing a word or token.
* This object itself is a CharSequence whose characters consist
* of all the tokens, separated by blanks.
*
* @author jrose
*/
public
class
TokenList
extends
ArrayList
<
String
>
implements
CharSequence
{
protected
String
separator
;
protected
boolean
frozen
;
public
TokenList
()
{
this
.
separator
=
" "
;
}
public
TokenList
(
Collection
<?
extends
Object
>
tokens
)
{
super
(
tokens
.
size
());
this
.
separator
=
" "
;
addTokens
(
tokens
);
}
public
TokenList
(
Collection
<?
extends
Object
>
tokens
,
String
separator
)
{
super
(
tokens
.
size
());
this
.
separator
=
separator
;
addTokens
(
tokens
);
}
public
TokenList
(
Object
[]
tokens
)
{
super
(
tokens
.
length
);
this
.
separator
=
" "
;
addTokens
(
tokens
,
0
,
tokens
.
length
);
}
public
TokenList
(
Object
[]
tokens
,
int
beg
,
int
end
)
{
super
(
end
-
beg
);
// capacity
this
.
separator
=
" "
;
addTokens
(
tokens
,
beg
,
end
);
}
public
TokenList
(
Object
[]
tokens
,
int
beg
,
int
end
,
String
separator
)
{
super
(
end
-
beg
);
// capacity
this
.
separator
=
separator
;
addTokens
(
tokens
,
beg
,
end
);
}
public
TokenList
(
String
tokenStr
)
{
this
(
tokenStr
,
" "
,
false
);
}
public
TokenList
(
String
tokenStr
,
String
separator
)
{
this
(
tokenStr
,
separator
,
true
);
}
public
TokenList
(
String
tokenStr
,
String
separator
,
boolean
allowNulls
)
{
super
(
tokenStr
.
length
()
/
5
);
this
.
separator
=
separator
;
addTokens
(
tokenStr
,
allowNulls
);
}
static
public
final
TokenList
EMPTY
;
static
{
TokenList
tl
=
new
TokenList
(
new
Object
[
0
]);
tl
.
freeze
();
EMPTY
=
tl
;
}
public
void
freeze
()
{
if
(!
frozen
)
{
for
(
ListIterator
<
String
>
i
=
listIterator
();
i
.
hasNext
();)
{
i
.
set
(
i
.
next
().
toString
());
}
trimToSize
();
frozen
=
true
;
}
}
public
boolean
isFrozen
()
{
return
frozen
;
}
void
checkNotFrozen
()
{
if
(
isFrozen
())
{
throw
new
UnsupportedOperationException
(
"cannot modify frozen TokenList"
);
}
}
public
String
getSeparator
()
{
return
separator
;
}
public
void
setSeparator
(
String
separator
)
{
checkNotFrozen
();
this
.
separator
=
separator
;
}
/// All normal List mutators must check the frozen bit:
public
String
set
(
int
index
,
String
o
)
{
checkNotFrozen
();
return
super
.
set
(
index
,
o
);
}
public
boolean
add
(
String
o
)
{
checkNotFrozen
();
return
super
.
add
(
o
);
}
public
void
add
(
int
index
,
String
o
)
{
checkNotFrozen
();
super
.
add
(
index
,
o
);
}
public
boolean
addAll
(
Collection
<?
extends
String
>
c
)
{
checkNotFrozen
();
return
super
.
addAll
(
c
);
}
public
boolean
addAll
(
int
index
,
Collection
<?
extends
String
>
c
)
{
checkNotFrozen
();
return
super
.
addAll
(
index
,
c
);
}
public
boolean
remove
(
Object
o
)
{
checkNotFrozen
();
return
super
.
remove
(
o
);
}
public
String
remove
(
int
index
)
{
checkNotFrozen
();
return
super
.
remove
(
index
);
}
public
void
clear
()
{
checkNotFrozen
();
super
.
clear
();
}
/** Add a collection of tokens to the list, applying toString to each. */
public
boolean
addTokens
(
Collection
<?
extends
Object
>
tokens
)
{
// Note that if this sequence is empty, no tokens are added.
// This is different from adding a null string, which is
// a single token.
boolean
added
=
false
;
for
(
Object
token
:
tokens
)
{
add
(
token
.
toString
());
added
=
true
;
}
return
added
;
}
public
boolean
addTokens
(
Object
[]
tokens
,
int
beg
,
int
end
)
{
boolean
added
=
false
;
for
(
int
i
=
beg
;
i
<
end
;
i
++)
{
add
(
tokens
[
i
].
toString
());
added
=
true
;
}
return
added
;
}
public
boolean
addTokens
(
String
tokenStr
)
{
return
addTokens
(
tokenStr
,
false
);
}
public
boolean
addTokens
(
String
tokenStr
,
boolean
allowNulls
)
{
boolean
added
=
false
;
int
pos
=
0
,
limit
=
tokenStr
.
length
(),
sep
=
limit
;
while
(
pos
<
limit
)
{
sep
=
tokenStr
.
indexOf
(
separator
,
pos
);
if
(
sep
<
0
)
{
sep
=
limit
;
}
if
(
sep
==
pos
)
{
if
(
allowNulls
)
{
add
(
""
);
added
=
true
;
}
pos
+=
separator
.
length
();
}
else
{
add
(
tokenStr
.
substring
(
pos
,
sep
));
added
=
true
;
pos
=
sep
+
separator
.
length
();
}
}
if
(
allowNulls
&&
sep
<
limit
)
{
// Input was something like "tok1 tok2 ".
add
(
""
);
added
=
true
;
}
return
added
;
}
public
boolean
addToken
(
Object
token
)
{
return
add
(
token
.
toString
());
}
/** Format the token string, using quotes and escapes.
* Quotes must contain an odd number of 3 or more elements,
* a sequence of begin/end quote pairs, plus a superquote.
* For each token, the first begin/end pair is used for
* which the end quote does not occur in the token.
* If the token contains all end quotes, the last pair
* is used, with all occurrences of the end quote replaced
* by the superquote. If an end quote is the empty string,
* the separator is used instead.
*/
public
String
format
(
String
separator
,
String
[]
quotes
)
{
return
""
;
//@@
}
protected
int
[]
lengths
;
protected
static
final
int
MODC
=
0
,
HINT
=
1
,
BEG0
=
2
,
END0
=
3
;
// Layout of lengths:
// { modCount, hint, -1==beg[0], end[0]==beg[1], ..., length }
// Note that each beg[i]..end[i] span includes a leading separator,
// which is not part of the corresponding token.
protected
final
CharSequence
getCS
(
int
i
)
{
return
(
CharSequence
)
get
(
i
);
}
// Produce (and cache) an table of indexes for each token.
protected
int
[]
getLengths
()
{
int
[]
lengths
=
this
.
lengths
;
;
int
sepLength
=
separator
.
length
();
if
(
lengths
==
null
||
lengths
[
MODC
]
!=
modCount
)
{
int
size
=
this
.
size
();
lengths
=
new
int
[
END0
+
size
+
(
size
==
0
?
1
:
0
)];
lengths
[
MODC
]
=
modCount
;
int
end
=
-
sepLength
;
// cancels leading separator
lengths
[
BEG0
]
=
end
;
for
(
int
i
=
0
;
i
<
size
;
i
++)
{
end
+=
sepLength
;
// count leading separator
end
+=
getCS
(
i
).
length
();
lengths
[
END0
+
i
]
=
end
;
}
this
.
lengths
=
lengths
;
}
return
lengths
;
}
public
int
length
()
{
int
[]
lengths
=
getLengths
();
return
lengths
[
lengths
.
length
-
1
];
}
// Which token does the given index belong to?
protected
int
which
(
int
i
)
{
if
(
i
<
0
)
{
return
-
1
;
}
int
[]
lengths
=
getLengths
();
for
(
int
hint
=
lengths
[
HINT
];;
hint
=
0
)
{
for
(
int
wh
=
hint
;
wh
<
lengths
.
length
-
END0
;
wh
++)
{
int
beg
=
lengths
[
BEG0
+
wh
];
int
end
=
lengths
[
END0
+
wh
];
if
(
i
>=
beg
&&
i
<
end
)
{
lengths
[
HINT
]
=
wh
;
return
wh
;
}
}
if
(
hint
==
0
)
{
return
size
();
// end of the line
}
}
}
public
char
charAt
(
int
i
)
{
if
(
i
<
0
)
{
return
""
.
charAt
(
i
);
}
int
wh
=
which
(
i
);
int
beg
=
lengths
[
BEG0
+
wh
];
int
j
=
i
-
beg
;
int
sepLength
=
separator
.
length
();
if
(
j
<
sepLength
)
{
return
separator
.
charAt
(
j
);
}
return
getCS
(
wh
).
charAt
(
j
-
sepLength
);
}
public
CharSequence
subSequence
(
int
beg
,
int
end
)
{
//System.out.println("i: "+beg+".."+end);
if
(
beg
==
end
)
{
return
""
;
}
if
(
beg
<
0
)
{
charAt
(
beg
);
// raise exception
}
if
(
beg
>
end
)
{
charAt
(-
1
);
// raise exception
}
int
begWh
=
which
(
beg
);
int
endWh
=
which
(
end
);
if
(
endWh
==
size
()
||
end
==
lengths
[
BEG0
+
endWh
])
{
--
endWh
;
}
//System.out.println("wh: "+begWh+".."+endWh);
int
begBase
=
lengths
[
BEG0
+
begWh
];
int
endBase
=
lengths
[
BEG0
+
endWh
];
int
sepLength
=
separator
.
length
();
int
begFrag
=
0
;
if
((
beg
-
begBase
)
<
sepLength
)
{
begFrag
=
sepLength
-
(
beg
-
begBase
);
beg
+=
begFrag
;
}
int
endFrag
=
0
;
if
((
end
-
endBase
)
<
sepLength
)
{
endFrag
=
(
end
-
endBase
);
end
=
endBase
;
endBase
=
lengths
[
BEG0
+
--
endWh
];
}
if
(
false
)
{
System
.
out
.
print
(
"beg[wbf]end[wbf]"
);
int
pr
[]
=
{
begWh
,
begBase
,
begFrag
,
beg
,
endWh
,
endBase
,
endFrag
,
end
};
for
(
int
k
=
0
;
k
<
pr
.
length
;
k
++)
{
System
.
out
.
print
((
k
==
4
?
" "
:
" "
)
+
(
pr
[
k
]));
}
System
.
out
.
println
();
}
if
(
begFrag
>
0
&&
(
end
+
endFrag
)
-
begBase
<=
sepLength
)
{
// Special case: Slice the separator.
beg
-=
begFrag
;
end
+=
endFrag
;
return
separator
.
substring
(
beg
-
begBase
,
end
-
begBase
);
}
if
(
begWh
==
endWh
&&
(
begFrag
+
endFrag
)
==
0
)
{
// Special case: Slice a single token.
return
getCS
(
begWh
).
subSequence
(
beg
-
begBase
-
sepLength
,
end
-
endBase
-
sepLength
);
}
Object
[]
subTokens
=
new
Object
[
1
+
(
endWh
-
begWh
)
+
1
];
int
fillp
=
0
;
if
(
begFrag
==
sepLength
)
{
// Insert a leading null token to force an initial separator.
subTokens
[
fillp
++]
=
""
;
begFrag
=
0
;
}
for
(
int
wh
=
begWh
;
wh
<=
endWh
;
wh
++)
{
CharSequence
cs
=
getCS
(
wh
);
if
(
wh
==
begWh
||
wh
==
endWh
)
{
// Slice it.
int
csBeg
=
(
wh
==
begWh
)
?
(
beg
-
begBase
)
-
sepLength
:
0
;
int
csEnd
=
(
wh
==
endWh
)
?
(
end
-
endBase
)
-
sepLength
:
cs
.
length
();
cs
=
cs
.
subSequence
(
csBeg
,
csEnd
);
if
(
begFrag
>
0
&&
wh
==
begWh
)
{
cs
=
separator
.
substring
(
sepLength
-
begFrag
)
+
cs
;
}
if
(
endFrag
>
0
&&
wh
==
endWh
)
{
cs
=
cs
.
toString
()
+
separator
.
substring
(
0
,
endFrag
);
}
}
subTokens
[
fillp
++]
=
cs
;
}
return
new
TokenList
(
subTokens
,
0
,
fillp
,
separator
);
}
/** Returns the concatenation of all tokens,
* with intervening separator characters.
*/
public
String
toString
()
{
StringBuilder
buf
=
new
StringBuilder
(
length
());
int
size
=
this
.
size
();
for
(
int
i
=
0
;
i
<
size
;
i
++)
{
if
(
i
>
0
)
{
buf
.
append
(
separator
);
}
buf
.
append
(
get
(
i
));
}
return
buf
.
toString
();
}
/*---- TESTING CODE ----
public static void main(String[] av) {
if (av.length == 0) av = new String[]{"one", "2", "", "four"};
TokenList ts = new TokenList();
final String SEP = ", ";
ts.setSeparator(SEP);
for (int i = -1; i < av.length; i++) {
if (i >= 0) ts.addToken(av[i]);
{
TokenList tsCopy = new TokenList(ts.toString(), SEP);
if (!tsCopy.equals(ts)) {
tsCopy.setSeparator(")(");
System.out.println("!= ("+tsCopy+")");
}
}
{
TokenList tsBar = new TokenList(ts, "|");
tsBar.add(0, "[");
tsBar.add("]");
System.out.println(tsBar);
}
if (false) {
int[] ls = ts.getLengths();
System.out.println("ts: "+ts);
System.out.print("ls: {");
for (int j = 0; j < ls.length; j++) System.out.print(" "+ls[j]);
System.out.println(" }");
}
assert0(ts.size() == i+1);
assert0(i < 0 || ts.get(i) == av[i]);
String tss = ts.toString();
int tslen = tss.length();
assert0(ts.length() == tss.length());
for (int n = 0; n < tslen; n++) {
assert0(ts.charAt(n) == tss.charAt(n));
}
for (int j = 0; j < tslen; j++) {
for (int k = tslen; k >= j; k--) {
CharSequence sub = ts.subSequence(j, k);
//System.out.println("|"+sub+"|");
assert0(sub.toString().equals(tss.substring(j, k)));
}
}
}
}
static void assert0(boolean z) {
if (!z) throw new RuntimeException("assert failed");
}
// ---- TESTING CODE ----*/
}
test/tools/pack200/pack200-verifier/src/xmlkit/XMLKit.java
0 → 100644
浏览文件 @
130dc864
/*
* 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
xmlkit
;
// -*- mode: java; indent-tabs-mode: nil -*-
// XML Implementation packages:
import
java.util.*
;
import
java.io.Reader
;
import
java.io.Writer
;
import
java.io.OutputStream
;
import
java.io.InputStreamReader
;
import
java.io.OutputStreamWriter
;
import
java.io.BufferedReader
;
import
java.io.PrintWriter
;
import
java.io.StringWriter
;
import
java.io.StringReader
;
import
java.io.IOException
;
import
org.xml.sax.XMLReader
;
import
org.xml.sax.InputSource
;
import
org.xml.sax.ContentHandler
;
import
org.xml.sax.SAXException
;
import
org.xml.sax.SAXParseException
;
import
org.xml.sax.Attributes
;
import
org.xml.sax.ext.LexicalHandler
;
import
org.xml.sax.helpers.AttributesImpl
;
/**
* A kit of methods and classes useful for manipulating XML trees in
* memory. They are very compact and easy to use. An XML element
* occupies six pointers of overhead (like two arrays) plus a pointer
* for its name, each attribute name and value, and each sub-element.
* Many useful XML operations (or Lisp-like calls) can be accomplished
* with a single method call on an element itself.
* <p>
* There is strong integration with the Java collection classes.
* There are viewing and conversion operators to and from various
* collection types. Elements directly support list iterators.
* Most <tt>List</tt> methods work analogously on elements.
* <p>
* Because of implementation compromises, these XML trees are less
* functional than many standard XML classes.
* <ul>
* <li>There are no parent or sibling pointers in the tree.</li>
* <li>Attribute names are simple strings, with no namespaces.</li>
* <li>There is no internal support for schemas or validation.</li>
* </ul>
* <p>
* Here is a summary of functionality in <tt>XMLKit</tt>.
* (Overloaded groups of methods are summarized by marking some
* arguments optional with their default values. Some overloaded
* arguments are marked with their alternative types separated by
* a bar "|". Arguments or return values for which a null is
* specially significant are marked by an alternative "|null".
* Accessors which have corresponding setters are marked
* by "/set". Removers which have corresponding retainers are marked
* by "/retain".)
* <pre>
* --- element construction
* new Element(int elemCapacity=4), String name=""
* new Element(String name, String[] attrs={}, Element[] elems={}, int elemCapacity=4)
* new Element(String name, String[] attrs, Object[] elems, int elemCapacity=4)
* new Element(Element original) // shallow copy
* new Element(String name="", Collection elems) // coercion
*
* Element shallowCopy()
* Element shallowFreeze() // side-effecting
* Element deepCopy()
* Element deepFreeze() // not side-effecting
*
* EMPTY // frozen empty anonymous element
* void ensureExtraCapacity(int)
* void trimToSize()
* void sortAttrs() // sort by key
*
* --- field accessors
* String getName()/set
* int size()
* boolean isEmpty()
* boolean isFrozen()
* boolean isAnonymous()
* int getExtraCapacity()/set
* int attrSize()
*
* --- attribute accessors
* String getAttr(int i)/set
* String getAttrName(int i)
*
* String getAttr(String key)/set
* List getAttrList(String key)/set
* Number getAttrNumber(String key)/set
* long getAttrLong(String key)/set
* double getAttrDouble(String key)/set
*
* String getAttr(String key, String dflt=null)
* long getAttrLong(String key, long dflt=0)
* double getAttrDouble(String key, double dflt=0)
*
* Element copyAttrsOnly()
* Element getAttrs()/set => <em><><key>value</key>...</></em>
* void addAttrs(Element attrs)
*
* void removeAttr(int i)
* void clearAttrs()
*
* --- element accessors
* Object get(int i)/set
* Object getLast() | null
* Object[] toArray()
* Element copyContentOnly()
*
* void add(int i=0, Object subElem)
* int addAll(int i=0, Collection | Element elems)
* int addContent(int i=0, TokenList|Element|Object|null)
* void XMLKit.addContent(TokenList|Element|Object|null, Collection sink|null)
*
* void clear(int beg=0, int end=size)
* void sort(Comparator=contentOrder())
* void reverse()
* void shuffle(Random rnd=(anonymous))
* void rotate(int distance)
* Object min/max(Comparator=contentOrder())
*
* --- text accessors
* CharSequence getText()/set
* CharSequence getUnmarkedText()
* int addText(int i=size, CharSequence)
* void trimText();
*
* --- views
* List asList() // element view
* ListIterator iterator()
* PrintWriter asWriter()
* Map asAttrMap()
* Iterable<CharSequence> texts()
* Iterable<Element> elements()
* Iterable<T> partsOnly(Class<T>)
* String[] toStrings()
*
* --- queries
* boolean equals(Element | Object)
* int compareTo(Element | Object)
* boolean equalAttrs(Element)
* int hashCode()
* boolean isText() // every sub-elem is CharSequence
* boolean hasText() // some sub-elem is CharSequence
*
* boolean contains(Object)
* boolean containsAttr(String)
*
* int indexOf(Object)
* int indexOf(Filter, int fromIndex=0)
* int lastIndexOf(Object)
* int lastIndexOf(Filter, int fromIndex=size-1)
*
* int indexOfAttr(String)
*
* // finders, removers, and replacers do addContent of each filtered value
* // (i.e., TokenLists and anonymous Elements are broken out into their parts)
* boolean matches(Filter)
*
* Object find(Filter, int fromIndex=0)
* Object findLast(Filter, int fromIndex=size-1)
* Element findAll(Filter, int fromIndex=0 & int toIndex=size)
* int findAll(Filter, Collection sink | null, int fromIndex=0 & int toIndex=size)
*
* Element removeAllInTree(Filter)/retain
* int findAllInTree(Filter, Collection sink | null)
* int countAllInTree(Filter)
* Element removeAllInTree(Filter)/retain
* int removeAllInTree(Filter, Collection sink | null)/retain
* void replaceAllInTree(Filter)
*
* Element findElement(String name=any)
* Element findAllElements(String name=any)
*
* Element findWithAttr(String key, String value=any)
* Element findAllWithAttr(String key, String value=any)
*
* Element removeElement(String name=any)
* Element removeAllElements(String name=any)/retain
*
* Element removeWithAttr(String key, String value=any)
* Element removeAllWithAttr(String key, String value=any)/retain
*
* //countAll is the same as findAll but with null sink
* int countAll(Filter)
* int countAllElements(String name=any)
* int countAllWithAttr(String key, String value=any)
*
* void replaceAll(Filter, int fromIndex=0 & int toIndex=size)
* void replaceAllInTree(Filter)
* void XMLKit.replaceAll(Filter, List target) //if(fx){remove x;addContent fx}
*
* --- element mutators
* boolean remove(Object)
* Object remove(int)
* Object removeLast() | null
*
* Object remove(Filter, int fromIndex=0)
* Object removeLast(Filter, int fromIndex=size-1)
* Element sink = removeAll(Filter, int fromIndex=0 & int toIndex=size)/retain
* int count = removeAll(Filter, int fromIndex=0 & int toIndex=size, Collection sink | null)/retain
*
* Element removeAllElements(String name=any)
*
* --- attribute mutators
* ??int addAllAttrsFrom(Element attrSource)
*
* --- parsing and printing
* void tokenize(String delims=whitespace, returnDelims=false)
* void writeTo(Writer)
* void writePrettyTo(Writer)
* String prettyString()
* String toString()
*
* ContentHandler XMLKit.makeBuilder(Collection sink, tokenizing=false, makeFrozen=false) // for standard XML parser
* Element XMLKit.readFrom(Reader, tokenizing=false, makeFrozen=false)
* void XMLKit.prettyPrintTo(Writer | OutputStream, Element)
* class XMLKit.Printer(Writer) { void print/Recursive(Element) }
* void XMLKit.output(Object elem, ContentHandler, LexicalHandler=null)
* void XMLKit.writeToken(String, char quote, Writer)
* void XMLKit.writeCData(String, Writer)
* Number XMLKit.convertToNumber(String, Number dflt=null)
* long XMLKit.convertToLong(String, long dflt=0)
* double XMLKit.convertToDouble(String, double dflt=0)
*
* --- filters
* XMLKit.ElementFilter { Element filter(Element) }
* XMLKit.elementFilter(String name=any | Collection nameSet)
* XMLKit.AttrFilter(String key) { boolean test(String value) }
* XMLKit.attrFilter(String key, String value=any)
* XMLKit.attrFilter(Element matchThis, String key)
* XMLKit.classFilter(Class)
* XMLKit.textFilter() // matches any CharSequence
* XMLKit.specialFilter() // matches any Special element
* XMLKit.methodFilter(Method m, Object[] args=null, falseResult=null)
* XMLKit.testMethodFilter(Method m, Object[] args=null)
* XMLKit.not(Filter) // inverts sense of Filter
* XMLKit.and(Filter&Filter | Filter[])
* XMLKit.or(Filter&Filter | Filter[])
* XMLKit.stack(Filter&Filter | Filter[]) // result is (fx && g(fx))
* XMLKit.content(Filter, Collection sink) // copies content to sink
* XMLKit.replaceInTree(Filter pre, Filter post=null) // pre-replace else recur
* XMLKit.findInTree(Filter pre, Collection sink=null) // pre-find else recur
* XMLKit.nullFilter() // ignores input, always returns null (i.e., false)
* XMLKit.selfFilter( ) // always returns input (i.e., true)
* XMLKit.emptyFilter() // ignores input, always returns EMPTY
* XMLKit.constantFilter(Object) // ignores input, always returns constant
*
* --- misc
* Comparator XMLKit.contentOrder() // for comparing/sorting mixed content
* Method XMLKit.Element.method(String name) // returns Element method
* </pre>
*
* @author jrose
*/
public
abstract
class
XMLKit
{
private
XMLKit
()
{
}
// We need at least this much slop if the element is to stay unfrozen.
static
final
int
NEED_SLOP
=
1
;
static
final
Object
[]
noPartsFrozen
=
{};
static
final
Object
[]
noPartsNotFrozen
=
new
Object
[
NEED_SLOP
];
static
final
String
WHITESPACE_CHARS
=
" \t\n\r\f"
;
static
final
String
ANON_NAME
=
new
String
(
"*"
);
// unique copy of "*"
public
static
final
class
Element
implements
Comparable
<
Element
>,
Iterable
<
Object
>
{
// Note: Does not implement List, because it has more
// significant parts besides its sub-elements. Therefore,
// hashCode and equals must be more distinctive than Lists.
// <name> of element
String
name
;
// number of child elements, in parts[0..size-1]
int
size
;
// The parts start with child elements:: {e0, e1, e2, ...}.
// Following that are optional filler elements, all null.
// Following that are attributes as key/value pairs.
// They are in reverse: {...key2, val2, key1, val1, key0, val0}.
// Child elements and attr keys and values are never null.
Object
[]
parts
;
// Build a partially-constructed node.
// Caller is responsible for initializing promised attributes.
Element
(
String
name
,
int
size
,
int
capacity
)
{
this
.
name
=
name
.
toString
();
this
.
size
=
size
;
assert
(
size
<=
capacity
);
this
.
parts
=
capacity
>
0
?
new
Object
[
capacity
]
:
noPartsFrozen
;
}
/** An anonymous, empty element.
* Optional elemCapacity argument is expected number of sub-elements.
*/
public
Element
()
{
this
(
ANON_NAME
,
0
,
NEED_SLOP
+
4
);
}
public
Element
(
int
extraCapacity
)
{
this
(
ANON_NAME
,
0
,
NEED_SLOP
+
Math
.
max
(
0
,
extraCapacity
));
}
/** An empty element with the given name.
* Optional extraCapacity argument is expected number of sub-elements.
*/
public
Element
(
String
name
)
{
this
(
name
,
0
,
NEED_SLOP
+
4
);
}
public
Element
(
String
name
,
int
extraCapacity
)
{
this
(
name
,
0
,
NEED_SLOP
+
Math
.
max
(
0
,
extraCapacity
));
}
/** An empty element with the given name and attributes.
* Optional extraCapacity argument is expected number of sub-elements.
*/
public
Element
(
String
name
,
String
...
attrs
)
{
this
(
name
,
attrs
,
(
Element
[])
null
,
0
);
}
public
Element
(
String
name
,
String
[]
attrs
,
int
extraCapacity
)
{
this
(
name
,
attrs
,
(
Element
[])
null
,
extraCapacity
);
}
/** An empty element with the given name and sub-elements.
* Optional extraCapacity argument is expected extra sub-elements.
*/
public
Element
(
String
name
,
Element
...
elems
)
{
this
(
name
,
(
String
[])
null
,
elems
,
0
);
}
public
Element
(
String
name
,
Element
[]
elems
,
int
extraCapacity
)
{
this
(
name
,
(
String
[])
null
,
elems
,
extraCapacity
);
}
/** An empty element with the given name, attributes, and sub-elements.
* Optional extraCapacity argument is expected extra sub-elements.
*/
public
Element
(
String
name
,
String
[]
attrs
,
Object
...
elems
)
{
this
(
name
,
attrs
,
elems
,
0
);
}
public
Element
(
String
name
,
String
[]
attrs
,
Object
[]
elems
,
int
extraCapacity
)
{
this
(
name
,
0
,
((
elems
==
null
)
?
0
:
elems
.
length
)
+
Math
.
max
(
0
,
extraCapacity
)
+
NEED_SLOP
+
((
attrs
==
null
)
?
0
:
attrs
.
length
));
int
ne
=
((
elems
==
null
)
?
0
:
elems
.
length
);
int
na
=
((
attrs
==
null
)
?
0
:
attrs
.
length
);
int
fillp
=
0
;
for
(
int
i
=
0
;
i
<
ne
;
i
++)
{
if
(
elems
[
i
]
!=
null
)
{
parts
[
fillp
++]
=
elems
[
i
];
}
}
size
=
fillp
;
for
(
int
i
=
0
;
i
<
na
;
i
+=
2
)
{
setAttr
(
attrs
[
i
+
0
],
attrs
[
i
+
1
]);
}
}
public
Element
(
Collection
c
)
{
this
(
c
.
size
());
addAll
(
c
);
}
public
Element
(
String
name
,
Collection
c
)
{
this
(
name
,
c
.
size
());
addAll
(
c
);
}
/** Shallow copy. Same as old.shallowCopy().
* Optional extraCapacity argument is expected extra sub-elements.
*/
public
Element
(
Element
old
)
{
this
(
old
,
0
);
}
public
Element
(
Element
old
,
int
extraCapacity
)
{
this
(
old
.
name
,
old
.
size
,
old
.
size
+
Math
.
max
(
0
,
extraCapacity
)
+
NEED_SLOP
+
old
.
attrLength
());
// copy sub-elements
System
.
arraycopy
(
old
.
parts
,
0
,
parts
,
0
,
size
);
int
alen
=
parts
.
length
-
(
size
+
Math
.
max
(
0
,
extraCapacity
)
+
NEED_SLOP
);
// copy attributes
System
.
arraycopy
(
old
.
parts
,
old
.
parts
.
length
-
alen
,
parts
,
parts
.
length
-
alen
,
alen
);
assert
(!
isFrozen
());
}
/** Shallow copy. Same as new Element(this). */
public
Element
shallowCopy
()
{
return
new
Element
(
this
);
}
static
public
final
Element
EMPTY
=
new
Element
(
ANON_NAME
,
0
,
0
);
Element
deepFreezeOrCopy
(
boolean
makeFrozen
)
{
if
(
makeFrozen
&&
isFrozen
())
{
return
this
;
// no need to copy it
}
int
alen
=
attrLength
();
int
plen
=
size
+
(
makeFrozen
?
0
:
NEED_SLOP
)
+
alen
;
Element
copy
=
new
Element
(
name
,
size
,
plen
);
// copy attributes
System
.
arraycopy
(
parts
,
parts
.
length
-
alen
,
copy
.
parts
,
plen
-
alen
,
alen
);
// copy sub-elements
for
(
int
i
=
0
;
i
<
size
;
i
++)
{
Object
e
=
parts
[
i
];
String
str
;
if
(
e
instanceof
Element
)
{
// recursion is common case
e
=
((
Element
)
e
).
deepFreezeOrCopy
(
makeFrozen
);
}
else
if
(
makeFrozen
)
{
// Freeze StringBuffers, etc.
e
=
fixupString
(
e
);
}
copy
.
setRaw
(
i
,
e
);
}
return
copy
;
}
/** Returns new Element(this), and also recursively copies sub-elements. */
public
Element
deepCopy
()
{
return
deepFreezeOrCopy
(
false
);
}
/** Returns frozen version of deepCopy. */
public
Element
deepFreeze
()
{
return
deepFreezeOrCopy
(
true
);
}
/** Freeze this element.
* Throw an IllegalArgumentException if any sub-element is not already frozen.
* (Use deepFreeze() to make a frozen copy of an entire element tree.)
*/
public
void
shallowFreeze
()
{
if
(
isFrozen
())
{
return
;
}
int
alen
=
attrLength
();
Object
[]
nparts
=
new
Object
[
size
+
alen
];
// copy attributes
System
.
arraycopy
(
parts
,
parts
.
length
-
alen
,
nparts
,
size
,
alen
);
// copy sub-elements
for
(
int
i
=
0
;
i
<
size
;
i
++)
{
Object
e
=
parts
[
i
];
String
str
;
if
(
e
instanceof
Element
)
{
// recursion is common case
if
(!((
Element
)
e
).
isFrozen
())
{
throw
new
IllegalArgumentException
(
"Sub-element must be frozen."
);
}
}
else
{
// Freeze StringBuffers, etc.
e
=
fixupString
(
e
);
}
nparts
[
i
]
=
e
;
}
parts
=
nparts
;
assert
(
isFrozen
());
}
/** Return the name of this element. */
public
String
getName
()
{
return
name
;
}
/** Change the name of this element. */
public
void
setName
(
String
name
)
{
checkNotFrozen
();
this
.
name
=
name
.
toString
();
}
/** Reports if the element's name is a particular string (spelled "*").
* Such elements are created by the nullary Element constructor,
* and by query functions which return multiple values,
* such as <tt>findAll</tt>.
*/
public
boolean
isAnonymous
()
{
return
name
==
ANON_NAME
;
}
/** Return number of elements. (Does not include attributes.) */
public
int
size
()
{
return
size
;
}
/** True if no elements. (Does not consider attributes.) */
public
boolean
isEmpty
()
{
return
size
==
0
;
}
/** True if this element does not allow modification. */
public
boolean
isFrozen
()
{
// It is frozen iff there is no slop space.
return
!
hasNulls
(
NEED_SLOP
);
}
void
checkNotFrozen
()
{
if
(
isFrozen
())
{
throw
new
UnsupportedOperationException
(
"cannot modify frozen element"
);
}
}
/** Remove specified elements. (Does not affect attributes.) */
public
void
clear
()
{
clear
(
0
,
size
);
}
public
void
clear
(
int
beg
)
{
clear
(
beg
,
size
);
}
public
void
clear
(
int
beg
,
int
end
)
{
if
(
end
>
size
)
{
badIndex
(
end
);
}
if
(
beg
<
0
||
beg
>
end
)
{
badIndex
(
beg
);
}
if
(
beg
==
end
)
{
return
;
}
checkNotFrozen
();
if
(
end
==
size
)
{
if
(
beg
==
0
&&
parts
.
length
>
0
&&
parts
[
parts
.
length
-
1
]
==
null
)
{
// If no attributes, free the parts array.
parts
=
noPartsNotFrozen
;
size
=
0
;
}
else
{
clearParts
(
beg
,
size
);
size
=
beg
;
}
}
else
{
close
(
beg
,
end
-
beg
);
}
}
void
clearParts
(
int
beg
,
int
end
)
{
for
(
int
i
=
beg
;
i
<
end
;
i
++)
{
parts
[
i
]
=
null
;
}
}
/** True if name, attributes, and elements are the same. */
public
boolean
equals
(
Element
that
)
{
if
(!
this
.
name
.
equals
(
that
.
name
))
{
return
false
;
}
if
(
this
.
size
!=
that
.
size
)
{
return
false
;
}
// elements must be equal and ordered
Object
[]
thisParts
=
this
.
parts
;
Object
[]
thatParts
=
that
.
parts
;
for
(
int
i
=
0
;
i
<
size
;
i
++)
{
Object
thisPart
=
thisParts
[
i
];
Object
thatPart
=
thatParts
[
i
];
if
(
thisPart
instanceof
Element
)
{
// recursion is common case
if
(!
thisPart
.
equals
(
thatPart
))
{
return
false
;
}
}
else
{
// If either is a non-string char sequence, normalize it.
thisPart
=
fixupString
(
thisPart
);
thatPart
=
fixupString
(
thatPart
);
if
(!
thisPart
.
equals
(
thatPart
))
{
return
false
;
}
}
}
// finally, attributes must be equal (unordered)
return
this
.
equalAttrs
(
that
);
}
// bridge method
public
boolean
equals
(
Object
o
)
{
if
(!(
o
instanceof
Element
))
{
return
false
;
}
return
equals
((
Element
)
o
);
}
public
int
hashCode
()
{
int
hc
=
0
;
int
alen
=
attrLength
();
for
(
int
i
=
parts
.
length
-
alen
;
i
<
parts
.
length
;
i
+=
2
)
{
hc
+=
(
parts
[
i
+
0
].
hashCode
()
^
parts
[
i
+
1
].
hashCode
());
}
hc
^=
hc
<<
11
;
hc
+=
name
.
hashCode
();
for
(
int
i
=
0
;
i
<
size
;
i
++)
{
hc
^=
hc
<<
7
;
Object
p
=
parts
[
i
];
if
(
p
instanceof
Element
)
{
hc
+=
p
.
hashCode
();
// recursion is common case
}
else
{
hc
+=
fixupString
(
p
).
hashCode
();
}
}
hc
^=
hc
>>>
19
;
return
hc
;
}
/** Compare lexicographically. Earlier-spelled attrs are more sigificant. */
public
int
compareTo
(
Element
that
)
{
int
r
;
// Primary key is element name.
r
=
this
.
name
.
compareTo
(
that
.
name
);
if
(
r
!=
0
)
{
return
r
;
}
// Secondary key is attributes, as if in normal key order.
// The key/value pairs are sorted as a token sequence.
int
thisAlen
=
this
.
attrLength
();
int
thatAlen
=
that
.
attrLength
();
if
(
thisAlen
!=
0
||
thatAlen
!=
0
)
{
r
=
compareAttrs
(
thisAlen
,
that
,
thatAlen
,
true
);
assert
(
assertAttrCompareOK
(
r
,
that
));
if
(
r
!=
0
)
{
return
r
;
}
}
// Finally, elements should be equal and ordered,
// and the first difference rules.
Object
[]
thisParts
=
this
.
parts
;
Object
[]
thatParts
=
that
.
parts
;
int
minSize
=
this
.
size
;
if
(
minSize
>
that
.
size
)
{
minSize
=
that
.
size
;
}
Comparator
<
Object
>
cc
=
contentOrder
();
for
(
int
i
=
0
;
i
<
minSize
;
i
++)
{
r
=
cc
.
compare
(
thisParts
[
i
],
thatParts
[
i
]);
if
(
r
!=
0
)
{
return
r
;
}
}
//if (this.size < that.size) return -1;
return
this
.
size
-
that
.
size
;
}
private
boolean
assertAttrCompareOK
(
int
r
,
Element
that
)
{
Element
e0
=
this
.
copyAttrsOnly
();
Element
e1
=
that
.
copyAttrsOnly
();
e0
.
sortAttrs
();
e1
.
sortAttrs
();
int
r2
;
for
(
int
k
=
0
;;
k
++)
{
boolean
con0
=
e0
.
containsAttr
(
k
);
boolean
con1
=
e1
.
containsAttr
(
k
);
if
(
con0
!=
con1
)
{
if
(!
con0
)
{
r2
=
0
-
1
;
break
;
}
if
(!
con1
)
{
r2
=
1
-
0
;
break
;
}
}
if
(!
con0
)
{
r2
=
0
;
break
;
}
String
k0
=
e0
.
getAttrName
(
k
);
String
k1
=
e1
.
getAttrName
(
k
);
r2
=
k0
.
compareTo
(
k1
);
if
(
r2
!=
0
)
{
break
;
}
String
v0
=
e0
.
getAttr
(
k
);
String
v1
=
e1
.
getAttr
(
k
);
r2
=
v0
.
compareTo
(
v1
);
if
(
r2
!=
0
)
{
break
;
}
}
if
(
r
!=
0
)
{
r
=
(
r
>
0
)
?
1
:
-
1
;
}
if
(
r2
!=
0
)
{
r2
=
(
r2
>
0
)
?
1
:
-
1
;
}
if
(
r
!=
r2
)
{
System
.
out
.
println
(
"*** wrong attr compare, "
+
r
+
" != "
+
r2
);
System
.
out
.
println
(
" this = "
+
this
);
System
.
out
.
println
(
" attr->"
+
e0
);
System
.
out
.
println
(
" that = "
+
that
);
System
.
out
.
println
(
" attr->"
+
e1
);
}
return
r
==
r2
;
}
private
void
badIndex
(
int
i
)
{
Object
badRef
=
(
new
Object
[
0
])[
i
];
}
public
Object
get
(
int
i
)
{
if
(
i
>=
size
)
{
badIndex
(
i
);
}
return
parts
[
i
];
}
public
Object
set
(
int
i
,
Object
e
)
{
if
(
i
>=
size
)
{
badIndex
(
i
);
}
e
.
getClass
();
// null check
checkNotFrozen
();
Object
old
=
parts
[
i
];
setRaw
(
i
,
e
);
return
old
;
}
void
setRaw
(
int
i
,
Object
e
)
{
parts
[
i
]
=
e
;
}
public
boolean
remove
(
Object
e
)
{
int
i
=
indexOf
(
e
);
if
(
i
<
0
)
{
return
false
;
}
close
(
i
,
1
);
return
true
;
}
public
Object
remove
(
int
i
)
{
if
(
i
>=
size
)
{
badIndex
(
i
);
}
Object
e
=
parts
[
i
];
close
(
i
,
1
);
return
e
;
}
public
Object
removeLast
()
{
if
(
size
==
0
)
{
return
null
;
}
return
remove
(
size
-
1
);
}
/** Remove the first element matching the given filter.
* Return the filtered value.
*/
public
Object
remove
(
Filter
f
)
{
return
findOrRemove
(
f
,
0
,
true
);
}
public
Object
remove
(
Filter
f
,
int
fromIndex
)
{
if
(
fromIndex
<
0
)
{
fromIndex
=
0
;
}
return
findOrRemove
(
f
,
fromIndex
,
true
);
}
/** Remove the last element matching the given filter.
* Return the filtered value.
*/
public
Object
removeLast
(
Filter
f
)
{
return
findOrRemoveLast
(
f
,
size
-
1
,
true
);
}
public
Object
removeLast
(
Filter
f
,
int
fromIndex
)
{
if
(
fromIndex
>=
size
)
{
fromIndex
=
size
-
1
;
}
return
findOrRemoveLast
(
f
,
fromIndex
,
true
);
}
/** Remove all elements matching the given filter.
* If there is a non-null collection given as a sink,
* transfer removed elements to the given collection.
* The int result is the number of removed elements.
* If there is a null sink given, the removed elements
* are discarded. If there is no sink given, the removed
* elements are returned in an anonymous container element.
*/
public
Element
removeAll
(
Filter
f
)
{
Element
result
=
new
Element
();
findOrRemoveAll
(
f
,
false
,
0
,
size
,
result
.
asList
(),
true
);
return
result
;
}
public
Element
removeAll
(
Filter
f
,
int
fromIndex
,
int
toIndex
)
{
Element
result
=
new
Element
();
findOrRemoveAll
(
f
,
true
,
fromIndex
,
toIndex
,
result
.
asList
(),
true
);
return
result
;
}
public
int
removeAll
(
Filter
f
,
Collection
<
Object
>
sink
)
{
return
findOrRemoveAll
(
f
,
false
,
0
,
size
,
sink
,
true
);
}
public
int
removeAll
(
Filter
f
,
int
fromIndex
,
int
toIndex
,
Collection
<
Object
>
sink
)
{
return
findOrRemoveAll
(
f
,
false
,
fromIndex
,
toIndex
,
sink
,
true
);
}
/** Remove all elements not matching the given filter.
* If there is a non-null collection given as a sink,
* transfer removed elements to the given collection.
* The int result is the number of removed elements.
* If there is a null sink given, the removed elements
* are discarded. If there is no sink given, the removed
* elements are returned in an anonymous container element.
*/
public
Element
retainAll
(
Filter
f
)
{
Element
result
=
new
Element
();
findOrRemoveAll
(
f
,
true
,
0
,
size
,
result
.
asList
(),
true
);
return
result
;
}
public
Element
retainAll
(
Filter
f
,
int
fromIndex
,
int
toIndex
)
{
Element
result
=
new
Element
();
findOrRemoveAll
(
f
,
true
,
fromIndex
,
toIndex
,
result
.
asList
(),
true
);
return
result
;
}
public
int
retainAll
(
Filter
f
,
Collection
<
Object
>
sink
)
{
return
findOrRemoveAll
(
f
,
true
,
0
,
size
,
sink
,
true
);
}
public
int
retainAll
(
Filter
f
,
int
fromIndex
,
int
toIndex
,
Collection
<
Object
>
sink
)
{
return
findOrRemoveAll
(
f
,
true
,
fromIndex
,
toIndex
,
sink
,
true
);
}
public
void
add
(
int
i
,
Object
e
)
{
// (The shape of this method is tweaked for common cases.)
e
.
getClass
();
// force a null check on e
if
(
hasNulls
(
1
+
NEED_SLOP
))
{
// Common case: Have some slop space.
if
(
i
==
size
)
{
// Most common case: Append.
setRaw
(
i
,
e
);
size
++;
return
;
}
if
(
i
>
size
)
{
badIndex
(
i
);
}
// Second most common case: Shift right by one.
open
(
i
,
1
);
setRaw
(
i
,
e
);
return
;
}
// Ran out of space. Do something complicated.
size
=
expand
(
i
,
1
);
setRaw
(
i
,
e
);
}
public
boolean
add
(
Object
e
)
{
add
(
size
,
e
);
return
true
;
}
public
Object
getLast
()
{
return
size
==
0
?
null
:
parts
[
size
-
1
];
}
/** Returns the text of this Element.
* All sub-elements of this Element must be of type CharSequence.
* A ClassCastException is raised if there are non-character sub-elements.
* If there is one sub-element, return it.
* Otherwise, returns a TokenList of all sub-elements.
* This results in a space being placed between each adjacent pair of sub-elements.
*/
public
CharSequence
getText
()
{
checkTextOnly
();
if
(
size
==
1
)
{
return
parts
[
0
].
toString
();
}
else
{
return
new
TokenList
(
parts
,
0
,
size
);
}
}
/** Provides an iterable view of this object as a series of texts.
* All sub-elements of this Element must be of type CharSequence.
* A ClassCastException is raised if there are non-character sub-elements.
*/
public
Iterable
<
CharSequence
>
texts
()
{
checkTextOnly
();
return
(
Iterable
<
CharSequence
>)
(
Iterable
)
this
;
}
/** Returns an array of strings derived from the sub-elements of this object.
* All sub-elements of this Element must be of type CharSequence.
* A ClassCastException is raised if there are non-character sub-elements.
*/
public
String
[]
toStrings
()
{
//checkTextOnly();
String
[]
result
=
new
String
[
size
];
for
(
int
i
=
0
;
i
<
size
;
i
++)
{
result
[
i
]
=
((
CharSequence
)
parts
[
i
]).
toString
();
}
return
result
;
}
/** Like getText, except that it disregards non-text elements.
* Non-text elements are replaced by their textual contents, if any.
* Text elements which were separated only by non-text element
* boundaries are merged into single tokens.
* <p>
* There is no corresponding setter, since this accessor does
* not report the full state of the element.
*/
public
CharSequence
getFlatText
()
{
if
(
size
==
1
)
{
// Simple cases.
if
(
parts
[
0
]
instanceof
CharSequence
)
{
return
parts
[
0
].
toString
();
}
else
{
return
new
TokenList
();
}
}
if
(
isText
())
{
return
getText
();
}
// Filter and merge.
Element
result
=
new
Element
(
size
);
boolean
merge
=
false
;
for
(
int
i
=
0
;
i
<
size
;
i
++)
{
Object
text
=
parts
[
i
];
if
(!(
text
instanceof
CharSequence
))
{
// Skip, but erase this boundary.
if
(
text
instanceof
Element
)
{
Element
te
=
(
Element
)
text
;
if
(!
te
.
isEmpty
())
{
result
.
addText
(
te
.
getFlatText
());
}
}
merge
=
true
;
continue
;
}
if
(
merge
)
{
// Merge w/ previous token.
result
.
addText
((
CharSequence
)
text
);
merge
=
false
;
}
else
{
result
.
add
(
text
);
}
}
if
(
result
.
size
()
==
1
)
{
return
(
CharSequence
)
result
.
parts
[
0
];
}
else
{
return
result
.
getText
();
}
}
/** Return true if all sub-elements are of type CharSequence. */
public
boolean
isText
()
{
for
(
int
i
=
0
;
i
<
size
;
i
++)
{
if
(!(
parts
[
i
]
instanceof
CharSequence
))
{
return
false
;
}
}
return
true
;
}
/** Return true if at least one sub-element is of type CharSequence. */
public
boolean
hasText
()
{
for
(
int
i
=
0
;
i
<
size
;
i
++)
{
if
(
parts
[
i
]
instanceof
CharSequence
)
{
return
true
;
}
}
return
false
;
}
/** Raise a ClassCastException if !isText. */
public
void
checkTextOnly
()
{
for
(
int
i
=
0
;
i
<
size
;
i
++)
{
((
CharSequence
)
parts
[
i
]).
getClass
();
}
}
/** Clears out all sub-elements, and replaces them by the given text.
* A ClassCastException is raised if there are non-character sub-elements,
* either before or after the change.
*/
public
void
setText
(
CharSequence
text
)
{
checkTextOnly
();
clear
();
if
(
text
instanceof
TokenList
)
{
// TL's contain only strings
addAll
(
0
,
(
TokenList
)
text
);
}
else
{
add
(
text
);
}
}
/** Add text at the given position, merging with any previous
* text element, but preserving token boundaries where possible.
* <p>
* In all cases, the new value of getText() is the string
* concatenation of the old value of getText() plus the new text.
* <p>
* The total effect is to concatenate the given text to any
* pre-existing text, and to do so efficiently even if there
* are many such concatenations. Also, getText calls which
* return multiple tokens (in a TokenList) are respected.
* For example, if x is empty, x.addText(y.getText()) puts
* an exact structural copy of y's text into x.
* <p>
* Internal token boundaries in the original text, and in the new
* text (i.e., if it is a TokenList), are preserved. However,
* at the point where new text joins old text, a StringBuffer
* or new String may be created to join the last old and first
* new token.
* <p>
* If the given text is a TokenList, add the tokens as
* separate sub-elements, possibly merging the first token to
* a previous text item (to avoid making a new token boundary).
* <p>
* If the element preceding position i is a StringBuffer,
* append the first new token to it.
* <p>
* If the preceding element is a CharSequence, replace it by a
* StringBuffer containing both its and the first new token.
* <p>
* If tokens are added after a StringBuffer, freeze it into a String.
* <p>
* Every token not merged into a previous CharSequence is added
* as a new sub-element, starting at position i.
* <p>
* Returns the number of elements added, which is useful
* for further calls to addText. This number is zero
* if the input string was null, or was successfully
* merged into a StringBuffer at position i-1.
* <p>
* By contrast, calling add(text) always adds a new sub-element.
* In that case, if there is a previous string, a separating
* space is virtually present also, and will be observed if
* getText() is used to return all the text together.
*/
public
int
addText
(
int
i
,
CharSequence
text
)
{
if
(
text
instanceof
String
)
{
return
addText
(
i
,
(
String
)
text
);
}
else
if
(
text
instanceof
TokenList
)
{
// Text is a list of tokens.
TokenList
tl
=
(
TokenList
)
text
;
int
tlsize
=
tl
.
size
();
if
(
tlsize
==
0
)
{
return
0
;
}
String
token0
=
tl
.
get
(
0
).
toString
();
if
(
tlsize
==
1
)
{
return
addText
(
i
,
token0
);
}
if
(
mergeWithPrev
(
i
,
token0
,
false
))
{
// Add the n-1 remaining tokens.
addAll
(
i
,
tl
.
subList
(
1
,
tlsize
));
return
tlsize
-
1
;
}
else
{
addAll
(
i
,
(
Collection
)
tl
);
return
tlsize
;
}
}
else
{
return
addText
(
i
,
text
.
toString
());
}
}
public
int
addText
(
CharSequence
text
)
{
return
addText
(
size
,
text
);
}
private
// no reason to make this helper public
int
addText
(
int
i
,
String
text
)
{
if
(
text
.
length
()
==
0
)
{
return
0
;
// Trivial success.
}
if
(
mergeWithPrev
(
i
,
text
,
true
))
{
return
0
;
// Merged with previous token.
}
// No previous token.
add
(
i
,
text
);
return
1
;
}
// Tries to merge token with previous contents.
// Returns true if token is successfully disposed of.
// If keepSB is false, any previous StringBuffer is frozen.
// If keepSB is true, a StringBuffer may be created to hold
// the merged token.
private
boolean
mergeWithPrev
(
int
i
,
String
token
,
boolean
keepSB
)
{
if
(
i
==
0
)
// Trivial success if the token is length zero.
{
return
(
token
.
length
()
==
0
);
}
Object
prev
=
parts
[
i
-
1
];
if
(
prev
instanceof
StringBuffer
)
{
StringBuffer
psb
=
(
StringBuffer
)
prev
;
psb
.
append
(
token
);
if
(!
keepSB
)
{
parts
[
i
-
1
]
=
psb
.
toString
();
}
return
true
;
}
if
(
token
.
length
()
==
0
)
{
return
true
;
// Trivial success.
}
if
(
prev
instanceof
CharSequence
)
{
// Must concatenate.
StringBuffer
psb
=
new
StringBuffer
(
prev
.
toString
());
psb
.
append
(
token
);
if
(
keepSB
)
{
parts
[
i
-
1
]
=
psb
;
}
else
{
parts
[
i
-
1
]
=
psb
.
toString
();
}
return
true
;
}
return
false
;
}
/** Trim all strings, using String.trim().
* Remove empty strings.
* Normalize CharSequences to Strings.
*/
public
void
trimText
()
{
checkNotFrozen
();
int
fillp
=
0
;
int
size
=
this
.
size
;
Object
[]
parts
=
this
.
parts
;
for
(
int
i
=
0
;
i
<
size
;
i
++)
{
Object
e
=
parts
[
i
];
if
(
e
instanceof
CharSequence
)
{
String
tt
=
e
.
toString
().
trim
();
if
(
tt
.
length
()
==
0
)
{
continue
;
}
e
=
tt
;
}
parts
[
fillp
++]
=
e
;
}
while
(
size
>
fillp
)
{
parts
[--
size
]
=
null
;
}
this
.
size
=
fillp
;
}
/** Add one or more subelements at the given position.
* If the object reference is null, nothing happens.
* If the object is an anonymous Element, addAll is called.
* If the object is a TokenList, addAll is called (to add the tokens).
* Otherwise, add is called, adding a single subelement or string.
* The net effect is to add zero or more tokens.
* The returned value is the number of added elements.
* <p>
* Note that getText() can return a TokenList which preserves
* token boundaries in the text source. Such a text will be
* added as multiple text sub-elements.
* <p>
* If a text string is added adjacent to an immediately
* preceding string, there will be a token boundary between
* the strings, which will print as an extra space.
*/
public
int
addContent
(
int
i
,
Object
e
)
{
if
(
e
==
null
)
{
return
0
;
}
else
if
(
e
instanceof
TokenList
)
{
return
addAll
(
i
,
(
Collection
)
e
);
}
else
if
(
e
instanceof
Element
&&
((
Element
)
e
).
isAnonymous
())
{
return
addAll
(
i
,
(
Element
)
e
);
}
else
{
add
(
i
,
e
);
return
1
;
}
}
public
int
addContent
(
Object
e
)
{
return
addContent
(
size
,
e
);
}
public
Object
[]
toArray
()
{
Object
[]
result
=
new
Object
[
size
];
System
.
arraycopy
(
parts
,
0
,
result
,
0
,
size
);
return
result
;
}
public
Element
copyContentOnly
()
{
Element
content
=
new
Element
(
size
);
System
.
arraycopy
(
parts
,
0
,
content
.
parts
,
0
,
size
);
content
.
size
=
size
;
return
content
;
}
public
void
sort
(
Comparator
<
Object
>
c
)
{
Arrays
.
sort
(
parts
,
0
,
size
,
c
);
}
public
void
sort
()
{
sort
(
CONTENT_ORDER
);
}
/** Equivalent to Collections.reverse(this.asList()). */
public
void
reverse
()
{
for
(
int
i
=
0
,
mid
=
size
>>
1
,
j
=
size
-
1
;
i
<
mid
;
i
++,
j
--)
{
Object
p
=
parts
[
i
];
parts
[
i
]
=
parts
[
j
];
parts
[
j
]
=
p
;
}
}
/** Equivalent to Collections.shuffle(this.asList() [, rnd]). */
public
void
shuffle
()
{
Collections
.
shuffle
(
this
.
asList
());
}
public
void
shuffle
(
Random
rnd
)
{
Collections
.
shuffle
(
this
.
asList
(),
rnd
);
}
/** Equivalent to Collections.rotate(this.asList(), dist). */
public
void
rotate
(
int
dist
)
{
Collections
.
rotate
(
this
.
asList
(),
dist
);
}
/** Equivalent to Collections.min(this.asList(), c). */
public
Object
min
(
Comparator
<
Object
>
c
)
{
return
Collections
.
min
(
this
.
asList
(),
c
);
}
public
Object
min
()
{
return
min
(
CONTENT_ORDER
);
}
/** Equivalent to Collections.max(this.asList(), c). */
public
Object
max
(
Comparator
<
Object
>
c
)
{
return
Collections
.
max
(
this
.
asList
(),
c
);
}
public
Object
max
()
{
return
max
(
CONTENT_ORDER
);
}
public
int
addAll
(
int
i
,
Collection
c
)
{
if
(
c
instanceof
LView
)
{
return
addAll
(
i
,
((
LView
)
c
).
asElement
());
}
else
{
int
csize
=
c
.
size
();
if
(
csize
==
0
)
{
return
0
;
}
openOrExpand
(
i
,
csize
);
int
fill
=
i
;
for
(
Object
part
:
c
)
{
parts
[
fill
++]
=
part
;
}
return
csize
;
}
}
public
int
addAll
(
int
i
,
Element
e
)
{
int
esize
=
e
.
size
;
if
(
esize
==
0
)
{
return
0
;
}
openOrExpand
(
i
,
esize
);
System
.
arraycopy
(
e
.
parts
,
0
,
parts
,
i
,
esize
);
return
esize
;
}
public
int
addAll
(
Collection
c
)
{
return
addAll
(
size
,
c
);
}
public
int
addAll
(
Element
e
)
{
return
addAll
(
size
,
e
);
}
public
int
addAllAttrsFrom
(
Element
e
)
{
int
added
=
0
;
for
(
int
k
=
0
;
e
.
containsAttr
(
k
);
k
++)
{
String
old
=
setAttr
(
e
.
getAttrName
(
k
),
e
.
getAttr
(
k
));
if
(
old
==
null
)
{
added
+=
1
;
}
}
// Return number of added (not merely changed) attrs.
return
added
;
}
// Search.
public
boolean
matches
(
Filter
f
)
{
return
f
.
filter
(
this
)
!=
null
;
}
public
Object
find
(
Filter
f
)
{
return
findOrRemove
(
f
,
0
,
false
);
}
public
Object
find
(
Filter
f
,
int
fromIndex
)
{
if
(
fromIndex
<
0
)
{
fromIndex
=
0
;
}
return
findOrRemove
(
f
,
fromIndex
,
false
);
}
/** Find the last element matching the given filter.
* Return the filtered value.
*/
public
Object
findLast
(
Filter
f
)
{
return
findOrRemoveLast
(
f
,
size
-
1
,
false
);
}
public
Object
findLast
(
Filter
f
,
int
fromIndex
)
{
if
(
fromIndex
>=
size
)
{
fromIndex
=
size
-
1
;
}
return
findOrRemoveLast
(
f
,
fromIndex
,
false
);
}
/** Find all elements matching the given filter.
* If there is a non-null collection given as a sink,
* transfer matching elements to the given collection.
* The int result is the number of matching elements.
* If there is a null sink given, the matching elements are
* not collected. If there is no sink given, the matching
* elements are returned in an anonymous container element.
* In no case is the receiver element changed.
* <p>
* Note that a simple count of matching elements can be
* obtained by passing a null collection argument.
*/
public
Element
findAll
(
Filter
f
)
{
Element
result
=
new
Element
();
findOrRemoveAll
(
f
,
false
,
0
,
size
,
result
.
asList
(),
false
);
return
result
;
}
public
Element
findAll
(
Filter
f
,
int
fromIndex
,
int
toIndex
)
{
Element
result
=
new
Element
(
name
);
findOrRemoveAll
(
f
,
false
,
fromIndex
,
toIndex
,
result
.
asList
(),
false
);
return
result
;
}
public
int
findAll
(
Filter
f
,
Collection
<
Object
>
sink
)
{
return
findOrRemoveAll
(
f
,
false
,
0
,
size
,
sink
,
false
);
}
public
int
findAll
(
Filter
f
,
int
fromIndex
,
int
toIndex
,
Collection
<
Object
>
sink
)
{
return
findOrRemoveAll
(
f
,
false
,
fromIndex
,
toIndex
,
sink
,
false
);
}
/// Driver routines.
private
Object
findOrRemove
(
Filter
f
,
int
fromIndex
,
boolean
remove
)
{
for
(
int
i
=
fromIndex
;
i
<
size
;
i
++)
{
Object
x
=
f
.
filter
(
parts
[
i
]);
if
(
x
!=
null
)
{
if
(
remove
)
{
close
(
i
,
1
);
}
return
x
;
}
}
return
null
;
}
private
Object
findOrRemoveLast
(
Filter
f
,
int
fromIndex
,
boolean
remove
)
{
for
(
int
i
=
fromIndex
;
i
>=
0
;
i
--)
{
Object
x
=
f
.
filter
(
parts
[
i
]);
if
(
x
!=
null
)
{
if
(
remove
)
{
close
(
i
,
1
);
}
return
x
;
}
}
return
null
;
}
private
int
findOrRemoveAll
(
Filter
f
,
boolean
fInvert
,
int
fromIndex
,
int
toIndex
,
Collection
<
Object
>
sink
,
boolean
remove
)
{
if
(
fromIndex
<
0
)
{
badIndex
(
fromIndex
);
}
if
(
toIndex
>
size
)
{
badIndex
(
toIndex
);
}
int
found
=
0
;
for
(
int
i
=
fromIndex
;
i
<
toIndex
;
i
++)
{
Object
p
=
parts
[
i
];
Object
x
=
f
.
filter
(
p
);
if
(
fInvert
?
(
x
==
null
)
:
(
x
!=
null
))
{
if
(
remove
)
{
close
(
i
--,
1
);
toIndex
--;
}
found
+=
XMLKit
.
addContent
(
fInvert
?
p
:
x
,
sink
);
}
}
return
found
;
}
public
void
replaceAll
(
Filter
f
)
{
XMLKit
.
replaceAll
(
f
,
this
.
asList
());
}
public
void
replaceAll
(
Filter
f
,
int
fromIndex
,
int
toIndex
)
{
XMLKit
.
replaceAll
(
f
,
this
.
asList
().
subList
(
fromIndex
,
toIndex
));
}
/// Recursive walks.
// findAllInTree(f) == findAll(findInTree(f,S)), S.toElement
// findAllInTree(f,S) == findAll(findInTree(content(f,S)))
// removeAllInTree(f) == replaceAll(replaceInTree(and(f,emptyF)))
// removeAllInTree(f,S) == replaceAll(replaceInTree(and(content(f,S),emptyF)))
// retainAllInTree(f) == removeAllInTree(not(f))
// replaceAllInTree(f) == replaceAll(replaceInTree(f))
public
Element
findAllInTree
(
Filter
f
)
{
Element
result
=
new
Element
();
findAllInTree
(
f
,
result
.
asList
());
return
result
;
}
public
int
findAllInTree
(
Filter
f
,
Collection
<
Object
>
sink
)
{
int
found
=
0
;
int
size
=
this
.
size
;
// cache copy
for
(
int
i
=
0
;
i
<
size
;
i
++)
{
Object
p
=
parts
[
i
];
Object
x
=
f
.
filter
(
p
);
if
(
x
!=
null
)
{
found
+=
XMLKit
.
addContent
(
x
,
sink
);
}
else
if
(
p
instanceof
Element
)
{
found
+=
((
Element
)
p
).
findAllInTree
(
f
,
sink
);
}
}
return
found
;
}
public
int
countAllInTree
(
Filter
f
)
{
return
findAllInTree
(
f
,
null
);
}
public
int
removeAllInTree
(
Filter
f
,
Collection
<
Object
>
sink
)
{
if
(
sink
==
null
)
{
sink
=
newCounterColl
();
}
replaceAll
(
replaceInTree
(
and
(
content
(
f
,
sink
),
emptyFilter
())));
return
sink
.
size
();
}
public
Element
removeAllInTree
(
Filter
f
)
{
Element
result
=
new
Element
();
removeAllInTree
(
f
,
result
.
asList
());
return
result
;
}
public
int
retainAllInTree
(
Filter
f
,
Collection
<
Object
>
sink
)
{
return
removeAllInTree
(
not
(
f
),
sink
);
}
public
Element
retainAllInTree
(
Filter
f
)
{
Element
result
=
new
Element
();
retainAllInTree
(
f
,
result
.
asList
());
return
result
;
}
public
void
replaceAllInTree
(
Filter
f
)
{
replaceAll
(
replaceInTree
(
f
));
}
/** Raise a ClassCastException if any subelements are the wrong type. */
public
void
checkPartsOnly
(
Class
<?>
elementClass
)
{
for
(
int
i
=
0
;
i
<
size
;
i
++)
{
elementClass
.
cast
(
parts
[
i
]).
getClass
();
}
}
/** Return true if all sub-elements are of the given type. */
public
boolean
isPartsOnly
(
Class
<?>
elementClass
)
{
for
(
int
i
=
0
;
i
<
size
;
i
++)
{
if
(!
elementClass
.
isInstance
(
parts
[
i
]))
{
return
false
;
}
}
return
true
;
}
/** Provides an iterable view of this object as a series of elements.
* All sub-elements of this Element must be of type Element.
* A ClassCastException is raised if there are non-Element sub-elements.
*/
public
<
T
>
Iterable
<
T
>
partsOnly
(
Class
<
T
>
elementClass
)
{
checkPartsOnly
(
elementClass
);
return
(
Iterable
<
T
>)
(
Iterable
)
this
;
}
public
Iterable
<
Element
>
elements
()
{
return
partsOnly
(
Element
.
class
);
}
/// Useful shorthands.
// Finding or removing elements w/o regard to their type or content.
public
Element
findElement
()
{
return
(
Element
)
find
(
elementFilter
());
}
public
Element
findAllElements
()
{
return
findAll
(
elementFilter
());
}
public
Element
removeElement
()
{
return
(
Element
)
remove
(
elementFilter
());
}
public
Element
removeAllElements
()
{
return
(
Element
)
removeAll
(
elementFilter
());
}
// Finding or removing by element tag or selected attribute,
// as if by elementFilter(name) or attrFilter(name, value).
// Roughly akin to Common Lisp ASSOC.
public
Element
findElement
(
String
name
)
{
return
(
Element
)
find
(
elementFilter
(
name
));
}
public
Element
removeElement
(
String
name
)
{
return
(
Element
)
remove
(
elementFilter
(
name
));
}
public
Element
findWithAttr
(
String
key
)
{
return
(
Element
)
find
(
attrFilter
(
name
));
}
public
Element
findWithAttr
(
String
key
,
String
value
)
{
return
(
Element
)
find
(
attrFilter
(
name
,
value
));
}
public
Element
removeWithAttr
(
String
key
)
{
return
(
Element
)
remove
(
attrFilter
(
name
));
}
public
Element
removeWithAttr
(
String
key
,
String
value
)
{
return
(
Element
)
remove
(
attrFilter
(
name
,
value
));
}
public
Element
findAllElements
(
String
name
)
{
return
findAll
(
elementFilter
(
name
));
}
public
Element
removeAllElements
(
String
name
)
{
return
removeAll
(
elementFilter
(
name
));
}
public
Element
retainAllElements
(
String
name
)
{
return
retainAll
(
elementFilter
(
name
));
}
public
Element
findAllWithAttr
(
String
key
)
{
return
findAll
(
attrFilter
(
key
));
}
public
Element
removeAllWithAttr
(
String
key
)
{
return
removeAll
(
attrFilter
(
key
));
}
public
Element
retainAllWithAttr
(
String
key
)
{
return
retainAll
(
attrFilter
(
key
));
}
public
Element
findAllWithAttr
(
String
key
,
String
value
)
{
return
findAll
(
attrFilter
(
key
,
value
));
}
public
Element
removeAllWithAttr
(
String
key
,
String
value
)
{
return
removeAll
(
attrFilter
(
key
,
value
));
}
public
Element
retainAllWithAttr
(
String
key
,
String
value
)
{
return
retainAll
(
attrFilter
(
key
,
value
));
}
public
int
countAll
(
Filter
f
)
{
return
findAll
(
f
,
null
);
}
public
int
countAllElements
()
{
return
countAll
(
elementFilter
());
}
public
int
countAllElements
(
String
name
)
{
return
countAll
(
elementFilter
(
name
));
}
public
int
countAllWithAttr
(
String
key
)
{
return
countAll
(
attrFilter
(
name
));
}
public
int
countAllWithAttr
(
String
key
,
String
value
)
{
return
countAll
(
attrFilter
(
key
,
value
));
}
public
int
indexOf
(
Object
e
)
{
for
(
int
i
=
0
;
i
<
size
;
i
++)
{
if
(
e
.
equals
(
parts
[
i
]))
{
return
i
;
}
}
return
-
1
;
}
public
int
lastIndexOf
(
Object
e
)
{
for
(
int
i
=
size
-
1
;
i
>=
0
;
i
--)
{
if
(
e
.
equals
(
parts
[
i
]))
{
return
i
;
}
}
return
-
1
;
}
/** Remove the first element matching the given filter.
* Return the filtered value.
*/
public
int
indexOf
(
Filter
f
)
{
return
indexOf
(
f
,
0
);
}
public
int
indexOf
(
Filter
f
,
int
fromIndex
)
{
if
(
fromIndex
<
0
)
{
fromIndex
=
0
;
}
for
(
int
i
=
fromIndex
;
i
<
size
;
i
++)
{
Object
x
=
f
.
filter
(
parts
[
i
]);
if
(
x
!=
null
)
{
return
i
;
}
}
return
-
1
;
}
/** Remove the last element matching the given filter.
* Return the filtered value.
*/
public
int
lastIndexOf
(
Filter
f
)
{
return
lastIndexOf
(
f
,
size
-
1
);
}
public
int
lastIndexOf
(
Filter
f
,
int
fromIndex
)
{
if
(
fromIndex
>=
size
)
{
fromIndex
=
size
-
1
;
}
for
(
int
i
=
fromIndex
;
i
>=
0
;
i
--)
{
Object
x
=
f
.
filter
(
parts
[
i
]);
if
(
x
!=
null
)
{
return
i
;
}
}
return
-
1
;
}
public
boolean
contains
(
Object
e
)
{
return
indexOf
(
e
)
>=
0
;
}
// attributes
private
int
findOrCreateAttr
(
String
key
,
boolean
create
)
{
key
.
toString
();
// null check
int
attrBase
=
parts
.
length
;
for
(
int
i
=
parts
.
length
-
2
;
i
>=
size
;
i
-=
2
)
{
String
akey
=
(
String
)
parts
[
i
+
0
];
if
(
akey
==
null
)
{
if
(!
create
)
{
return
-
1
;
}
if
(
i
==
size
)
{
break
;
// NEED_SLOP
}
parts
[
i
+
0
]
=
key
;
//parts[i+1] = ""; //caller responsibility
return
i
;
}
attrBase
=
i
;
if
(
akey
.
equals
(
key
))
{
return
i
;
}
}
// If we fell through, we ran into an element part.
// Therefore we have run out of empty slots.
if
(!
create
)
{
return
-
1
;
}
assert
(!
isFrozen
());
int
alen
=
parts
.
length
-
attrBase
;
expand
(
size
,
2
);
// generally expands by more than 2
// since there was a reallocation, the garbage slots are really null
assert
(
parts
[
size
+
0
]
==
null
&&
parts
[
size
+
1
]
==
null
);
alen
+=
2
;
int
i
=
parts
.
length
-
alen
;
parts
[
i
+
0
]
=
key
;
//parts[i+1] = ""; //caller responsibility
return
i
;
}
public
int
attrSize
()
{
return
attrLength
()
>>>
1
;
}
public
int
indexOfAttr
(
String
key
)
{
return
findOrCreateAttr
(
key
,
false
);
}
public
boolean
containsAttr
(
String
key
)
{
return
indexOfAttr
(
key
)
>=
0
;
}
public
String
getAttr
(
String
key
)
{
return
getAttr
(
key
,
null
);
}
public
String
getAttr
(
String
key
,
String
dflt
)
{
int
i
=
findOrCreateAttr
(
key
,
false
);
return
(
i
<
0
)
?
dflt
:
(
String
)
parts
[
i
+
1
];
}
public
TokenList
getAttrList
(
String
key
)
{
return
convertToList
(
getAttr
(
key
));
}
public
Number
getAttrNumber
(
String
key
)
{
return
convertToNumber
(
getAttr
(
key
));
}
public
long
getAttrLong
(
String
key
)
{
return
getAttrLong
(
key
,
0
);
}
public
double
getAttrDouble
(
String
key
)
{
return
getAttrDouble
(
key
,
0.0
);
}
public
long
getAttrLong
(
String
key
,
long
dflt
)
{
return
convertToLong
(
getAttr
(
key
),
dflt
);
}
public
double
getAttrDouble
(
String
key
,
double
dflt
)
{
return
convertToDouble
(
getAttr
(
key
),
dflt
);
}
int
indexAttr
(
int
k
)
{
int
i
=
parts
.
length
-
(
k
*
2
)
-
2
;
if
(
i
<
size
||
parts
[
i
]
==
null
)
{
return
-
2
;
// always oob
}
return
i
;
}
public
boolean
containsAttr
(
int
k
)
{
return
indexAttr
(
k
)
>=
0
;
}
public
String
getAttr
(
int
k
)
{
return
(
String
)
parts
[
indexAttr
(
k
)
+
1
];
}
public
String
getAttrName
(
int
k
)
{
return
(
String
)
parts
[
indexAttr
(
k
)
+
0
];
}
public
Iterable
<
String
>
attrNames
()
{
//return asAttrMap().keySet();
return
new
Iterable
<
String
>()
{
public
Iterator
<
String
>
iterator
()
{
return
new
ANItr
();
}
};
}
// Hand-inlined replacement for asAttrMap().keySet().iterator():
class
ANItr
implements
Iterator
<
String
>
{
boolean
lastRet
;
int
cursor
=
-
2
;
// pointer from end of parts
public
boolean
hasNext
()
{
int
i
=
cursor
+
parts
.
length
;
return
i
>=
size
&&
parts
[
i
]
==
null
;
}
public
String
next
()
{
int
i
=
cursor
+
parts
.
length
;
Object
x
;
if
(
i
<
size
||
(
x
=
parts
[
i
])
==
null
)
{
nsee
();
return
null
;
}
cursor
-=
2
;
lastRet
=
true
;
return
(
String
)
x
;
}
public
void
remove
()
{
if
(!
lastRet
)
{
throw
new
IllegalStateException
();
}
Element
.
this
.
removeAttr
((-
4
-
cursor
)
/
2
);
cursor
+=
2
;
lastRet
=
false
;
}
Exception
nsee
()
{
throw
new
NoSuchElementException
(
"attribute "
+
(-
2
-
cursor
)
/
2
);
}
}
/** Return an anonymous copy of self, but only with attributes.
*/
public
Element
copyAttrsOnly
()
{
int
alen
=
attrLength
();
Element
attrs
=
new
Element
(
alen
);
Object
[]
attrParts
=
attrs
.
parts
;
assert
(
attrParts
.
length
==
NEED_SLOP
+
alen
);
System
.
arraycopy
(
parts
,
parts
.
length
-
alen
,
attrParts
,
NEED_SLOP
,
alen
);
return
attrs
;
}
/** Get all attributes, represented as an element with sub-elements.
* The name of each sub-element is the attribute key, and the text
* This is a fresh copy, and can be updated with affecting the original.
* of each sub-element is the corresponding attribute value.
* See also asAttrMap() for a "live" view of all the attributes as a Map.
*/
public
Element
getAttrs
()
{
int
asize
=
attrSize
();
Element
attrs
=
new
Element
(
ANON_NAME
,
asize
,
NEED_SLOP
+
asize
);
for
(
int
i
=
0
;
i
<
asize
;
i
++)
{
Element
attr
=
new
Element
(
getAttrName
(
i
),
1
,
NEED_SLOP
+
1
);
// %%% normalize attrs to token lists?
attr
.
setRaw
(
0
,
getAttr
(
i
));
attrs
.
setRaw
(
i
,
attr
);
}
return
attrs
;
}
public
void
setAttrs
(
Element
attrs
)
{
int
alen
=
attrLength
();
clearParts
(
parts
.
length
-
alen
,
alen
);
if
(!
hasNulls
(
NEED_SLOP
+
attrs
.
size
*
2
))
{
expand
(
size
,
attrs
.
size
*
2
);
}
addAttrs
(
attrs
);
}
public
void
addAttrs
(
Element
attrs
)
{
for
(
int
i
=
0
;
i
<
attrs
.
size
;
i
++)
{
Element
attr
=
(
Element
)
attrs
.
get
(
i
);
setAttr
(
attr
.
name
,
attr
.
getText
().
toString
());
}
}
public
void
removeAttr
(
int
i
)
{
checkNotFrozen
();
while
((
i
-=
2
)
>=
size
)
{
Object
k
=
parts
[
i
+
0
];
Object
v
=
parts
[
i
+
1
];
if
(
k
==
null
)
{
break
;
}
parts
[
i
+
2
]
=
k
;
parts
[
i
+
3
]
=
v
;
}
parts
[
i
+
2
]
=
null
;
parts
[
i
+
3
]
=
null
;
}
public
void
clearAttrs
()
{
if
(
parts
.
length
==
0
||
parts
[
parts
.
length
-
1
]
==
null
)
{
return
;
// no attrs to clear
}
checkNotFrozen
();
if
(
size
==
0
)
{
// If no elements, free the parts array.
parts
=
noPartsNotFrozen
;
return
;
}
for
(
int
i
=
parts
.
length
-
1
;
parts
[
i
]
!=
null
;
i
--)
{
assert
(
i
>=
size
);
parts
[
i
]
=
null
;
}
}
public
String
setAttr
(
String
key
,
String
value
)
{
String
old
;
if
(
value
==
null
)
{
int
i
=
findOrCreateAttr
(
key
,
false
);
if
(
i
>=
0
)
{
old
=
(
String
)
parts
[
i
+
1
];
removeAttr
(
i
);
}
else
{
old
=
null
;
}
}
else
{
checkNotFrozen
();
int
i
=
findOrCreateAttr
(
key
,
true
);
old
=
(
String
)
parts
[
i
+
1
];
parts
[
i
+
1
]
=
value
;
}
return
old
;
}
public
String
setAttrList
(
String
key
,
List
<
String
>
l
)
{
if
(
l
==
null
)
{
return
setAttr
(
key
,
null
);
}
if
(!(
l
instanceof
TokenList
))
{
l
=
new
TokenList
(
l
);
}
return
setAttr
(
key
,
l
.
toString
());
}
public
String
setAttrNumber
(
String
key
,
Number
n
)
{
return
setAttr
(
key
,
(
n
==
null
)
?
null
:
n
.
toString
());
}
public
String
setAttrLong
(
String
key
,
long
n
)
{
return
setAttr
(
key
,
(
n
==
0
)
?
null
:
String
.
valueOf
(
n
));
}
public
String
setAttrDouble
(
String
key
,
double
n
)
{
return
setAttr
(
key
,
(
n
==
0
)
?
null
:
String
.
valueOf
(
n
));
}
public
String
setAttr
(
int
k
,
String
value
)
{
int
i
=
indexAttr
(
k
);
String
old
=
(
String
)
parts
[
i
+
1
];
if
(
value
==
null
)
{
removeAttr
(
i
);
}
else
{
checkNotFrozen
();
parts
[
i
+
1
]
=
value
;
}
return
old
;
}
int
attrLength
()
{
return
parts
.
length
-
attrBase
();
}
/** Are the attributes of the two two elements equal?
* Disregards name, sub-elements, and ordering of attributes.
*/
public
boolean
equalAttrs
(
Element
that
)
{
int
alen
=
this
.
attrLength
();
if
(
alen
!=
that
.
attrLength
())
{
return
false
;
}
if
(
alen
==
0
)
{
return
true
;
}
return
compareAttrs
(
alen
,
that
,
alen
,
false
)
==
0
;
}
private
int
compareAttrs
(
int
thisAlen
,
Element
that
,
int
thatAlen
,
boolean
fullCompare
)
{
Object
[]
thisParts
=
this
.
parts
;
Object
[]
thatParts
=
that
.
parts
;
int
thisBase
=
thisParts
.
length
-
thisAlen
;
int
thatBase
=
thatParts
.
length
-
thatAlen
;
// search indexes into unmatched parts of this.attrs:
int
firstI
=
0
;
// search indexes into unmatched parts of that.attrs:
int
firstJ
=
0
;
int
lastJ
=
thatAlen
-
2
;
// try to find the mismatch with the first key:
String
firstKey
=
null
;
int
firstKeyValCmp
=
0
;
int
foundKeys
=
0
;
for
(
int
i
=
0
;
i
<
thisAlen
;
i
+=
2
)
{
String
key
=
(
String
)
thisParts
[
thisBase
+
i
+
0
];
String
val
=
(
String
)
thisParts
[
thisBase
+
i
+
1
];
String
otherVal
=
null
;
for
(
int
j
=
firstJ
;
j
<=
lastJ
;
j
+=
2
)
{
if
(
key
.
equals
(
thatParts
[
thatBase
+
j
+
0
]))
{
foundKeys
+=
1
;
otherVal
=
(
String
)
thatParts
[
thatBase
+
j
+
1
];
// Optimization: Narrow subsequent searches when easy.
if
(
j
==
lastJ
)
{
lastJ
-=
2
;
}
else
if
(
j
==
firstJ
)
{
firstJ
+=
2
;
}
if
(
i
==
firstI
)
{
firstI
+=
2
;
}
break
;
}
}
int
valCmp
;
if
(
otherVal
!=
null
)
{
// The key was found.
if
(!
fullCompare
)
{
if
(!
val
.
equals
(
otherVal
))
{
return
1
-
0
;
//arb.
}
continue
;
}
valCmp
=
val
.
compareTo
(
otherVal
);
}
else
{
// Found the key in this but not that.
// Such a mismatch puts the guy missing the key last.
valCmp
=
0
-
1
;
}
if
(
valCmp
!=
0
)
{
// found a mismatch, key present in both elems
if
(
firstKey
==
null
||
firstKey
.
compareTo
(
key
)
>
0
)
{
// found a better key
firstKey
=
key
;
firstKeyValCmp
=
valCmp
;
}
}
}
// We have located the first mismatch of all keys in this.attrs.
// In general we must also look for keys in that.attrs but missing
// from this.attrs; such missing keys, if earlier than firstKey,
// rule the comparison.
// We can sometimes prove quickly there is no missing key.
if
(
foundKeys
==
thatAlen
/
2
)
{
// Exhausted all keys in that.attrs.
return
firstKeyValCmp
;
}
// Search for a missing key in that.attrs earlier than firstKey.
findMissingKey:
for
(
int
j
=
firstJ
;
j
<=
lastJ
;
j
+=
2
)
{
String
otherKey
=
(
String
)
thatParts
[
thatBase
+
j
+
0
];
if
(
firstKey
==
null
||
firstKey
.
compareTo
(
otherKey
)
>
0
)
{
// Found a better key; is it missing?
for
(
int
i
=
firstI
;
i
<
thisAlen
;
i
+=
2
)
{
if
(
otherKey
.
equals
(
thisParts
[
thisBase
+
i
+
0
]))
{
continue
findMissingKey
;
}
}
// If we get here, there was no match in this.attrs.
return
1
-
0
;
}
}
// No missing key. Previous comparison value rules.
return
firstKeyValCmp
;
}
// Binary search looking for first non-null after size.
int
attrBase
()
{
// Smallest & largest possible attribute indexes:
int
kmin
=
0
;
int
kmax
=
(
parts
.
length
-
size
)
>>>
1
;
// earlist possible attribute position:
int
abase
=
parts
.
length
-
(
kmax
*
2
);
// binary search using scaled indexes:
while
(
kmin
!=
kmax
)
{
int
kmid
=
kmin
+
((
kmax
-
kmin
)
>>>
1
);
if
(
parts
[
abase
+
(
kmid
*
2
)]
==
null
)
{
kmin
=
kmid
+
1
;
}
else
{
kmax
=
kmid
;
}
assert
(
kmin
<=
kmax
);
}
return
abase
+
(
kmax
*
2
);
}
/** Sort attributes by name. */
public
void
sortAttrs
()
{
checkNotFrozen
();
int
abase
=
attrBase
();
int
alen
=
parts
.
length
-
abase
;
String
[]
buf
=
new
String
[
alen
];
// collect keys
for
(
int
k
=
0
;
k
<
alen
/
2
;
k
++)
{
String
akey
=
(
String
)
parts
[
abase
+
(
k
*
2
)
+
0
];
buf
[
k
]
=
akey
;
}
Arrays
.
sort
(
buf
,
0
,
alen
/
2
);
// collect values
for
(
int
k
=
0
;
k
<
alen
/
2
;
k
++)
{
String
akey
=
buf
[
k
];
buf
[
k
+
alen
/
2
]
=
getAttr
(
akey
);
}
// reorder keys and values
int
fillp
=
parts
.
length
;
for
(
int
k
=
0
;
k
<
alen
/
2
;
k
++)
{
String
akey
=
buf
[
k
];
String
aval
=
buf
[
k
+
alen
/
2
];
fillp
-=
2
;
parts
[
fillp
+
0
]
=
akey
;
parts
[
fillp
+
1
]
=
aval
;
}
assert
(
fillp
==
abase
);
}
/*
Notes on whitespace and tokenization.
On input, never split CDATA blocks. They remain single tokens.
?Try to treat encoded characters as CDATA-quoted, also?
Internally, each String sub-element is logically a token.
However, if there was no token-splitting on input,
consecutive strings are merged by the parser.
Internally, we need addToken (intervening blank) and addText
(hard concatenation).
Optionally on input, tokenize unquoted text into words.
Between each adjacent word pair, elide either one space
or all space.
On output, we always add spaces between tokens.
The Element("a", {"b", "c", Element("d"), "e f"})
outputs as "<a>b c<d/>e f</a>"
*/
/** Split strings into tokens, using a StringTokenizer. */
public
void
tokenize
(
String
delims
,
boolean
returnDelims
)
{
checkNotFrozen
();
if
(
delims
==
null
)
{
delims
=
WHITESPACE_CHARS
;
// StringTokenizer default
}
for
(
int
i
=
0
;
i
<
size
;
i
++)
{
if
(!(
parts
[
i
]
instanceof
CharSequence
))
{
continue
;
}
int
osize
=
size
;
String
str
=
parts
[
i
].
toString
();
StringTokenizer
st
=
new
StringTokenizer
(
str
,
delims
,
returnDelims
);
int
nstrs
=
st
.
countTokens
();
switch
(
nstrs
)
{
case
0
:
close
(
i
--,
1
);
break
;
case
1
:
parts
[
i
]
=
st
.
nextToken
();
break
;
default
:
openOrExpand
(
i
+
1
,
nstrs
-
1
);
for
(
int
j
=
0
;
j
<
nstrs
;
j
++)
{
parts
[
i
+
j
]
=
st
.
nextToken
();
}
i
+=
nstrs
-
1
;
break
;
}
}
}
public
void
tokenize
(
String
delims
)
{
tokenize
(
delims
,
false
);
}
public
void
tokenize
()
{
tokenize
(
null
,
false
);
}
// views
class
LView
extends
AbstractList
<
Object
>
{
Element
asElement
()
{
return
Element
.
this
;
}
public
int
size
()
{
return
Element
.
this
.
size
();
}
public
Object
get
(
int
i
)
{
return
Element
.
this
.
get
(
i
);
}
@Override
public
boolean
contains
(
Object
e
)
{
return
Element
.
this
.
contains
(
e
);
}
@Override
public
Object
[]
toArray
()
{
return
Element
.
this
.
toArray
();
}
@Override
public
int
indexOf
(
Object
e
)
{
return
Element
.
this
.
indexOf
(
e
);
}
@Override
public
int
lastIndexOf
(
Object
e
)
{
return
Element
.
this
.
lastIndexOf
(
e
);
}
@Override
public
void
add
(
int
i
,
Object
e
)
{
++
modCount
;
Element
.
this
.
add
(
i
,
e
);
}
@Override
public
boolean
addAll
(
int
i
,
Collection
<?
extends
Object
>
c
)
{
++
modCount
;
return
Element
.
this
.
addAll
(
i
,
c
)
>
0
;
}
@Override
public
boolean
addAll
(
Collection
<?
extends
Object
>
c
)
{
++
modCount
;
return
Element
.
this
.
addAll
(
c
)
>
0
;
}
@Override
public
Object
remove
(
int
i
)
{
++
modCount
;
return
Element
.
this
.
remove
(
i
);
}
@Override
public
Object
set
(
int
i
,
Object
e
)
{
++
modCount
;
return
Element
.
this
.
set
(
i
,
e
);
}
@Override
public
void
clear
()
{
++
modCount
;
Element
.
this
.
clear
();
}
// Others: toArray(Object[]), containsAll, removeAll, retainAll
}
/** Produce a list view of sub-elements.
* (The list view does not provide access to the element's
* name or attributes.)
* Changes to this view are immediately reflected in the
* element itself.
*/
public
List
<
Object
>
asList
()
{
return
new
LView
();
}
/** Produce a list iterator on all sub-elements. */
public
ListIterator
<
Object
>
iterator
()
{
//return asList().listIterator();
return
new
Itr
();
}
// Hand-inlined replacement for LView.listIterator():
class
Itr
implements
ListIterator
<
Object
>
{
int
lastRet
=
-
1
;
int
cursor
=
0
;
public
boolean
hasNext
()
{
return
cursor
<
size
;
}
public
boolean
hasPrevious
()
{
return
cursor
>
0
&&
cursor
<=
size
;
}
public
Object
next
()
{
if
(!
hasNext
())
{
nsee
();
}
return
parts
[
lastRet
=
cursor
++];
}
public
Object
previous
()
{
if
(!
hasPrevious
())
{
nsee
();
}
return
parts
[--
cursor
];
}
public
int
nextIndex
()
{
return
cursor
;
}
public
int
previousIndex
()
{
return
cursor
-
1
;
}
public
void
set
(
Object
x
)
{
parts
[
lastRet
]
=
x
;
}
public
void
add
(
Object
x
)
{
lastRet
=
-
1
;
Element
.
this
.
add
(
cursor
++,
x
);
}
public
void
remove
()
{
if
(
lastRet
<
0
)
{
throw
new
IllegalStateException
();
}
Element
.
this
.
remove
(
lastRet
);
if
(
lastRet
<
cursor
)
{
--
cursor
;
}
lastRet
=
-
1
;
}
void
nsee
()
{
throw
new
NoSuchElementException
(
"element "
+
cursor
);
}
}
/** A PrintWriter which always appends as if by addText.
* Use of this stream may insert a StringBuffer at the end
* of the Element. The user must not directly modify this
* StringBuffer, or use it in other data structures.
* From time to time, the StringBuffer may be replaced by a
* constant string as a result of using the PrintWriter.
*/
public
PrintWriter
asWriter
()
{
return
new
ElemW
();
}
class
ElemW
extends
PrintWriter
{
ElemW
()
{
super
(
new
StringWriter
());
}
final
StringBuffer
buf
=
((
StringWriter
)
out
).
getBuffer
();
{
lock
=
buf
;
}
// synchronize on this buffer
@Override
public
void
println
()
{
synchronized
(
buf
)
{
ensureCursor
();
super
.
println
();
}
}
@Override
public
void
write
(
int
ch
)
{
synchronized
(
buf
)
{
ensureCursor
();
//buf.append(ch);
super
.
write
(
ch
);
}
}
@Override
public
void
write
(
char
buf
[],
int
off
,
int
len
)
{
synchronized
(
buf
)
{
ensureCursor
();
super
.
write
(
buf
,
off
,
len
);
}
}
@Override
public
void
write
(
String
s
,
int
off
,
int
len
)
{
synchronized
(
buf
)
{
ensureCursor
();
//buf.append(s.substring(off, off+len));
super
.
write
(
s
,
off
,
len
);
}
}
@Override
public
void
write
(
String
s
)
{
synchronized
(
buf
)
{
ensureCursor
();
//buf.append(s);
super
.
write
(
s
);
}
}
private
void
ensureCursor
()
{
checkNotFrozen
();
if
(
getLast
()
!=
buf
)
{
int
pos
=
indexOf
(
buf
);
if
(
pos
>=
0
)
{
// Freeze the pre-existing use of buf.
setRaw
(
pos
,
buf
.
toString
());
}
add
(
buf
);
}
}
}
/** Produce a map view of attributes, in which the attribute
* name strings are the keys.
* (The map view does not provide access to the element's
* name or sub-elements.)
* Changes to this view are immediately reflected in the
* element itself.
*/
public
Map
<
String
,
String
>
asAttrMap
()
{
class
Entry
implements
Map
.
Entry
<
String
,
String
>
{
final
int
k
;
Entry
(
int
k
)
{
this
.
k
=
k
;
assert
(((
String
)
getKey
()).
toString
()
!=
null
);
// check, fail-fast
}
public
String
getKey
()
{
return
Element
.
this
.
getAttrName
(
k
);
}
public
String
getValue
()
{
return
Element
.
this
.
getAttr
(
k
);
}
public
String
setValue
(
String
v
)
{
return
Element
.
this
.
setAttr
(
k
,
v
.
toString
());
}
@Override
public
boolean
equals
(
Object
o
)
{
if
(!(
o
instanceof
Map
.
Entry
))
{
return
false
;
}
Map
.
Entry
that
=
(
Map
.
Entry
)
o
;
return
(
this
.
getKey
().
equals
(
that
.
getKey
())
&&
this
.
getValue
().
equals
(
that
.
getValue
()));
}
@Override
public
int
hashCode
()
{
return
getKey
().
hashCode
()
^
getValue
().
hashCode
();
}
}
class
EIter
implements
Iterator
<
Map
.
Entry
<
String
,
String
>>
{
int
k
=
0
;
// index of pending next() attribute
public
boolean
hasNext
()
{
return
Element
.
this
.
containsAttr
(
k
);
}
public
Map
.
Entry
<
String
,
String
>
next
()
{
return
new
Entry
(
k
++);
}
public
void
remove
()
{
Element
.
this
.
removeAttr
(--
k
);
}
}
class
ESet
extends
AbstractSet
<
Map
.
Entry
<
String
,
String
>>
{
public
int
size
()
{
return
Element
.
this
.
attrSize
();
}
public
Iterator
<
Map
.
Entry
<
String
,
String
>>
iterator
()
{
return
new
EIter
();
}
@Override
public
void
clear
()
{
Element
.
this
.
clearAttrs
();
}
}
class
AView
extends
AbstractMap
<
String
,
String
>
{
private
transient
Set
<
Map
.
Entry
<
String
,
String
>>
eSet
;
public
Set
<
Map
.
Entry
<
String
,
String
>>
entrySet
()
{
if
(
eSet
==
null
)
{
eSet
=
new
ESet
();
}
return
eSet
;
}
@Override
public
int
size
()
{
return
Element
.
this
.
attrSize
();
}
public
boolean
containsKey
(
String
k
)
{
return
Element
.
this
.
containsAttr
(
k
);
}
public
String
get
(
String
k
)
{
return
Element
.
this
.
getAttr
(
k
);
}
@Override
public
String
put
(
String
k
,
String
v
)
{
return
Element
.
this
.
setAttr
(
k
,
v
.
toString
());
}
public
String
remove
(
String
k
)
{
return
Element
.
this
.
setAttr
(
k
,
null
);
}
}
return
new
AView
();
}
/** Reports number of additional elements this object can accommodate
* without reallocation.
*/
public
int
getExtraCapacity
()
{
int
abase
=
attrBase
();
return
Math
.
max
(
0
,
abase
-
size
-
NEED_SLOP
);
}
/** Ensures that at least the given number of additional elements
* can be added to this object without reallocation.
*/
public
void
ensureExtraCapacity
(
int
cap
)
{
if
(
cap
==
0
||
hasNulls
(
cap
+
NEED_SLOP
))
{
return
;
}
setExtraCapacity
(
cap
);
}
/**
* Trim excess capacity to zero, or do nothing if frozen.
* This minimizes the space occupied by this Element,
* at the expense of a reallocation if sub-elements or attributes
* are added later.
*/
public
void
trimToSize
()
{
if
(
isFrozen
())
{
return
;
}
setExtraCapacity
(
0
);
}
/** Changes the number of additional elements this object can accommodate
* without reallocation.
*/
public
void
setExtraCapacity
(
int
cap
)
{
checkNotFrozen
();
int
abase
=
attrBase
();
int
alen
=
parts
.
length
-
abase
;
// slots allocated for attrs
int
nlen
=
size
+
cap
+
NEED_SLOP
+
alen
;
if
(
nlen
!=
parts
.
length
)
{
Object
[]
nparts
=
new
Object
[
nlen
];
// copy attributes
System
.
arraycopy
(
parts
,
abase
,
nparts
,
nlen
-
alen
,
alen
);
// copy sub-elements
System
.
arraycopy
(
parts
,
0
,
nparts
,
0
,
size
);
parts
=
nparts
;
}
assert
(
cap
==
getExtraCapacity
());
}
// Return true if there are at least len nulls of slop available.
boolean
hasNulls
(
int
len
)
{
if
(
len
==
0
)
{
return
true
;
}
int
lastNull
=
size
+
len
-
1
;
if
(
lastNull
>=
parts
.
length
)
{
return
false
;
}
return
(
parts
[
lastNull
]
==
null
);
}
// Opens up parts array at pos by len spaces.
void
open
(
int
pos
,
int
len
)
{
assert
(
pos
<
size
);
assert
(
hasNulls
(
len
+
NEED_SLOP
));
checkNotFrozen
();
int
nsize
=
size
+
len
;
int
tlen
=
size
-
pos
;
System
.
arraycopy
(
parts
,
pos
,
parts
,
pos
+
len
,
tlen
);
size
=
nsize
;
}
// Reallocate and open up at parts[pos] to at least len empty places.
// Shift anything after pos right by len. Reallocate if necessary.
// If pos < size, caller must fill it in with non-null values.
// Returns incremented size; caller is responsible for storing it
// down, if desired.
int
expand
(
int
pos
,
int
len
)
{
assert
(
pos
<=
size
);
// There must be at least len nulls between elems and attrs.
assert
(!
hasNulls
(
NEED_SLOP
+
len
));
// caller responsibility
checkNotFrozen
();
int
nsize
=
size
+
len
;
// length of all elements
int
tlen
=
size
-
pos
;
// length of elements in post-pos tail
int
abase
=
attrBase
();
int
alen
=
parts
.
length
-
abase
;
// slots allocated for attrs
int
nlen
=
nsize
+
alen
+
NEED_SLOP
;
nlen
+=
(
nlen
>>>
1
);
// add new slop!
Object
[]
nparts
=
new
Object
[
nlen
];
// copy head of sub-elements
System
.
arraycopy
(
parts
,
0
,
nparts
,
0
,
pos
);
// copy tail of sub-elements
System
.
arraycopy
(
parts
,
pos
,
nparts
,
pos
+
len
,
tlen
);
// copy attributes
System
.
arraycopy
(
parts
,
abase
,
nparts
,
nlen
-
alen
,
alen
);
// update self
parts
=
nparts
;
//assert(hasNulls(len)); <- not yet true, since size != nsize
return
nsize
;
}
// Open or expand at the given position, as appropriate.
boolean
openOrExpand
(
int
pos
,
int
len
)
{
if
(
pos
<
0
||
pos
>
size
)
{
badIndex
(
pos
);
}
if
(
hasNulls
(
len
+
NEED_SLOP
))
{
if
(
pos
==
size
)
{
size
+=
len
;
}
else
{
open
(
pos
,
len
);
}
return
false
;
}
else
{
size
=
expand
(
pos
,
len
);
return
true
;
}
}
// Close up at parts[pos] len old places.
// Shift anything after pos left by len.
// Fill unused end of parts with null.
void
close
(
int
pos
,
int
len
)
{
assert
(
len
>
0
);
assert
((
size
-
pos
)
>=
len
);
checkNotFrozen
();
int
tlen
=
(
size
-
pos
)
-
len
;
// length of elements in post-pos tail
int
nsize
=
size
-
len
;
System
.
arraycopy
(
parts
,
pos
+
len
,
parts
,
pos
,
tlen
);
// reinitialize the unoccupied slots to null
clearParts
(
nsize
,
nsize
+
len
);
// update self
size
=
nsize
;
assert
(
hasNulls
(
len
));
}
public
void
writeTo
(
Writer
w
)
throws
IOException
{
new
Printer
(
w
).
print
(
this
);
}
public
void
writePrettyTo
(
Writer
w
)
throws
IOException
{
prettyPrintTo
(
w
,
this
);
}
public
String
prettyString
()
{
StringWriter
sw
=
new
StringWriter
();
try
{
writePrettyTo
(
sw
);
}
catch
(
IOException
ee
)
{
throw
new
Error
(
ee
);
// should not happen
}
return
sw
.
toString
();
}
@Override
public
String
toString
()
{
StringWriter
sw
=
new
StringWriter
();
try
{
writeTo
(
sw
);
}
catch
(
IOException
ee
)
{
throw
new
Error
(
ee
);
// should not happen
}
return
sw
.
toString
();
}
public
String
dump
()
{
// For debugging only. Reveals internal layout.
StringBuilder
buf
=
new
StringBuilder
();
buf
.
append
(
"<"
).
append
(
name
).
append
(
"["
).
append
(
size
).
append
(
"]"
);
for
(
int
i
=
0
;
i
<
parts
.
length
;
i
++)
{
Object
p
=
parts
[
i
];
if
(
p
==
null
)
{
buf
.
append
(
" null"
);
}
else
{
buf
.
append
(
" {"
);
String
cname
=
p
.
getClass
().
getName
();
cname
=
cname
.
substring
(
1
+
cname
.
indexOf
(
'/'
));
cname
=
cname
.
substring
(
1
+
cname
.
indexOf
(
'$'
));
cname
=
cname
.
substring
(
1
+
cname
.
indexOf
(
'#'
));
if
(!
cname
.
equals
(
"String"
))
{
buf
.
append
(
cname
).
append
(
":"
);
}
buf
.
append
(
p
);
buf
.
append
(
"}"
);
}
}
return
buf
.
append
(
">"
).
toString
();
}
public
static
java
.
lang
.
reflect
.
Method
method
(
String
name
)
{
HashMap
allM
=
allMethods
;
if
(
allM
==
null
)
{
allM
=
makeAllMethods
();
}
java
.
lang
.
reflect
.
Method
res
=
(
java
.
lang
.
reflect
.
Method
)
allMethods
.
get
(
name
);
if
(
res
==
null
)
{
throw
new
IllegalArgumentException
(
name
);
}
return
res
;
}
private
static
HashMap
allMethods
;
private
static
synchronized
HashMap
makeAllMethods
()
{
if
(
allMethods
!=
null
)
{
return
allMethods
;
}
java
.
lang
.
reflect
.
Method
[]
methods
=
Element
.
class
.
getMethods
();
HashMap
<
String
,
java
.
lang
.
reflect
.
Method
>
allM
=
new
HashMap
<
String
,
java
.
lang
.
reflect
.
Method
>(),
ambig
=
new
HashMap
<
String
,
java
.
lang
.
reflect
.
Method
>();
for
(
int
i
=
0
;
i
<
methods
.
length
;
i
++)
{
java
.
lang
.
reflect
.
Method
m
=
methods
[
i
];
Class
[]
args
=
m
.
getParameterTypes
();
String
name
=
m
.
getName
();
assert
(
java
.
lang
.
reflect
.
Modifier
.
isPublic
(
m
.
getModifiers
()));
if
(
name
.
startsWith
(
"notify"
))
{
continue
;
}
if
(
name
.
endsWith
(
"Attr"
)
&&
args
.
length
>
0
&&
args
[
0
]
==
int
.
class
)
// ignore getAttr(int), etc.
{
continue
;
}
if
(
name
.
endsWith
(
"All"
)
&&
args
.
length
>
1
&&
args
[
0
]
==
Filter
.
class
)
// ignore findAll(Filter, int...), etc.
{
continue
;
}
java
.
lang
.
reflect
.
Method
pm
=
allM
.
put
(
name
,
m
);
if
(
pm
!=
null
)
{
Class
[]
pargs
=
pm
.
getParameterTypes
();
if
(
pargs
.
length
>
args
.
length
)
{
allM
.
put
(
name
,
pm
);
// put it back
}
else
if
(
pargs
.
length
==
args
.
length
)
{
ambig
.
put
(
name
,
pm
);
// make a note of it
}
}
}
// Delete ambiguous methods.
for
(
Map
.
Entry
<
String
,
java
.
lang
.
reflect
.
Method
>
e
:
ambig
.
entrySet
())
{
String
name
=
e
.
getKey
();
java
.
lang
.
reflect
.
Method
pm
=
e
.
getValue
();
java
.
lang
.
reflect
.
Method
m
=
allM
.
get
(
name
);
Class
[]
args
=
m
.
getParameterTypes
();
Class
[]
pargs
=
pm
.
getParameterTypes
();
if
(
pargs
.
length
==
args
.
length
)
{
//System.out.println("ambig: "+pm);
//System.out.println(" with: "+m);
//ambig: int addAll(int,Element)
// with: int addAll(int,Collection)
allM
.
put
(
name
,
null
);
// get rid of
}
}
//System.out.println("allM: "+allM);
return
allMethods
=
allM
;
}
}
static
Object
fixupString
(
Object
part
)
{
if
(
part
instanceof
CharSequence
&&
!(
part
instanceof
String
))
{
return
part
.
toString
();
}
else
{
return
part
;
}
}
public
static
final
class
Special
implements
Comparable
<
Special
>
{
String
kind
;
Object
value
;
public
Special
(
String
kind
,
Object
value
)
{
this
.
kind
=
kind
;
this
.
value
=
value
;
}
public
String
getKind
()
{
return
kind
;
}
public
Object
getValue
()
{
return
value
;
}
@Override
public
boolean
equals
(
Object
o
)
{
if
(!(
o
instanceof
Special
))
{
return
false
;
}
Special
that
=
(
Special
)
o
;
return
this
.
kind
.
equals
(
that
.
kind
)
&&
this
.
value
.
equals
(
that
.
value
);
}
@Override
public
int
hashCode
()
{
return
kind
.
hashCode
()
*
65
+
value
.
hashCode
();
}
public
int
compareTo
(
Special
that
)
{
int
r
=
this
.
kind
.
compareTo
(
that
.
kind
);
if
(
r
!=
0
)
{
return
r
;
}
return
((
Comparable
)
this
.
value
).
compareTo
(
that
.
value
);
}
@Override
public
String
toString
()
{
int
split
=
kind
.
indexOf
(
' '
);
String
pref
=
kind
.
substring
(
0
,
split
<
0
?
0
:
split
);
String
post
=
kind
.
substring
(
split
+
1
);
return
pref
+
value
+
post
;
}
}
/** Supports sorting of mixed content. Sorts strings first,
* then Elements, then everything else (as Comparable).
*/
public
static
Comparator
<
Object
>
contentOrder
()
{
return
CONTENT_ORDER
;
}
private
static
Comparator
<
Object
>
CONTENT_ORDER
=
new
ContentComparator
();
private
static
class
ContentComparator
implements
Comparator
<
Object
>
{
public
int
compare
(
Object
o1
,
Object
o2
)
{
boolean
cs1
=
(
o1
instanceof
CharSequence
);
boolean
cs2
=
(
o2
instanceof
CharSequence
);
if
(
cs1
&&
cs2
)
{
String
s1
=
(
String
)
fixupString
(
o1
);
String
s2
=
(
String
)
fixupString
(
o2
);
return
s1
.
compareTo
(
s2
);
}
if
(
cs1
)
{
return
0
-
1
;
}
if
(
cs2
)
{
return
1
-
0
;
}
boolean
el1
=
(
o1
instanceof
Element
);
boolean
el2
=
(
o2
instanceof
Element
);
if
(
el1
&&
el2
)
{
return
((
Element
)
o1
).
compareTo
((
Element
)
o2
);
}
if
(
el1
)
{
return
0
-
1
;
}
if
(
el2
)
{
return
1
-
0
;
}
return
((
Comparable
)
o1
).
compareTo
(
o2
);
}
}
/** Used to find, filter, or transform sub-elements.
* When used as a predicate, the filter returns a null
* value for false, and the original object value for true.
* When used as a transformer, the filter may return
* null, for no values, the original object, a new object,
* or an anonymous Element (meaning multiple results).
*/
public
interface
Filter
{
Object
filter
(
Object
value
);
}
/** Use this to find an element, perhaps with a given name. */
public
static
class
ElementFilter
implements
Filter
{
/** Subclasses may override this to implement better value tests.
* By default, it returns the element itself, thus recognizing
* all elements, regardless of name.
*/
public
Element
filter
(
Element
elem
)
{
return
elem
;
// override this
}
public
final
Object
filter
(
Object
value
)
{
if
(!(
value
instanceof
Element
))
{
return
null
;
}
return
filter
((
Element
)
value
);
}
@Override
public
String
toString
()
{
return
"<ElementFilter name='*'/>"
;
}
}
private
static
Filter
elementFilter
;
public
static
Filter
elementFilter
()
{
return
(
elementFilter
!=
null
)
?
elementFilter
:
(
elementFilter
=
new
ElementFilter
());
}
public
static
Filter
elementFilter
(
final
String
name
)
{
name
.
toString
();
// null check
return
new
ElementFilter
()
{
@Override
public
Element
filter
(
Element
elem
)
{
return
name
.
equals
(
elem
.
name
)
?
elem
:
null
;
}
@Override
public
String
toString
()
{
return
"<ElementFilter name='"
+
name
+
"'/>"
;
}
};
}
public
static
Filter
elementFilter
(
final
Collection
nameSet
)
{
nameSet
.
getClass
();
// null check
return
new
ElementFilter
()
{
@Override
public
Element
filter
(
Element
elem
)
{
return
nameSet
.
contains
(
elem
.
name
)
?
elem
:
null
;
}
@Override
public
String
toString
()
{
return
"<ElementFilter name='"
+
nameSet
+
"'/>"
;
}
};
}
public
static
Filter
elementFilter
(
String
...
nameSet
)
{
Collection
<
String
>
ncoll
=
Arrays
.
asList
(
nameSet
);
if
(
nameSet
.
length
>
10
)
{
ncoll
=
new
HashSet
<
String
>(
ncoll
);
}
return
elementFilter
(
ncoll
);
}
/** Use this to find an element with a named attribute,
* possibly with a particular value.
* (Note that an attribute is missing if and only if its value is null.)
*/
public
static
class
AttrFilter
extends
ElementFilter
{
protected
final
String
attrName
;
public
AttrFilter
(
String
attrName
)
{
this
.
attrName
=
attrName
.
toString
();
}
/** Subclasses may override this to implement better value tests.
* By default, it returns true for any non-null value, thus
* recognizing any attribute of the given name, regardless of value.
*/
public
boolean
test
(
String
attrVal
)
{
return
attrVal
!=
null
;
// override this
}
@Override
public
final
Element
filter
(
Element
elem
)
{
return
test
(
elem
.
getAttr
(
attrName
))
?
elem
:
null
;
}
@Override
public
String
toString
()
{
return
"<AttrFilter name='"
+
attrName
+
"' value='*'/>"
;
}
}
public
static
Filter
attrFilter
(
String
attrName
)
{
return
new
AttrFilter
(
attrName
);
}
public
static
Filter
attrFilter
(
String
attrName
,
final
String
attrVal
)
{
if
(
attrVal
==
null
)
{
return
not
(
attrFilter
(
attrName
));
}
return
new
AttrFilter
(
attrName
)
{
@Override
public
boolean
test
(
String
attrVal2
)
{
return
attrVal
.
equals
(
attrVal2
);
}
@Override
public
String
toString
()
{
return
"<AttrFilter name='"
+
attrName
+
"' value='"
+
attrVal
+
"'/>"
;
}
};
}
public
static
Filter
attrFilter
(
Element
matchThis
,
String
attrName
)
{
return
attrFilter
(
attrName
,
matchThis
.
getAttr
(
attrName
));
}
/** Use this to find a sub-element of a given class. */
public
static
Filter
classFilter
(
final
Class
clazz
)
{
return
new
Filter
()
{
public
Object
filter
(
Object
value
)
{
return
clazz
.
isInstance
(
value
)
?
value
:
null
;
}
@Override
public
String
toString
()
{
return
"<ClassFilter class='"
+
clazz
.
getName
()
+
"'/>"
;
}
};
}
private
static
Filter
textFilter
;
public
static
Filter
textFilter
()
{
return
(
textFilter
!=
null
)
?
textFilter
:
(
textFilter
=
classFilter
(
CharSequence
.
class
));
}
private
static
Filter
specialFilter
;
public
static
Filter
specialFilter
()
{
return
(
specialFilter
!=
null
)
?
specialFilter
:
(
specialFilter
=
classFilter
(
Special
.
class
));
}
private
static
Filter
selfFilter
;
/** This filter always returns its own argument. */
public
static
Filter
selfFilter
()
{
if
(
selfFilter
!=
null
)
{
return
selfFilter
;
}
return
selfFilter
=
new
Filter
()
{
public
Object
filter
(
Object
value
)
{
return
value
;
}
@Override
public
String
toString
()
{
return
"<Self/>"
;
}
};
}
/** This filter always returns a fixed value, regardless of argument. */
public
static
Filter
constantFilter
(
final
Object
value
)
{
return
new
Filter
()
{
public
Object
filter
(
Object
ignore
)
{
return
value
;
}
@Override
public
String
toString
()
{
return
"<Constant>"
+
value
+
"</Constant>"
;
}
};
}
private
static
Filter
nullFilter
;
public
static
Filter
nullFilter
()
{
return
(
nullFilter
!=
null
)
?
nullFilter
:
(
nullFilter
=
constantFilter
(
null
));
}
private
static
Filter
emptyFilter
;
public
static
Filter
emptyFilter
()
{
return
(
emptyFilter
!=
null
)
?
emptyFilter
:
(
emptyFilter
=
constantFilter
(
Element
.
EMPTY
));
}
/** Use this to invert the logical sense of the given filter. */
public
static
Filter
not
(
final
Filter
f
)
{
return
new
Filter
()
{
public
Object
filter
(
Object
value
)
{
return
f
.
filter
(
value
)
==
null
?
value
:
null
;
}
@Override
public
String
toString
()
{
return
"<Not>"
+
f
+
"</Not>"
;
}
};
}
/** Use this to combine several filters with logical AND.
* Returns either the first null or the last non-null value.
*/
public
static
Filter
and
(
final
Filter
f0
,
final
Filter
f1
)
{
return
and
(
new
Filter
[]{
f0
,
f1
});
}
public
static
Filter
and
(
final
Filter
...
fs
)
{
switch
(
fs
.
length
)
{
case
0
:
return
selfFilter
();
// always true (on non-null inputs)
case
1
:
return
fs
[
0
];
}
return
new
Filter
()
{
public
Object
filter
(
Object
value
)
{
Object
res
=
fs
[
0
].
filter
(
value
);
if
(
res
!=
null
)
{
res
=
fs
[
1
].
filter
(
value
);
for
(
int
i
=
2
;
res
!=
null
&&
i
<
fs
.
length
;
i
++)
{
res
=
fs
[
i
].
filter
(
value
);
}
}
return
res
;
}
@Override
public
String
toString
()
{
return
opToString
(
"<And>"
,
fs
,
"</And>"
);
}
};
}
/** Use this to combine several filters with logical OR.
* Returns either the first non-null or the last null value.
*/
public
static
Filter
or
(
final
Filter
f0
,
final
Filter
f1
)
{
return
or
(
new
Filter
[]{
f0
,
f1
});
}
public
static
Filter
or
(
final
Filter
...
fs
)
{
switch
(
fs
.
length
)
{
case
0
:
return
nullFilter
();
case
1
:
return
fs
[
0
];
}
return
new
Filter
()
{
public
Object
filter
(
Object
value
)
{
Object
res
=
fs
[
0
].
filter
(
value
);
if
(
res
==
null
)
{
res
=
fs
[
1
].
filter
(
value
);
for
(
int
i
=
2
;
res
==
null
&&
i
<
fs
.
length
;
i
++)
{
res
=
fs
[
i
].
filter
(
value
);
}
}
return
res
;
}
@Override
public
String
toString
()
{
return
opToString
(
"<Or>"
,
fs
,
"</Or>"
);
}
};
}
/** Use this to combine several filters with logical AND,
* and where each non-null result is passed as the argument
* to the next filter.
* Returns either the first null or the last non-null value.
*/
public
static
Filter
stack
(
final
Filter
f0
,
final
Filter
f1
)
{
return
stack
(
new
Filter
[]{
f0
,
f1
});
}
public
static
Filter
stack
(
final
Filter
...
fs
)
{
switch
(
fs
.
length
)
{
case
0
:
return
nullFilter
();
case
1
:
return
fs
[
0
];
}
return
new
Filter
()
{
public
Object
filter
(
Object
value
)
{
Object
res
=
fs
[
0
].
filter
(
value
);
if
(
res
!=
null
)
{
res
=
fs
[
1
].
filter
(
res
);
for
(
int
i
=
2
;
res
!=
null
&&
i
<
fs
.
length
;
i
++)
{
res
=
fs
[
i
].
filter
(
res
);
}
}
return
res
;
}
@Override
public
String
toString
()
{
return
opToString
(
"<Stack>"
,
fs
,
"</Stack>"
);
}
};
}
/** Copy everything produced by f to sink, using addContent. */
public
static
Filter
content
(
final
Filter
f
,
final
Collection
<
Object
>
sink
)
{
return
new
Filter
()
{
public
Object
filter
(
Object
value
)
{
Object
res
=
f
.
filter
(
value
);
addContent
(
res
,
sink
);
return
res
;
}
@Override
public
String
toString
()
{
return
opToString
(
"<addContent>"
,
new
Object
[]{
f
,
sink
},
"</addContent>"
);
}
};
}
/** Look down the tree using f, collecting fx, else recursing into x.
* Identities:
* <code>
* findInTree(f, s) == findInTree(content(f, s))
* findInTree(f) == replaceInTree(and(f, selfFilter())).
* </code>
*/
public
static
Filter
findInTree
(
Filter
f
,
Collection
<
Object
>
sink
)
{
if
(
sink
!=
null
)
{
f
=
content
(
f
,
sink
);
}
return
findInTree
(
f
);
}
/** Look down the tree using f, recursing into x unless fx. */
public
static
Filter
findInTree
(
final
Filter
f
)
{
return
new
Filter
()
{
public
Object
filter
(
Object
value
)
{
Object
res
=
f
.
filter
(
value
);
if
(
res
!=
null
)
{
return
res
;
}
if
(
value
instanceof
Element
)
{
// recurse
return
((
Element
)
value
).
find
(
this
);
}
return
null
;
}
@Override
public
String
toString
()
{
return
opToString
(
"<FindInTree>"
,
new
Object
[]{
f
},
"</FindInTree>"
);
}
};
}
/** Look down the tree using f. Replace each x with fx, else recurse.
* If post filter g is given, optionally replace with gx after recursion.
*/
public
static
Filter
replaceInTree
(
final
Filter
f
,
final
Filter
g
)
{
return
new
Filter
()
{
public
Object
filter
(
Object
value
)
{
Object
res
=
(
f
==
null
)
?
null
:
f
.
filter
(
value
);
if
(
res
!=
null
)
{
return
res
;
}
if
(
value
instanceof
Element
)
{
// recurse
((
Element
)
value
).
replaceAll
(
this
);
// Optional postorder traversal:
if
(
g
!=
null
)
{
res
=
g
.
filter
(
value
);
}
}
return
res
;
// usually null, meaning no replacement
}
@Override
public
String
toString
()
{
return
opToString
(
"<ReplaceInTree>"
,
new
Object
[]{
f
,
g
},
"</ReplaceInTree>"
);
}
};
}
public
static
Filter
replaceInTree
(
Filter
f
)
{
f
.
getClass
();
// null check
return
replaceInTree
(
f
,
null
);
}
/** Make a filter which calls this method on the given element.
* If the method is static, the first argument is passed the
* the subtree value being filtered.
* If the method is non-static, the receiver is the subtree value itself.
* <p>
* Optionally, additional arguments may be specified.
* <p>
* If the filtered value does not match the receiver class
* (or else the first argument type, if the method is static),
* the filter returns null without invoking the method.
* <p>
* The returned filter value is the result returned from the method.
* Optionally, a non-null special false result value may be specified.
* If the result returned from the method is equal to that false value,
* the filter will return null.
*/
public
static
Filter
methodFilter
(
java
.
lang
.
reflect
.
Method
m
,
Object
[]
extraArgs
,
Object
falseResult
)
{
return
methodFilter
(
m
,
false
,
extraArgs
,
falseResult
);
}
public
static
Filter
methodFilter
(
java
.
lang
.
reflect
.
Method
m
,
Object
[]
args
)
{
return
methodFilter
(
m
,
args
,
null
);
}
public
static
Filter
methodFilter
(
java
.
lang
.
reflect
.
Method
m
)
{
return
methodFilter
(
m
,
null
,
null
);
}
public
static
Filter
testMethodFilter
(
java
.
lang
.
reflect
.
Method
m
,
Object
[]
extraArgs
,
Object
falseResult
)
{
return
methodFilter
(
m
,
true
,
extraArgs
,
falseResult
);
}
public
static
Filter
testMethodFilter
(
java
.
lang
.
reflect
.
Method
m
,
Object
[]
extraArgs
)
{
return
methodFilter
(
m
,
true
,
extraArgs
,
zeroArgs
.
get
(
m
.
getReturnType
()));
}
public
static
Filter
testMethodFilter
(
java
.
lang
.
reflect
.
Method
m
)
{
return
methodFilter
(
m
,
true
,
null
,
zeroArgs
.
get
(
m
.
getReturnType
()));
}
private
static
Filter
methodFilter
(
final
java
.
lang
.
reflect
.
Method
m
,
final
boolean
isTest
,
Object
[]
extraArgs
,
final
Object
falseResult
)
{
Class
[]
params
=
m
.
getParameterTypes
();
final
boolean
isStatic
=
java
.
lang
.
reflect
.
Modifier
.
isStatic
(
m
.
getModifiers
());
int
insertLen
=
(
isStatic
?
1
:
0
);
if
(
insertLen
+
(
extraArgs
==
null
?
0
:
extraArgs
.
length
)
>
params
.
length
)
{
throw
new
IllegalArgumentException
(
"too many arguments"
);
}
final
Object
[]
args
=
(
params
.
length
==
insertLen
)
?
null
:
new
Object
[
params
.
length
];
final
Class
valueType
=
!
isStatic
?
m
.
getDeclaringClass
()
:
params
[
0
];
if
(
valueType
.
isPrimitive
())
{
throw
new
IllegalArgumentException
(
"filtered value must be reference type"
);
}
int
fillp
=
insertLen
;
if
(
extraArgs
!=
null
)
{
for
(
int
i
=
0
;
i
<
extraArgs
.
length
;
i
++)
{
args
[
fillp
++]
=
extraArgs
[
i
];
}
}
if
(
args
!=
null
)
{
while
(
fillp
<
args
.
length
)
{
Class
param
=
params
[
fillp
];
args
[
fillp
++]
=
param
.
isPrimitive
()
?
zeroArgs
.
get
(
param
)
:
null
;
}
}
final
Thread
curt
=
Thread
.
currentThread
();
class
MFilt
implements
Filter
{
public
Object
filter
(
Object
value
)
{
if
(!
valueType
.
isInstance
(
value
))
{
return
null
;
// filter fails quickly
}
Object
[]
args1
=
args
;
if
(
isStatic
)
{
if
(
args1
==
null
)
{
args1
=
new
Object
[
1
];
}
else
if
(
curt
!=
Thread
.
currentThread
())
// Dirty hack to curtail array copying in common case.
{
args1
=
(
Object
[])
args1
.
clone
();
}
args1
[
0
]
=
value
;
}
Object
res
;
try
{
res
=
m
.
invoke
(
value
,
args1
);
}
catch
(
java
.
lang
.
reflect
.
InvocationTargetException
te
)
{
Throwable
ee
=
te
.
getCause
();
if
(
ee
instanceof
RuntimeException
)
{
throw
(
RuntimeException
)
ee
;
}
if
(
ee
instanceof
Error
)
{
throw
(
Error
)
ee
;
}
throw
new
RuntimeException
(
"throw in filter"
,
ee
);
}
catch
(
IllegalAccessException
ee
)
{
throw
new
RuntimeException
(
"access error in filter"
,
ee
);
}
if
(
res
==
null
)
{
if
(!
isTest
&&
m
.
getReturnType
()
==
Void
.
TYPE
)
{
// Void methods return self by convention.
// (But void "tests" always return false.)
res
=
value
;
}
}
else
{
if
(
falseResult
!=
null
&&
falseResult
.
equals
(
res
))
{
res
=
null
;
}
else
if
(
isTest
)
{
// Tests return self by convention.
res
=
value
;
}
}
return
res
;
}
@Override
public
String
toString
()
{
return
"<Method>"
+
m
+
"</Method>"
;
}
}
return
new
MFilt
();
}
private
static
HashMap
<
Class
,
Object
>
zeroArgs
=
new
HashMap
<
Class
,
Object
>();
static
{
zeroArgs
.
put
(
Boolean
.
TYPE
,
Boolean
.
FALSE
);
zeroArgs
.
put
(
Character
.
TYPE
,
new
Character
((
char
)
0
));
zeroArgs
.
put
(
Byte
.
TYPE
,
new
Byte
((
byte
)
0
));
zeroArgs
.
put
(
Short
.
TYPE
,
new
Short
((
short
)
0
));
zeroArgs
.
put
(
Integer
.
TYPE
,
new
Integer
(
0
));
zeroArgs
.
put
(
Float
.
TYPE
,
new
Float
(
0
));
zeroArgs
.
put
(
Long
.
TYPE
,
new
Long
(
0
));
zeroArgs
.
put
(
Double
.
TYPE
,
new
Double
(
0
));
}
private
static
String
opToString
(
String
s1
,
Object
[]
s2
,
String
s3
)
{
StringBuilder
buf
=
new
StringBuilder
(
s1
);
for
(
int
i
=
0
;
i
<
s2
.
length
;
i
++)
{
if
(
s2
[
i
]
!=
null
)
{
buf
.
append
(
s2
[
i
]);
}
}
buf
.
append
(
s3
);
return
buf
.
toString
();
}
/** Call the filter on each list element x, and replace x with the
* resulting filter value e, or its parts.
* If e is null, keep x. (This eases use of partial-domain filters.)
* If e is a TokenList or an anonymous Element, add e's parts
* to the list instead of x.
* Otherwise, replace x by e.
* <p>
* The effect at each list position <code>n</code> may be expressed
* in terms of XMLKit.addContent as follows:
* <pre>
* Object e = f.filter(target.get(n));
* if (e != null) {
* target.remove(n);
* addContent(e, target.subList(n,n));
* }
* </pre>
* <p>
* Note: To force deletion of x, simply have the filter return
* Element.EMPTY or TokenList.EMPTY.
* To force null filter values to have this effect,
* use the expression: <code>or(f, emptyFilter())</code>.
*/
public
static
void
replaceAll
(
Filter
f
,
List
<
Object
>
target
)
{
for
(
ListIterator
<
Object
>
i
=
target
.
listIterator
();
i
.
hasNext
();)
{
Object
x
=
i
.
next
();
Object
fx
=
f
.
filter
(
x
);
if
(
fx
==
null
)
{
// Unliked addContent, a null is a no-op here.
// i.remove();
}
else
if
(
fx
instanceof
TokenList
)
{
TokenList
tl
=
(
TokenList
)
fx
;
if
(
tl
.
size
()
==
1
)
{
i
.
set
(
tl
);
}
else
{
i
.
remove
();
for
(
String
part
:
tl
)
{
i
.
add
(
part
);
}
}
}
else
if
(
fx
instanceof
Element
&&
((
Element
)
fx
).
isAnonymous
())
{
Element
anon
=
(
Element
)
fx
;
if
(
anon
.
size
()
==
1
)
{
i
.
set
(
anon
);
}
else
{
i
.
remove
();
for
(
Object
part
:
anon
)
{
i
.
add
(
part
);
}
}
}
else
if
(
x
!=
fx
)
{
i
.
set
(
fx
);
}
}
}
/** If e is null, return zero.
* If e is a TokenList or an anonymous Element, add e's parts
* to the collection, and return the number of parts.
* Otherwise, add e to the collection, and return one.
* If the collection reference is null, the result is as if
* a throwaway collection were used.
*/
public
static
int
addContent
(
Object
e
,
Collection
<
Object
>
sink
)
{
if
(
e
==
null
)
{
return
0
;
}
else
if
(
e
instanceof
TokenList
)
{
TokenList
tl
=
(
TokenList
)
e
;
if
(
sink
!=
null
)
{
sink
.
addAll
(
tl
);
}
return
tl
.
size
();
}
else
if
(
e
instanceof
Element
&&
((
Element
)
e
).
isAnonymous
())
{
Element
anon
=
(
Element
)
e
;
if
(
sink
!=
null
)
{
sink
.
addAll
(
anon
.
asList
());
}
return
anon
.
size
();
}
else
{
if
(
sink
!=
null
)
{
sink
.
add
(
e
);
}
return
1
;
}
}
static
Collection
<
Object
>
newCounterColl
()
{
return
new
AbstractCollection
<
Object
>()
{
int
size
;
public
int
size
()
{
return
size
;
}
@Override
public
boolean
add
(
Object
o
)
{
++
size
;
return
true
;
}
public
Iterator
<
Object
>
iterator
()
{
throw
new
UnsupportedOperationException
();
}
};
}
/** SAX2 document handler for building Element trees. */
private
static
class
Builder
implements
ContentHandler
,
LexicalHandler
{
/*, EntityResolver, DTDHandler, ErrorHandler*/
Collection
<
Object
>
sink
;
boolean
makeFrozen
;
boolean
tokenizing
;
Builder
(
Collection
<
Object
>
sink
,
boolean
tokenizing
,
boolean
makeFrozen
)
{
this
.
sink
=
sink
;
this
.
tokenizing
=
tokenizing
;
this
.
makeFrozen
=
makeFrozen
;
}
Object
[]
parts
=
new
Object
[
30
];
int
nparts
=
0
;
int
[]
attrBases
=
new
int
[
10
];
// index into parts
int
[]
elemBases
=
new
int
[
10
];
// index into parts
int
depth
=
-
1
;
// index into attrBases, elemBases
// Parts is organized this way:
// | name0 | akey aval ... | subelem ... | name1 | ... |
// The position of the first "akey" after name0 is attrBases[0].
// The position of the first "subelem" after name0 is elemBases[0].
// The position after the last part is always nparts.
int
mergeableToken
=
-
1
;
// index into parts of recent CharSequence
boolean
inCData
=
false
;
void
addPart
(
Object
x
)
{
//System.out.println("addPart "+x);
if
(
nparts
==
parts
.
length
)
{
Object
[]
newParts
=
new
Object
[
parts
.
length
*
2
];
System
.
arraycopy
(
parts
,
0
,
newParts
,
0
,
parts
.
length
);
parts
=
newParts
;
}
parts
[
nparts
++]
=
x
;
}
Object
getMergeableToken
()
{
if
(
mergeableToken
==
nparts
-
1
)
{
assert
(
parts
[
mergeableToken
]
instanceof
CharSequence
);
return
parts
[
nparts
-
1
];
}
else
{
return
null
;
}
}
void
clearMergeableToken
()
{
if
(
mergeableToken
>=
0
)
{
// Freeze temporary StringBuffers into strings.
assert
(
parts
[
mergeableToken
]
instanceof
CharSequence
);
parts
[
mergeableToken
]
=
parts
[
mergeableToken
].
toString
();
mergeableToken
=
-
1
;
}
}
void
setMergeableToken
()
{
if
(
mergeableToken
!=
nparts
-
1
)
{
clearMergeableToken
();
mergeableToken
=
nparts
-
1
;
assert
(
parts
[
mergeableToken
]
instanceof
CharSequence
);
}
}
// ContentHandler callbacks
public
void
startElement
(
String
ns
,
String
localName
,
String
name
,
Attributes
atts
)
{
clearMergeableToken
();
addPart
(
name
.
intern
());
++
depth
;
if
(
depth
==
attrBases
.
length
)
{
int
oldlen
=
depth
;
int
newlen
=
depth
*
2
;
int
[]
newAB
=
new
int
[
newlen
];
int
[]
newEB
=
new
int
[
newlen
];
System
.
arraycopy
(
attrBases
,
0
,
newAB
,
0
,
oldlen
);
System
.
arraycopy
(
elemBases
,
0
,
newEB
,
0
,
oldlen
);
attrBases
=
newAB
;
elemBases
=
newEB
;
}
attrBases
[
depth
]
=
nparts
;
// Collect attributes.
int
na
=
atts
.
getLength
();
for
(
int
k
=
0
;
k
<
na
;
k
++)
{
addPart
(
atts
.
getQName
(
k
).
intern
());
addPart
(
atts
.
getValue
(
k
));
}
// Get ready to collect elements.
elemBases
[
depth
]
=
nparts
;
}
public
void
endElement
(
String
ns
,
String
localName
,
String
name
)
{
assert
(
depth
>=
0
);
clearMergeableToken
();
int
ebase
=
elemBases
[
depth
];
int
elen
=
nparts
-
ebase
;
int
abase
=
attrBases
[
depth
];
int
alen
=
ebase
-
abase
;
int
nbase
=
abase
-
1
;
int
cap
=
alen
+
(
makeFrozen
?
0
:
NEED_SLOP
)
+
elen
;
Element
e
=
new
Element
((
String
)
parts
[
nbase
],
elen
,
cap
);
// Set up attributes.
for
(
int
k
=
0
;
k
<
alen
;
k
+=
2
)
{
e
.
parts
[
cap
-
k
-
2
]
=
parts
[
abase
+
k
+
0
];
e
.
parts
[
cap
-
k
-
1
]
=
parts
[
abase
+
k
+
1
];
}
// Set up sub-elements.
System
.
arraycopy
(
parts
,
ebase
,
e
.
parts
,
0
,
elen
);
// Back out of this level.
--
depth
;
nparts
=
nbase
;
assert
(
e
.
isFrozen
()
==
makeFrozen
);
assert
(
e
.
size
()
==
elen
);
assert
(
e
.
attrSize
()
*
2
==
alen
);
if
(
depth
>=
0
)
{
addPart
(
e
);
}
else
{
sink
.
add
(
e
);
}
}
public
void
startCDATA
()
{
inCData
=
true
;
}
public
void
endCDATA
()
{
inCData
=
false
;
}
public
void
characters
(
char
[]
buf
,
int
off
,
int
len
)
{
boolean
headSpace
=
false
;
boolean
tailSpace
=
false
;
int
firstLen
;
if
(
tokenizing
&&
!
inCData
)
{
// Strip unquoted blanks.
while
(
len
>
0
&&
isWhitespace
(
buf
[
off
]))
{
headSpace
=
true
;
++
off
;
--
len
;
}
if
(
len
==
0
)
{
tailSpace
=
true
;
// it is all space
}
while
(
len
>
0
&&
isWhitespace
(
buf
[
off
+
len
-
1
]))
{
tailSpace
=
true
;
--
len
;
}
firstLen
=
0
;
while
(
firstLen
<
len
&&
!
isWhitespace
(
buf
[
off
+
firstLen
]))
{
++
firstLen
;
}
}
else
{
firstLen
=
len
;
}
if
(
headSpace
)
{
clearMergeableToken
();
}
boolean
mergeAtEnd
=
!
tailSpace
;
// If buffer was empty, or had only ignorable blanks, do nothing.
if
(
len
==
0
)
{
return
;
}
// Decide whether to merge some of these chars into a previous token.
Object
prev
=
getMergeableToken
();
if
(
prev
instanceof
StringBuffer
)
{
((
StringBuffer
)
prev
).
append
(
buf
,
off
,
firstLen
);
}
else
if
(
prev
==
null
)
{
addPart
(
new
String
(
buf
,
off
,
firstLen
));
}
else
{
// Merge two strings.
String
prevStr
=
prev
.
toString
();
StringBuffer
prevBuf
=
new
StringBuffer
(
prevStr
.
length
()
+
firstLen
);
prevBuf
.
append
(
prevStr
);
prevBuf
.
append
(
buf
,
off
,
firstLen
);
if
(
mergeAtEnd
&&
len
==
firstLen
)
{
// Replace previous string with new StringBuffer.
parts
[
nparts
-
1
]
=
prevBuf
;
}
else
{
// Freeze it now.
parts
[
nparts
-
1
]
=
prevBuf
.
toString
();
}
}
off
+=
firstLen
;
len
-=
firstLen
;
if
(
len
>
0
)
{
// Appended only the first token.
clearMergeableToken
();
// Add the rest as separate parts.
while
(
len
>
0
)
{
while
(
len
>
0
&&
isWhitespace
(
buf
[
off
]))
{
++
off
;
--
len
;
}
int
nextLen
=
0
;
while
(
nextLen
<
len
&&
!
isWhitespace
(
buf
[
off
+
nextLen
]))
{
++
nextLen
;
}
assert
(
nextLen
>
0
);
addPart
(
new
String
(
buf
,
off
,
nextLen
));
off
+=
nextLen
;
len
-=
nextLen
;
}
}
if
(
mergeAtEnd
)
{
setMergeableToken
();
}
}
public
void
ignorableWhitespace
(
char
[]
buf
,
int
off
,
int
len
)
{
clearMergeableToken
();
if
(
false
)
{
characters
(
buf
,
off
,
len
);
clearMergeableToken
();
}
}
public
void
comment
(
char
[]
buf
,
int
off
,
int
len
)
{
addPart
(
new
Special
(
"<!-- -->"
,
new
String
(
buf
,
off
,
len
)));
}
public
void
processingInstruction
(
String
name
,
String
instruction
)
{
Element
pi
=
new
Element
(
name
);
pi
.
add
(
instruction
);
addPart
(
new
Special
(
"<? ?>"
,
pi
));
}
public
void
skippedEntity
(
String
name
)
{
}
public
void
startDTD
(
String
name
,
String
publicId
,
String
systemId
)
{
}
public
void
endDTD
()
{
}
public
void
startEntity
(
String
name
)
{
}
public
void
endEntity
(
String
name
)
{
}
public
void
setDocumentLocator
(
org
.
xml
.
sax
.
Locator
locator
)
{
}
public
void
startDocument
()
{
}
public
void
endDocument
()
{
}
public
void
startPrefixMapping
(
String
prefix
,
String
uri
)
{
}
public
void
endPrefixMapping
(
String
prefix
)
{
}
}
/** Produce a ContentHandler for use with an XML parser.
* The object is <em>also</em> a LexicalHandler.
* Every top-level Element produced will get added to sink.
* All elements will be frozen iff makeFrozen is true.
*/
public
static
ContentHandler
makeBuilder
(
Collection
<
Object
>
sink
,
boolean
tokenizing
,
boolean
makeFrozen
)
{
return
new
Builder
(
sink
,
tokenizing
,
makeFrozen
);
}
public
static
ContentHandler
makeBuilder
(
Collection
<
Object
>
sink
,
boolean
tokenizing
)
{
return
new
Builder
(
sink
,
tokenizing
,
false
);
}
public
static
ContentHandler
makeBuilder
(
Collection
<
Object
>
sink
)
{
return
makeBuilder
(
sink
,
false
,
false
);
}
public
static
Element
readFrom
(
Reader
in
,
boolean
tokenizing
,
boolean
makeFrozen
)
throws
IOException
{
Element
sink
=
new
Element
();
ContentHandler
b
=
makeBuilder
(
sink
.
asList
(),
tokenizing
,
makeFrozen
);
XMLReader
parser
;
try
{
parser
=
org
.
xml
.
sax
.
helpers
.
XMLReaderFactory
.
createXMLReader
();
}
catch
(
SAXException
ee
)
{
throw
new
Error
(
ee
);
}
//parser.setFastStandalone(true);
parser
.
setContentHandler
(
b
);
try
{
parser
.
setProperty
(
"http://xml.org/sax/properties/lexical-handler"
,
(
LexicalHandler
)
b
);
}
catch
(
SAXException
ee
)
{
// Ignore. We will miss the comments and whitespace.
}
try
{
parser
.
parse
(
new
InputSource
(
in
));
}
catch
(
SAXParseException
ee
)
{
throw
new
RuntimeException
(
"line "
+
ee
.
getLineNumber
()
+
" col "
+
ee
.
getColumnNumber
()
+
": "
,
ee
);
}
catch
(
SAXException
ee
)
{
throw
new
RuntimeException
(
ee
);
}
switch
(
sink
.
size
())
{
case
0
:
return
null
;
case
1
:
if
(
sink
.
get
(
0
)
instanceof
Element
)
{
return
(
Element
)
sink
.
get
(
0
);
}
// fall through
default
:
if
(
makeFrozen
)
{
sink
.
shallowFreeze
();
}
return
sink
;
}
}
public
static
Element
readFrom
(
Reader
in
,
boolean
tokenizing
)
throws
IOException
{
return
readFrom
(
in
,
tokenizing
,
false
);
}
public
static
Element
readFrom
(
Reader
in
)
throws
IOException
{
return
readFrom
(
in
,
false
,
false
);
}
public
static
void
prettyPrintTo
(
OutputStream
out
,
Element
e
)
throws
IOException
{
prettyPrintTo
(
new
OutputStreamWriter
(
out
),
e
);
}
public
static
void
prettyPrintTo
(
Writer
out
,
Element
e
)
throws
IOException
{
Printer
pr
=
new
Printer
(
out
);
pr
.
pretty
=
true
;
pr
.
print
(
e
);
}
static
class
Outputter
{
ContentHandler
ch
;
LexicalHandler
lh
;
Outputter
(
ContentHandler
ch
,
LexicalHandler
lh
)
{
this
.
ch
=
ch
;
this
.
lh
=
lh
;
}
AttributesImpl
atts
=
new
AttributesImpl
();
// handy
void
output
(
Object
x
)
throws
SAXException
{
// Cf. jdom.org/jdom-b8/src/java/org/jdom/output/SAXOutputter.java
if
(
x
instanceof
Element
)
{
Element
e
=
(
Element
)
x
;
atts
.
clear
();
for
(
int
asize
=
e
.
attrSize
(),
k
=
0
;
k
<
asize
;
k
++)
{
String
key
=
e
.
getAttrName
(
k
);
String
val
=
e
.
getAttr
(
k
);
atts
.
addAttribute
(
""
,
""
,
key
,
"CDATA"
,
val
);
}
ch
.
startElement
(
""
,
""
,
e
.
getName
(),
atts
);
for
(
int
i
=
0
;
i
<
e
.
size
();
i
++)
{
output
(
e
.
get
(
i
));
}
ch
.
endElement
(
""
,
""
,
e
.
getName
());
}
else
if
(
x
instanceof
Special
)
{
Special
sp
=
(
Special
)
x
;
if
(
sp
.
kind
.
startsWith
(
"<!--"
))
{
char
[]
chars
=
sp
.
value
.
toString
().
toCharArray
();
lh
.
comment
(
chars
,
0
,
chars
.
length
);
}
else
if
(
sp
.
kind
.
startsWith
(
"<?"
))
{
Element
nameInstr
=
(
Element
)
sp
.
value
;
ch
.
processingInstruction
(
nameInstr
.
name
,
nameInstr
.
get
(
0
).
toString
());
}
else
{
// drop silently
}
}
else
{
char
[]
chars
=
x
.
toString
().
toCharArray
();
ch
.
characters
(
chars
,
0
,
chars
.
length
);
}
}
}
public
static
class
Printer
{
public
Writer
w
;
public
boolean
tokenizing
;
public
boolean
pretty
;
public
boolean
abbreviated
;
// nonstandard format cuts down on noise
int
depth
=
0
;
boolean
prevStr
;
int
tabStop
=
2
;
public
Printer
(
Writer
w
)
{
this
.
w
=
w
;
}
public
Printer
()
{
StringWriter
sw
=
new
StringWriter
();
this
.
w
=
sw
;
}
public
String
nextString
()
{
StringBuffer
sb
=
((
StringWriter
)
w
).
getBuffer
();
String
next
=
sb
.
toString
();
sb
.
setLength
(
0
);
// reset
return
next
;
}
void
indent
(
int
depth
)
throws
IOException
{
if
(
depth
>
0
)
{
w
.
write
(
"\n"
);
}
int
nsp
=
tabStop
*
depth
;
while
(
nsp
>
0
)
{
String
s
=
" "
;
String
t
=
s
.
substring
(
0
,
nsp
<
s
.
length
()
?
nsp
:
s
.
length
());
w
.
write
(
t
);
nsp
-=
t
.
length
();
}
}
public
void
print
(
Element
e
)
throws
IOException
{
if
(
e
.
isAnonymous
())
{
printParts
(
e
);
return
;
}
printRecursive
(
e
);
}
public
void
println
(
Element
e
)
throws
IOException
{
print
(
e
);
w
.
write
(
"\n"
);
w
.
flush
();
}
public
void
printRecursive
(
Element
e
)
throws
IOException
{
boolean
indented
=
false
;
if
(
pretty
&&
!
prevStr
&&
e
.
size
()
+
e
.
attrSize
()
>
0
)
{
indent
(
depth
);
indented
=
true
;
}
w
.
write
(
"<"
);
w
.
write
(
e
.
name
);
for
(
int
asize
=
e
.
attrSize
(),
k
=
0
;
k
<
asize
;
k
++)
{
String
key
=
e
.
getAttrName
(
k
);
String
val
=
e
.
getAttr
(
k
);
w
.
write
(
" "
);
w
.
write
(
key
);
w
.
write
(
"="
);
if
(
val
==
null
)
{
w
.
write
(
"null"
);
// Should not happen....
}
else
if
(
val
.
indexOf
(
"\""
)
<
0
)
{
w
.
write
(
"\""
);
writeToken
(
val
,
'"'
,
w
);
w
.
write
(
"\""
);
}
else
{
w
.
write
(
"'"
);
writeToken
(
val
,
'\''
,
w
);
w
.
write
(
"'"
);
}
}
if
(
e
.
size
()
==
0
)
{
w
.
write
(
"/>"
);
}
else
{
++
depth
;
if
(
abbreviated
)
{
w
.
write
(
"/"
);
}
else
{
w
.
write
(
">"
);
}
prevStr
=
false
;
printParts
(
e
);
if
(
abbreviated
)
{
w
.
write
(
">"
);
}
else
{
if
(
indented
&&
!
prevStr
)
{
indent
(
depth
-
1
);
}
w
.
write
(
"</"
);
w
.
write
(
e
.
name
);
w
.
write
(
">"
);
}
prevStr
=
false
;
--
depth
;
}
}
private
void
printParts
(
Element
e
)
throws
IOException
{
for
(
int
i
=
0
;
i
<
e
.
size
();
i
++)
{
Object
x
=
e
.
get
(
i
);
if
(
x
instanceof
Element
)
{
printRecursive
((
Element
)
x
);
prevStr
=
false
;
}
else
if
(
x
instanceof
Special
)
{
w
.
write
(((
Special
)
x
).
toString
());
prevStr
=
false
;
}
else
{
String
s
=
String
.
valueOf
(
x
);
if
(
pretty
)
{
s
=
s
.
trim
();
if
(
s
.
length
()
==
0
)
{
continue
;
}
}
if
(
prevStr
)
{
w
.
write
(
' '
);
}
writeToken
(
s
,
tokenizing
?
' '
:
(
char
)
-
1
,
w
);
prevStr
=
true
;
}
if
(
pretty
&&
depth
==
0
)
{
w
.
write
(
"\n"
);
prevStr
=
false
;
}
}
}
}
public
static
void
output
(
Object
e
,
ContentHandler
ch
,
LexicalHandler
lh
)
throws
SAXException
{
new
Outputter
(
ch
,
lh
).
output
(
e
);
}
public
static
void
output
(
Object
e
,
ContentHandler
ch
)
throws
SAXException
{
if
(
ch
instanceof
LexicalHandler
)
{
output
(
e
,
ch
,
(
LexicalHandler
)
ch
);
}
else
{
output
(
e
,
ch
,
null
);
}
}
public
static
void
writeToken
(
String
val
,
char
quote
,
Writer
w
)
throws
IOException
{
int
len
=
val
.
length
();
boolean
canUseCData
=
(
quote
!=
'"'
&&
quote
!=
'\''
);
int
vpos
=
0
;
for
(
int
i
=
0
;
i
<
len
;
i
++)
{
char
ch
=
val
.
charAt
(
i
);
if
((
ch
==
'<'
||
ch
==
'&'
||
ch
==
'>'
||
ch
==
quote
)
||
(
quote
==
' '
&&
isWhitespace
(
ch
)))
{
if
(
canUseCData
)
{
assert
(
vpos
==
0
);
writeCData
(
val
,
w
);
return
;
}
else
{
if
(
vpos
<
i
)
{
w
.
write
(
val
,
vpos
,
i
-
vpos
);
}
String
esc
;
switch
(
ch
)
{
case
'&'
:
esc
=
"&"
;
break
;
case
'<'
:
esc
=
"<"
;
break
;
case
'\''
:
esc
=
"'"
;
break
;
case
'"'
:
esc
=
"""
;
break
;
case
'>'
:
esc
=
">"
;
break
;
default
:
esc
=
"&#"
+
(
int
)
ch
+
";"
;
break
;
}
w
.
write
(
esc
);
vpos
=
i
+
1
;
// skip escaped char
}
}
}
// write the unquoted tail
w
.
write
(
val
,
vpos
,
val
.
length
()
-
vpos
);
}
public
static
void
writeCData
(
String
val
,
Writer
w
)
throws
IOException
{
String
begCData
=
"<![CDATA["
;
String
endCData
=
"]]>"
;
w
.
write
(
begCData
);
for
(
int
vpos
=
0
,
split
;;
vpos
=
split
)
{
split
=
val
.
indexOf
(
endCData
,
vpos
);
if
(
split
<
0
)
{
w
.
write
(
val
,
vpos
,
val
.
length
()
-
vpos
);
w
.
write
(
endCData
);
return
;
}
split
+=
2
;
// bisect the "]]>" goo
w
.
write
(
val
,
vpos
,
split
-
vpos
);
w
.
write
(
endCData
);
w
.
write
(
begCData
);
}
}
public
static
TokenList
convertToList
(
String
str
)
{
if
(
str
==
null
)
{
return
null
;
}
return
new
TokenList
(
str
);
}
/** If str is null, empty, or blank, returns null.
* Otherwise, return a Double if str spells a double value and contains '.' or 'e'.
* Otherwise, return an Integer if str spells an int value.
* Otherwise, return a Long if str spells a long value.
* Otherwise, return a BigInteger for the string.
* Otherwise, throw NumberFormatException.
*/
public
static
Number
convertToNumber
(
String
str
)
{
if
(
str
==
null
)
{
return
null
;
}
str
=
str
.
trim
();
if
(
str
.
length
()
==
0
)
{
return
null
;
}
if
(
str
.
indexOf
(
'.'
)
>=
0
||
str
.
indexOf
(
'e'
)
>=
0
||
str
.
indexOf
(
'E'
)
>=
0
)
{
return
Double
.
valueOf
(
str
);
}
try
{
long
lval
=
Long
.
parseLong
(
str
);
if
(
lval
==
(
int
)
lval
)
{
// Narrow to Integer, if possible.
return
new
Integer
((
int
)
lval
);
}
return
new
Long
(
lval
);
}
catch
(
NumberFormatException
ee
)
{
// Could not represent it as a long.
return
new
java
.
math
.
BigInteger
(
str
,
10
);
}
}
public
static
Number
convertToNumber
(
String
str
,
Number
dflt
)
{
Number
n
=
convertToNumber
(
str
);
return
(
n
==
null
)
?
dflt
:
n
;
}
public
static
long
convertToLong
(
String
str
)
{
return
convertToLong
(
str
,
0
);
}
public
static
long
convertToLong
(
String
str
,
long
dflt
)
{
Number
n
=
convertToNumber
(
str
);
return
(
n
==
null
)
?
dflt
:
n
.
longValue
();
}
public
static
double
convertToDouble
(
String
str
)
{
return
convertToDouble
(
str
,
0
);
}
public
static
double
convertToDouble
(
String
str
,
double
dflt
)
{
Number
n
=
convertToNumber
(
str
);
return
(
n
==
null
)
?
dflt
:
n
.
doubleValue
();
}
// Testing:
public
static
void
main
(
String
...
av
)
throws
Exception
{
Element
.
method
(
"getAttr"
);
//new org.jdom.input.SAXBuilder().build(file).getRootElement();
//jdom.org/jdom-b8/src/java/org/jdom/input/SAXBuilder.java
//Document build(InputSource in) throws JDOMException
int
reps
=
0
;
boolean
tokenizing
=
false
;
boolean
makeFrozen
=
false
;
if
(
av
.
length
>
0
)
{
tokenizing
=
true
;
try
{
reps
=
Integer
.
parseInt
(
av
[
0
]);
}
catch
(
NumberFormatException
ee
)
{
}
}
Reader
inR
=
new
BufferedReader
(
new
InputStreamReader
(
System
.
in
));
String
inS
=
null
;
if
(
reps
>
1
)
{
StringWriter
inBufR
=
new
StringWriter
(
1
<<
14
);
char
[]
cbuf
=
new
char
[
1024
];
for
(
int
nr
;
(
nr
=
inR
.
read
(
cbuf
))
>=
0
;)
{
inBufR
.
write
(
cbuf
,
0
,
nr
);
}
inS
=
inBufR
.
toString
();
inR
=
new
StringReader
(
inS
);
}
Element
e
=
XMLKit
.
readFrom
(
inR
,
tokenizing
,
makeFrozen
);
System
.
out
.
println
(
"transform = "
+
e
.
findAll
(
methodFilter
(
Element
.
method
(
"prettyString"
))));
System
.
out
.
println
(
"transform = "
+
e
.
findAll
(
testMethodFilter
(
Element
.
method
(
"hasText"
))));
long
tm0
=
0
;
int
warmup
=
10
;
for
(
int
i
=
1
;
i
<
reps
;
i
++)
{
inR
=
new
StringReader
(
inS
);
readFrom
(
inR
,
tokenizing
,
makeFrozen
);
if
(
i
==
warmup
)
{
System
.
out
.
println
(
"Start timing..."
);
tm0
=
System
.
currentTimeMillis
();
}
}
if
(
tm0
!=
0
)
{
long
tm1
=
System
.
currentTimeMillis
();
System
.
out
.
println
((
reps
-
warmup
)
+
" in "
+
(
tm1
-
tm0
)
+
" ms"
);
}
System
.
out
.
println
(
"hashCode = "
+
e
.
hashCode
());
String
eStr
=
e
.
toString
();
System
.
out
.
println
(
eStr
);
Element
e2
=
readFrom
(
new
StringReader
(
eStr
),
tokenizing
,
!
makeFrozen
);
System
.
out
.
println
(
"hashCode = "
+
e2
.
hashCode
());
if
(!
e
.
equals
(
e2
))
{
System
.
out
.
println
(
"**** NOT EQUAL 1\n"
+
e2
);
}
e
=
e
.
deepCopy
();
System
.
out
.
println
(
"hashCode = "
+
e
.
hashCode
());
if
(!
e
.
equals
(
e2
))
{
System
.
out
.
println
(
"**** NOT EQUAL 2"
);
}
e2
.
shallowFreeze
();
System
.
out
.
println
(
"hashCode = "
+
e2
.
hashCode
());
if
(!
e
.
equals
(
e2
))
{
System
.
out
.
println
(
"**** NOT EQUAL 3"
);
}
if
(
false
)
{
System
.
out
.
println
(
e
);
}
else
{
prettyPrintTo
(
new
OutputStreamWriter
(
System
.
out
),
e
);
}
System
.
out
.
println
(
"Flat text:|"
+
e
.
getFlatText
()
+
"|"
);
{
System
.
out
.
println
(
"<!--- Sorted: --->"
);
Element
ce
=
e
.
copyContentOnly
();
ce
.
sort
();
prettyPrintTo
(
new
OutputStreamWriter
(
System
.
out
),
ce
);
}
{
System
.
out
.
println
(
"<!--- Trimmed: --->"
);
Element
tr
=
e
.
deepCopy
();
findInTree
(
testMethodFilter
(
Element
.
method
(
"trimText"
))).
filter
(
tr
);
System
.
out
.
println
(
tr
);
}
{
System
.
out
.
println
(
"<!--- Unstrung: --->"
);
Element
us
=
e
.
deepCopy
();
int
nr
=
us
.
retainAllInTree
(
elementFilter
(),
null
);
System
.
out
.
println
(
"nr="
+
nr
);
System
.
out
.
println
(
us
);
}
{
System
.
out
.
println
(
"<!--- Rollup: --->"
);
Element
ru
=
e
.
deepCopy
();
Filter
makeAnonF
=
methodFilter
(
Element
.
method
(
"setName"
),
new
Object
[]{
ANON_NAME
});
Filter
testSizeF
=
testMethodFilter
(
Element
.
method
(
"size"
));
Filter
walk
=
replaceInTree
(
and
(
not
(
elementFilter
()),
emptyFilter
()),
and
(
testSizeF
,
makeAnonF
));
ru
=
(
Element
)
walk
.
filter
(
ru
);
//System.out.println(ru);
prettyPrintTo
(
new
OutputStreamWriter
(
System
.
out
),
ru
);
}
}
static
boolean
isWhitespace
(
char
c
)
{
switch
(
c
)
{
case
0x20
:
case
0x09
:
case
0x0D
:
case
0x0A
:
return
true
;
}
return
false
;
}
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录