Merge
This commit is contained in:
commit
7dd38808b9
@ -359,3 +359,4 @@ b2a69d66dc65ad1d3aeb3bd362cf5bb0deba040e jdk-9+111
|
||||
bb8379287f3736f38c52b2d1418784e2592461d1 jdk-9+114
|
||||
35225b837d66582037eeadeb471c13235dfd793d jdk-9+115
|
||||
baeb5edb38939cdb78ae0ac6f4fd368465cbf188 jdk-9+116
|
||||
4da0f73ce03aaf245b92cc040cc0ab0e3fa54dc2 jdk-9+117
|
||||
|
74
jdk/make/GenerateClasslist.gmk
Normal file
74
jdk/make/GenerateClasslist.gmk
Normal file
@ -0,0 +1,74 @@
|
||||
#
|
||||
# Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License version 2 only, as
|
||||
# published by the Free Software Foundation. Oracle designates this
|
||||
# particular file as subject to the "Classpath" exception as provided
|
||||
# by Oracle in the LICENSE file that accompanied this code.
|
||||
#
|
||||
# This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
# version 2 for more details (a copy is included in the LICENSE file that
|
||||
# accompanied this code).
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License version
|
||||
# 2 along with this work; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
# or visit www.oracle.com if you need additional information or have any
|
||||
# questions.
|
||||
#
|
||||
|
||||
################################################################################
|
||||
# Generate classlist
|
||||
################################################################################
|
||||
|
||||
default: all
|
||||
|
||||
include $(SPEC)
|
||||
include MakeBase.gmk
|
||||
include Tools.gmk
|
||||
include JarArchive.gmk
|
||||
|
||||
################################################################################
|
||||
# Create a jar with our generator class. Using a jar is intentional since it
|
||||
# will load more classes
|
||||
|
||||
$(eval $(call SetupJarArchive, CLASSLIST_JAR, \
|
||||
SRCS := $(BUILDTOOLS_OUTPUTDIR)/jdk_tools_classes, \
|
||||
INCLUDES := build/tools/classlist, \
|
||||
JAR := $(SUPPORT_OUTPUTDIR)/classlist.jar, \
|
||||
))
|
||||
|
||||
TARGETS += $(CLASSLIST_JAR)
|
||||
|
||||
################################################################################
|
||||
|
||||
CLASSLIST_FILE := $(SUPPORT_OUTPUTDIR)/classlist/classlist
|
||||
|
||||
# If an external buildjdk has been supplied, we don't build a separate interim
|
||||
# image, so just use the external build jdk instead.
|
||||
ifeq ($(EXTERNAL_BUILDJDK), true)
|
||||
INTERIM_IMAGE_DIR := $(BUILD_JDK)
|
||||
endif
|
||||
|
||||
$(CLASSLIST_FILE): $(INTERIM_IMAGE_DIR)/bin/java$(EXE_SUFFIX) $(CLASSLIST_JAR)
|
||||
$(call MakeDir, $(@D))
|
||||
$(call LogInfo, Generating lib/classlist)
|
||||
$(FIXPATH) $(INTERIM_IMAGE_DIR)/bin/java -XX:DumpLoadedClassList=$@.tmp \
|
||||
-cp $(SUPPORT_OUTPUTDIR)/classlist.jar \
|
||||
build.tools.classlist.HelloClasslist $(LOG_DEBUG) 2>&1
|
||||
# Filter out generated classes, remove after JDK-8149977
|
||||
$(FIXPATH) $(INTERIM_IMAGE_DIR)/bin/java -XX:DumpLoadedClassList=$@ \
|
||||
-Xshare:dump -XX:SharedClassListFile=$@.tmp $(LOG_DEBUG) 2>&1
|
||||
$(RM) $@.tmp
|
||||
|
||||
TARGETS += $(CLASSLIST_FILE)
|
||||
|
||||
################################################################################
|
||||
|
||||
all: $(TARGETS)
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -206,7 +206,8 @@ ColorData.img_oda_green 28
|
||||
ColorData.img_oda_blue 32
|
||||
ColorData.pGrayInverseLutData 36
|
||||
ColorData.screendata 40
|
||||
ColorData 44
|
||||
ColorData.representsPrimaries 44
|
||||
ColorData 48
|
||||
XFontStruct.ext_data 0
|
||||
XFontStruct.fid 4
|
||||
XFontStruct.direction 8
|
||||
|
@ -206,6 +206,7 @@ ColorData.img_oda_green 56
|
||||
ColorData.img_oda_blue 64
|
||||
ColorData.pGrayInverseLutData 72
|
||||
ColorData.screendata 80
|
||||
ColorData.representsPrimaries 84
|
||||
ColorData 88
|
||||
XFontStruct.ext_data 0
|
||||
XFontStruct.fid 8
|
||||
|
@ -206,6 +206,7 @@ ColorData.img_oda_green 56
|
||||
ColorData.img_oda_blue 64
|
||||
ColorData.pGrayInverseLutData 72
|
||||
ColorData.screendata 80
|
||||
ColorData.representsPrimaries 84
|
||||
ColorData 88
|
||||
XFontStruct.ext_data 0
|
||||
XFontStruct.fid 8
|
||||
|
@ -749,6 +749,7 @@ ColorData
|
||||
img_oda_blue pointer byte
|
||||
pGrayInverseLutData pointer int
|
||||
screendata int
|
||||
representsPrimaries int
|
||||
|
||||
AwtGraphicsConfigData
|
||||
awt_depth int
|
||||
|
@ -75,14 +75,3 @@ $(GENDATA_JAVA_SECURITY): $(BUILD_TOOLS) $(GENDATA_JAVA_SECURITY_SRC) $(RESTRICT
|
||||
TARGETS += $(GENDATA_JAVA_SECURITY)
|
||||
|
||||
################################################################################
|
||||
|
||||
$(SUPPORT_OUTPUTDIR)/modules_libs/java.base/classlist: \
|
||||
$(JDK_TOPDIR)/make/data/classlist/classlist.$(OPENJDK_TARGET_OS)
|
||||
$(call MakeDir, $(@D))
|
||||
$(RM) $@ $@.tmp
|
||||
$(TOOL_ADDJSUM) $< $@.tmp
|
||||
$(MV) $@.tmp $@
|
||||
|
||||
TARGETS += $(SUPPORT_OUTPUTDIR)/modules_libs/java.base/classlist
|
||||
|
||||
################################################################################
|
||||
|
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This application is meant to be run to create a classlist file representing
|
||||
* common use.
|
||||
*
|
||||
* The classlist is produced by adding -XX:DumpLoadedClassList=classlist
|
||||
*/
|
||||
package build.tools.classlist;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.logging.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.text.DateFormat;
|
||||
|
||||
import static java.util.stream.Collectors.*;
|
||||
|
||||
/**
|
||||
* This class is used to generate a classlist during build. Intent
|
||||
* is to touch a reasonable amount of JDK classes that are commonly
|
||||
* loaded and used early.
|
||||
*/
|
||||
public class HelloClasslist {
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger("Hello");
|
||||
|
||||
public static void main(String ... args) {
|
||||
|
||||
List<String> strings = Arrays.asList("Hello", "World!", "From: ",
|
||||
InetAddress.getLoopbackAddress().toString());
|
||||
|
||||
String helloWorld = strings.parallelStream()
|
||||
.map(s -> s.toLowerCase(Locale.ROOT))
|
||||
.collect(joining(","));
|
||||
|
||||
Stream.of(helloWorld.split(","))
|
||||
.forEach(System.out::println);
|
||||
|
||||
String newDate = DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(
|
||||
LocalDateTime.now(ZoneId.of("GMT")));
|
||||
|
||||
String oldDate = String.format("%s%n",
|
||||
DateFormat.getDateInstance(DateFormat.DEFAULT, Locale.ROOT)
|
||||
.format(new Date()));
|
||||
|
||||
LOGGER.log(Level.INFO, "New Date: " + newDate + " - old: " + oldDate);
|
||||
}
|
||||
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -53,7 +53,7 @@ iepoll(int epfd, struct epoll_event *events, int numfds, jlong timeout)
|
||||
start = t.tv_sec * 1000 + t.tv_usec / 1000;
|
||||
|
||||
for (;;) {
|
||||
int res = epoll_wait(epfd, events, numfds, timeout);
|
||||
int res = epoll_wait(epfd, events, numfds, remaining);
|
||||
if (res < 0 && errno == EINTR) {
|
||||
if (remaining >= 0) {
|
||||
gettimeofday(&t, NULL);
|
||||
|
@ -262,4 +262,14 @@ abstract class HmacCore extends MacSpi implements Cloneable {
|
||||
super("SHA-512", 128);
|
||||
}
|
||||
}
|
||||
public static final class HmacSHA512_224 extends HmacCore {
|
||||
public HmacSHA512_224() throws NoSuchAlgorithmException {
|
||||
super("SHA-512/224", 128);
|
||||
}
|
||||
}
|
||||
public static final class HmacSHA512_256 extends HmacCore {
|
||||
public HmacSHA512_256() throws NoSuchAlgorithmException {
|
||||
super("SHA-512/256", 128);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -704,6 +704,12 @@ public final class SunJCE extends Provider {
|
||||
put("Alg.Alias.Mac.OID.1.2.840.113549.2.11", "HmacSHA512");
|
||||
put("Alg.Alias.Mac.1.2.840.113549.2.11", "HmacSHA512");
|
||||
|
||||
// TODO: aliases with OIDs
|
||||
put("Mac.HmacSHA512/224",
|
||||
"com.sun.crypto.provider.HmacCore$HmacSHA512_224");
|
||||
put("Mac.HmacSHA512/256",
|
||||
"com.sun.crypto.provider.HmacCore$HmacSHA512_256");
|
||||
|
||||
put("Mac.HmacPBESHA1",
|
||||
"com.sun.crypto.provider.HmacPKCS12PBESHA1");
|
||||
|
||||
|
@ -33,8 +33,6 @@ import sun.invoke.util.VerifyType;
|
||||
import sun.invoke.util.Wrapper;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
|
||||
|
@ -396,7 +396,7 @@ class Invokers {
|
||||
LambdaForm lform = new LambdaForm(name + ":VarHandle_invoke_MT_" + shortenSignature(basicTypeSignature(mtype)),
|
||||
ARG_LIMIT + 1, names);
|
||||
|
||||
lform.prepare();
|
||||
lform.compileToBytecode();
|
||||
return lform;
|
||||
}
|
||||
|
||||
@ -448,7 +448,7 @@ class Invokers {
|
||||
LambdaForm lform = new LambdaForm(name + ":VarHandle_exactInvoker" + shortenSignature(basicTypeSignature(mtype)),
|
||||
ARG_LIMIT, names);
|
||||
|
||||
lform.prepare();
|
||||
lform.compileToBytecode();
|
||||
return lform;
|
||||
}
|
||||
|
||||
@ -497,44 +497,33 @@ class Invokers {
|
||||
|
||||
/*non-public*/ static
|
||||
@ForceInline
|
||||
MethodHandle checkVarHandleGenericType(VarHandle vh, VarHandle.AccessDescriptor vad) {
|
||||
MethodType expected = vad.symbolicMethodType;
|
||||
MethodType actual = VarHandle.AccessType.getMethodType(vad.type, vh);
|
||||
|
||||
MemberName mn = VarHandle.AccessMode.getMemberName(vad.mode, vh.vform);
|
||||
if (mn == null)
|
||||
throw vh.unsupported();
|
||||
// TODO the following MH is not constant, cache in stable field array
|
||||
// on VarForm?
|
||||
MethodHandle mh = DirectMethodHandle.make(mn);
|
||||
if (actual == expected) {
|
||||
MethodHandle checkVarHandleGenericType(VarHandle handle, VarHandle.AccessDescriptor ad) {
|
||||
// Test for exact match on invoker types
|
||||
// TODO match with erased types and add cast of return value to lambda form
|
||||
MethodHandle mh = handle.getMethodHandle(ad.mode);
|
||||
if (mh.type() == ad.symbolicMethodTypeInvoker) {
|
||||
return mh;
|
||||
}
|
||||
else {
|
||||
// Adapt to the actual (which should never fail since mh's method
|
||||
// type is in the basic form), then to the expected (which my fail
|
||||
// if the symbolic type descriptor does not match)
|
||||
// TODO optimize for the case of actual.erased() == expected.erased()
|
||||
return mh.asType(actual.insertParameterTypes(0, VarHandle.class)).
|
||||
asType(expected.insertParameterTypes(0, VarHandle.class));
|
||||
return mh.asType(ad.symbolicMethodTypeInvoker);
|
||||
}
|
||||
}
|
||||
|
||||
/*non-public*/ static
|
||||
@ForceInline
|
||||
void checkVarHandleExactType(VarHandle vh, VarHandle.AccessDescriptor vad) {
|
||||
MethodType expected = vad.symbolicMethodType;
|
||||
MethodType actual = VarHandle.AccessType.getMethodType(vad.type, vh);
|
||||
if (actual != expected)
|
||||
throw newWrongMethodTypeException(expected, actual);
|
||||
void checkVarHandleExactType(VarHandle handle, VarHandle.AccessDescriptor ad) {
|
||||
MethodType erasedTarget = handle.vform.methodType_table[ad.type];
|
||||
MethodType erasedSymbolic = ad.symbolicMethodTypeErased;
|
||||
if (erasedTarget != erasedSymbolic)
|
||||
throw newWrongMethodTypeException(erasedTarget, erasedSymbolic);
|
||||
}
|
||||
|
||||
/*non-public*/ static
|
||||
@ForceInline
|
||||
MemberName getVarHandleMemberName(VarHandle vh, VarHandle.AccessDescriptor vad) {
|
||||
MemberName mn = VarHandle.AccessMode.getMemberName(vad.mode, vh.vform);
|
||||
MemberName getVarHandleMemberName(VarHandle handle, VarHandle.AccessDescriptor ad) {
|
||||
MemberName mn = handle.vform.memberName_table[ad.mode];
|
||||
if (mn == null) {
|
||||
throw vh.unsupported();
|
||||
throw handle.unsupported();
|
||||
}
|
||||
return mn;
|
||||
}
|
||||
|
@ -430,14 +430,14 @@ class MethodHandleNatives {
|
||||
|
||||
// If not polymorphic in the return type, such as the compareAndSet
|
||||
// methods that return boolean
|
||||
if (ak.isPolyMorphicInReturnType) {
|
||||
if (ak.returnType != mtype.returnType()) {
|
||||
if (ak.at.isMonomorphicInReturnType) {
|
||||
if (ak.at.returnType != mtype.returnType()) {
|
||||
// The caller contains a different return type than that
|
||||
// defined by the method
|
||||
throw newNoSuchMethodErrorOnVarHandle(name, mtype);
|
||||
}
|
||||
// Adjust the return type of the signature method type
|
||||
sigType = sigType.changeReturnType(ak.returnType);
|
||||
sigType = sigType.changeReturnType(ak.at.returnType);
|
||||
}
|
||||
|
||||
// Get the guard method type for linking
|
||||
@ -455,26 +455,25 @@ class MethodHandleNatives {
|
||||
MemberName linker = new MemberName(
|
||||
VarHandleGuards.class, "guard_" + getVarHandleMethodSignature(sigType),
|
||||
guardType, REF_invokeStatic);
|
||||
try {
|
||||
return MemberName.getFactory().resolveOrFail(
|
||||
REF_invokeStatic, linker, VarHandleGuards.class, ReflectiveOperationException.class);
|
||||
} catch (ReflectiveOperationException ex) {
|
||||
// Fall back to lambda form linkage if guard method is not available
|
||||
// TODO Optionally log fallback ?
|
||||
|
||||
linker = MemberName.getFactory().resolveOrNull(REF_invokeStatic, linker,
|
||||
VarHandleGuards.class);
|
||||
if (linker != null) {
|
||||
return linker;
|
||||
}
|
||||
// Fall back to lambda form linkage if guard method is not available
|
||||
// TODO Optionally log fallback ?
|
||||
}
|
||||
return Invokers.varHandleInvokeLinkerMethod(name, mtype);
|
||||
}
|
||||
static String getVarHandleMethodSignature(MethodType mt) {
|
||||
StringBuilder sb = new StringBuilder(mt.parameterCount() + 1);
|
||||
StringBuilder sb = new StringBuilder(mt.parameterCount() + 2);
|
||||
|
||||
for (int i = 0; i < mt.parameterCount(); i++) {
|
||||
Class<?> pt = mt.parameterType(i);
|
||||
sb.append(getCharType(pt));
|
||||
}
|
||||
|
||||
sb.append('_').append(getCharType(mt.returnType()));
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
static char getCharType(Class<?> pt) {
|
||||
|
@ -24,42 +24,102 @@
|
||||
*/
|
||||
package java.lang.invoke;
|
||||
|
||||
import jdk.internal.vm.annotation.ForceInline;
|
||||
import jdk.internal.vm.annotation.Stable;
|
||||
|
||||
import java.lang.invoke.VarHandle.AccessMode;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A var handle form containing a set of member name, one for each operation.
|
||||
* Each member characterizes a static method.
|
||||
*/
|
||||
class VarForm {
|
||||
final class VarForm {
|
||||
|
||||
// Holds VarForm for VarHandle implementation classes
|
||||
private static final ClassValue<VarForm> VFORMS
|
||||
= new ClassValue<>() {
|
||||
@Override
|
||||
protected VarForm computeValue(Class<?> impl) {
|
||||
return new VarForm(linkFromStatic(impl));
|
||||
final @Stable MethodType[] methodType_table;
|
||||
|
||||
final @Stable MemberName[] memberName_table;
|
||||
|
||||
VarForm(Class<?> implClass, Class<?> receiver, Class<?> value, Class<?>... intermediate) {
|
||||
this.methodType_table = new MethodType[VarHandle.AccessType.values().length];
|
||||
|
||||
// TODO lazily calculate
|
||||
this.memberName_table = linkFromStatic(implClass);
|
||||
|
||||
// (Receiver, <Intermediates>)
|
||||
List<Class<?>> l = new ArrayList<>();
|
||||
if (receiver != null)
|
||||
l.add(receiver);
|
||||
l.addAll(Arrays.asList(intermediate));
|
||||
|
||||
// (Receiver, <Intermediates>)Value
|
||||
methodType_table[VarHandle.AccessType.GET.ordinal()] =
|
||||
MethodType.methodType(value, l).erase();
|
||||
|
||||
// (Receiver, <Intermediates>, Value)void
|
||||
l.add(value);
|
||||
methodType_table[VarHandle.AccessType.SET.ordinal()] =
|
||||
MethodType.methodType(void.class, l).erase();
|
||||
|
||||
// (Receiver, <Intermediates>, Value)Value
|
||||
methodType_table[VarHandle.AccessType.GET_AND_UPDATE.ordinal()] =
|
||||
MethodType.methodType(value, l).erase();
|
||||
|
||||
// (Receiver, <Intermediates>, Value, Value)boolean
|
||||
l.add(value);
|
||||
methodType_table[VarHandle.AccessType.COMPARE_AND_SWAP.ordinal()] =
|
||||
MethodType.methodType(boolean.class, l).erase();
|
||||
|
||||
// (Receiver, <Intermediates>, Value, Value)Value
|
||||
methodType_table[VarHandle.AccessType.COMPARE_AND_EXCHANGE.ordinal()] =
|
||||
MethodType.methodType(value, l).erase();
|
||||
}
|
||||
|
||||
@ForceInline
|
||||
final MethodType getMethodType(int type) {
|
||||
return methodType_table[type];
|
||||
}
|
||||
|
||||
@ForceInline
|
||||
final MemberName getMemberName(int mode) {
|
||||
// TODO calculate lazily
|
||||
MemberName mn = memberName_table[mode];
|
||||
if (mn == null) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
};
|
||||
|
||||
final @Stable MemberName[] table;
|
||||
|
||||
VarForm(MemberName[] table) {
|
||||
this.table = table;
|
||||
return mn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a var form given an VarHandle implementation class.
|
||||
* Each signature polymorphic method is linked to a static method of the
|
||||
* same name on the implementation class or a super class.
|
||||
*/
|
||||
static VarForm createFromStatic(Class<? extends VarHandle> impl) {
|
||||
return VFORMS.get(impl);
|
||||
|
||||
@Stable
|
||||
MethodType[] methodType_V_table;
|
||||
|
||||
@ForceInline
|
||||
final MethodType[] getMethodType_V_init() {
|
||||
MethodType[] table = new MethodType[VarHandle.AccessType.values().length];
|
||||
for (int i = 0; i < methodType_table.length; i++) {
|
||||
MethodType mt = methodType_table[i];
|
||||
// TODO only adjust for sig-poly methods returning Object
|
||||
table[i] = mt.changeReturnType(void.class);
|
||||
}
|
||||
methodType_V_table = table;
|
||||
return table;
|
||||
}
|
||||
|
||||
@ForceInline
|
||||
final MethodType getMethodType_V(int type) {
|
||||
MethodType[] table = methodType_V_table;
|
||||
if (table == null) {
|
||||
table = getMethodType_V_init();
|
||||
}
|
||||
return table[type];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Link all signature polymorphic methods.
|
||||
*/
|
||||
|
@ -27,10 +27,9 @@ package java.lang.invoke;
|
||||
|
||||
import jdk.internal.HotSpotIntrinsicCandidate;
|
||||
import jdk.internal.vm.annotation.ForceInline;
|
||||
import jdk.internal.vm.annotation.Stable;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@ -406,42 +405,10 @@ import static java.lang.invoke.MethodHandleStatics.newInternalError;
|
||||
* @since 9
|
||||
*/
|
||||
public abstract class VarHandle {
|
||||
// Use explicit final fields rather than an @Stable array as
|
||||
// this can reduce the memory per handle
|
||||
// e.g. by 24 bytes on 64 bit architectures
|
||||
final MethodType typeGet;
|
||||
final MethodType typeSet;
|
||||
final MethodType typeCompareSwap;
|
||||
final MethodType typeCompareExchange;
|
||||
final MethodType typeGetAndUpdate;
|
||||
|
||||
final VarForm vform;
|
||||
|
||||
VarHandle(VarForm vform, Class<?> receiver, Class<?> value, Class<?>... intermediate) {
|
||||
VarHandle(VarForm vform) {
|
||||
this.vform = vform;
|
||||
|
||||
// (Receiver, <Intermediates>)
|
||||
List<Class<?>> l = new ArrayList<>();
|
||||
if (receiver != null)
|
||||
l.add(receiver);
|
||||
l.addAll(Arrays.asList(intermediate));
|
||||
|
||||
// (Receiver, <Intermediates>)Value
|
||||
this.typeGet = MethodType.methodType(value, l);
|
||||
|
||||
// (Receiver, <Intermediates>, Value)void
|
||||
l.add(value);
|
||||
this.typeSet = MethodType.methodType(void.class, l);
|
||||
|
||||
// (Receiver, <Intermediates>, Value)Value
|
||||
this.typeGetAndUpdate = MethodType.methodType(value, l);
|
||||
|
||||
// (Receiver, <Intermediates>, Value, Value)boolean
|
||||
l.add(value);
|
||||
this.typeCompareSwap = MethodType.methodType(boolean.class, l);
|
||||
|
||||
// (Receiver, <Intermediates>, Value, Value)Value
|
||||
this.typeCompareExchange = MethodType.methodType(value, l);
|
||||
}
|
||||
|
||||
RuntimeException unsupported() {
|
||||
@ -1090,36 +1057,83 @@ public abstract class VarHandle {
|
||||
Object addAndGet(Object... args);
|
||||
|
||||
enum AccessType {
|
||||
GET, // 0
|
||||
SET, // 1
|
||||
COMPARE_AND_SWAP, // 2
|
||||
COMPARE_AND_EXCHANGE, // 3
|
||||
GET_AND_UPDATE; // 4
|
||||
GET(Object.class) {
|
||||
@Override
|
||||
MethodType accessModeType(Class<?> receiver, Class<?> value,
|
||||
Class<?>... intermediate) {
|
||||
Class<?>[] ps = allocateParameters(0, receiver, intermediate);
|
||||
fillParameters(ps, receiver, intermediate);
|
||||
return MethodType.methodType(value, ps);
|
||||
}
|
||||
},
|
||||
SET(void.class) {
|
||||
@Override
|
||||
MethodType accessModeType(Class<?> receiver, Class<?> value,
|
||||
Class<?>... intermediate) {
|
||||
Class<?>[] ps = allocateParameters(1, receiver, intermediate);
|
||||
int i = fillParameters(ps, receiver, intermediate);
|
||||
ps[i] = value;
|
||||
return MethodType.methodType(void.class, ps);
|
||||
}
|
||||
},
|
||||
COMPARE_AND_SWAP(boolean.class) {
|
||||
@Override
|
||||
MethodType accessModeType(Class<?> receiver, Class<?> value,
|
||||
Class<?>... intermediate) {
|
||||
Class<?>[] ps = allocateParameters(2, receiver, intermediate);
|
||||
int i = fillParameters(ps, receiver, intermediate);
|
||||
ps[i++] = value;
|
||||
ps[i] = value;
|
||||
return MethodType.methodType(boolean.class, ps);
|
||||
}
|
||||
},
|
||||
COMPARE_AND_EXCHANGE(Object.class) {
|
||||
@Override
|
||||
MethodType accessModeType(Class<?> receiver, Class<?> value,
|
||||
Class<?>... intermediate) {
|
||||
Class<?>[] ps = allocateParameters(2, receiver, intermediate);
|
||||
int i = fillParameters(ps, receiver, intermediate);
|
||||
ps[i++] = value;
|
||||
ps[i] = value;
|
||||
return MethodType.methodType(value, ps);
|
||||
}
|
||||
},
|
||||
GET_AND_UPDATE(Object.class) {
|
||||
@Override
|
||||
MethodType accessModeType(Class<?> receiver, Class<?> value,
|
||||
Class<?>... intermediate) {
|
||||
Class<?>[] ps = allocateParameters(1, receiver, intermediate);
|
||||
int i = fillParameters(ps, receiver, intermediate);
|
||||
ps[i] = value;
|
||||
return MethodType.methodType(value, ps);
|
||||
}
|
||||
};
|
||||
|
||||
MethodType getMethodType(VarHandle vh) {
|
||||
return getMethodType(this.ordinal(), vh);
|
||||
final Class<?> returnType;
|
||||
final boolean isMonomorphicInReturnType;
|
||||
|
||||
AccessType(Class<?> returnType) {
|
||||
this.returnType = returnType;
|
||||
isMonomorphicInReturnType = returnType != Object.class;
|
||||
}
|
||||
|
||||
@ForceInline
|
||||
static MethodType getMethodType(int ordinal, VarHandle vh) {
|
||||
if (ordinal == 0) {
|
||||
return vh.typeGet;
|
||||
}
|
||||
else if (ordinal == 1) {
|
||||
return vh.typeSet;
|
||||
}
|
||||
else if (ordinal == 2) {
|
||||
return vh.typeCompareSwap;
|
||||
}
|
||||
else if (ordinal == 3) {
|
||||
return vh.typeCompareExchange;
|
||||
}
|
||||
else if (ordinal == 4) {
|
||||
return vh.typeGetAndUpdate;
|
||||
}
|
||||
else {
|
||||
throw new IllegalStateException("Illegal access type: " + ordinal);
|
||||
}
|
||||
abstract MethodType accessModeType(Class<?> receiver, Class<?> value,
|
||||
Class<?>... intermediate);
|
||||
|
||||
private static Class<?>[] allocateParameters(int values,
|
||||
Class<?> receiver, Class<?>... intermediate) {
|
||||
int size = ((receiver != null) ? 1 : 0) + intermediate.length + values;
|
||||
return new Class<?>[size];
|
||||
}
|
||||
|
||||
private static int fillParameters(Class<?>[] ps,
|
||||
Class<?> receiver, Class<?>... intermediate) {
|
||||
int i = 0;
|
||||
if (receiver != null)
|
||||
ps[i++] = receiver;
|
||||
for (int j = 0; j < intermediate.length; j++)
|
||||
ps[i++] = intermediate[j];
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1133,115 +1147,115 @@ public abstract class VarHandle {
|
||||
* method
|
||||
* {@link VarHandle#get VarHandle.get}
|
||||
*/
|
||||
GET("get", AccessType.GET, Object.class),
|
||||
GET("get", AccessType.GET),
|
||||
/**
|
||||
* The access mode whose access is specified by the corresponding
|
||||
* method
|
||||
* {@link VarHandle#set VarHandle.set}
|
||||
*/
|
||||
SET("set", AccessType.SET, void.class),
|
||||
SET("set", AccessType.SET),
|
||||
/**
|
||||
* The access mode whose access is specified by the corresponding
|
||||
* method
|
||||
* {@link VarHandle#getVolatile VarHandle.getVolatile}
|
||||
*/
|
||||
GET_VOLATILE("getVolatile", AccessType.GET, Object.class),
|
||||
GET_VOLATILE("getVolatile", AccessType.GET),
|
||||
/**
|
||||
* The access mode whose access is specified by the corresponding
|
||||
* method
|
||||
* {@link VarHandle#setVolatile VarHandle.setVolatile}
|
||||
*/
|
||||
SET_VOLATILE("setVolatile", AccessType.SET, void.class),
|
||||
SET_VOLATILE("setVolatile", AccessType.SET),
|
||||
/**
|
||||
* The access mode whose access is specified by the corresponding
|
||||
* method
|
||||
* {@link VarHandle#getAcquire VarHandle.getAcquire}
|
||||
*/
|
||||
GET_ACQUIRE("getAcquire", AccessType.GET, Object.class),
|
||||
GET_ACQUIRE("getAcquire", AccessType.GET),
|
||||
/**
|
||||
* The access mode whose access is specified by the corresponding
|
||||
* method
|
||||
* {@link VarHandle#setRelease VarHandle.setRelease}
|
||||
*/
|
||||
SET_RELEASE("setRelease", AccessType.SET, void.class),
|
||||
SET_RELEASE("setRelease", AccessType.SET),
|
||||
/**
|
||||
* The access mode whose access is specified by the corresponding
|
||||
* method
|
||||
* {@link VarHandle#getOpaque VarHandle.getOpaque}
|
||||
*/
|
||||
GET_OPAQUE("getOpaque", AccessType.GET, Object.class),
|
||||
GET_OPAQUE("getOpaque", AccessType.GET),
|
||||
/**
|
||||
* The access mode whose access is specified by the corresponding
|
||||
* method
|
||||
* {@link VarHandle#setOpaque VarHandle.setOpaque}
|
||||
*/
|
||||
SET_OPAQUE("setOpaque", AccessType.SET, void.class),
|
||||
SET_OPAQUE("setOpaque", AccessType.SET),
|
||||
/**
|
||||
* The access mode whose access is specified by the corresponding
|
||||
* method
|
||||
* {@link VarHandle#compareAndSet VarHandle.compareAndSet}
|
||||
*/
|
||||
COMPARE_AND_SET("compareAndSet", AccessType.COMPARE_AND_SWAP, boolean.class),
|
||||
COMPARE_AND_SET("compareAndSet", AccessType.COMPARE_AND_SWAP),
|
||||
/**
|
||||
* The access mode whose access is specified by the corresponding
|
||||
* method
|
||||
* {@link VarHandle#compareAndExchangeVolatile VarHandle.compareAndExchangeVolatile}
|
||||
*/
|
||||
COMPARE_AND_EXCHANGE_VOLATILE("compareAndExchangeVolatile", AccessType.COMPARE_AND_EXCHANGE, Object.class),
|
||||
COMPARE_AND_EXCHANGE_VOLATILE("compareAndExchangeVolatile", AccessType.COMPARE_AND_EXCHANGE),
|
||||
/**
|
||||
* The access mode whose access is specified by the corresponding
|
||||
* method
|
||||
* {@link VarHandle#compareAndExchangeAcquire VarHandle.compareAndExchangeAcquire}
|
||||
*/
|
||||
COMPARE_AND_EXCHANGE_ACQUIRE("compareAndExchangeAcquire", AccessType.COMPARE_AND_EXCHANGE, Object.class),
|
||||
COMPARE_AND_EXCHANGE_ACQUIRE("compareAndExchangeAcquire", AccessType.COMPARE_AND_EXCHANGE),
|
||||
/**
|
||||
* The access mode whose access is specified by the corresponding
|
||||
* method
|
||||
* {@link VarHandle#compareAndExchangeRelease VarHandle.compareAndExchangeRelease}
|
||||
*/
|
||||
COMPARE_AND_EXCHANGE_RELEASE("compareAndExchangeRelease", AccessType.COMPARE_AND_EXCHANGE, Object.class),
|
||||
COMPARE_AND_EXCHANGE_RELEASE("compareAndExchangeRelease", AccessType.COMPARE_AND_EXCHANGE),
|
||||
/**
|
||||
* The access mode whose access is specified by the corresponding
|
||||
* method
|
||||
* {@link VarHandle#weakCompareAndSet VarHandle.weakCompareAndSet}
|
||||
*/
|
||||
WEAK_COMPARE_AND_SET("weakCompareAndSet", AccessType.COMPARE_AND_SWAP, boolean.class),
|
||||
WEAK_COMPARE_AND_SET("weakCompareAndSet", AccessType.COMPARE_AND_SWAP),
|
||||
/**
|
||||
* The access mode whose access is specified by the corresponding
|
||||
* method
|
||||
* {@link VarHandle#weakCompareAndSetVolatile VarHandle.weakCompareAndSetVolatile}
|
||||
*/
|
||||
WEAK_COMPARE_AND_SET_VOLATILE("weakCompareAndSetVolatile", AccessType.COMPARE_AND_SWAP, boolean.class),
|
||||
WEAK_COMPARE_AND_SET_VOLATILE("weakCompareAndSetVolatile", AccessType.COMPARE_AND_SWAP),
|
||||
/**
|
||||
* The access mode whose access is specified by the corresponding
|
||||
* method
|
||||
* {@link VarHandle#weakCompareAndSetAcquire VarHandle.weakCompareAndSetAcquire}
|
||||
*/
|
||||
WEAK_COMPARE_AND_SET_ACQUIRE("weakCompareAndSetAcquire", AccessType.COMPARE_AND_SWAP, boolean.class),
|
||||
WEAK_COMPARE_AND_SET_ACQUIRE("weakCompareAndSetAcquire", AccessType.COMPARE_AND_SWAP),
|
||||
/**
|
||||
* The access mode whose access is specified by the corresponding
|
||||
* method
|
||||
* {@link VarHandle#weakCompareAndSetRelease VarHandle.weakCompareAndSetRelease}
|
||||
*/
|
||||
WEAK_COMPARE_AND_SET_RELEASE("weakCompareAndSetRelease", AccessType.COMPARE_AND_SWAP, boolean.class),
|
||||
WEAK_COMPARE_AND_SET_RELEASE("weakCompareAndSetRelease", AccessType.COMPARE_AND_SWAP),
|
||||
/**
|
||||
* The access mode whose access is specified by the corresponding
|
||||
* method
|
||||
* {@link VarHandle#getAndSet VarHandle.getAndSet}
|
||||
*/
|
||||
GET_AND_SET("getAndSet", AccessType.GET_AND_UPDATE, Object.class),
|
||||
GET_AND_SET("getAndSet", AccessType.GET_AND_UPDATE),
|
||||
/**
|
||||
* The access mode whose access is specified by the corresponding
|
||||
* method
|
||||
* {@link VarHandle#getAndAdd VarHandle.getAndAdd}
|
||||
*/
|
||||
GET_AND_ADD("getAndAdd", AccessType.GET_AND_UPDATE, Object.class),
|
||||
GET_AND_ADD("getAndAdd", AccessType.GET_AND_UPDATE),
|
||||
/**
|
||||
* The access mode whose access is specified by the corresponding
|
||||
* method
|
||||
* {@link VarHandle#addAndGet VarHandle.addAndGet}
|
||||
*/
|
||||
ADD_AND_GET("addAndGet", AccessType.GET_AND_UPDATE, Object.class),
|
||||
ADD_AND_GET("addAndGet", AccessType.GET_AND_UPDATE),
|
||||
;
|
||||
|
||||
static final Map<String, AccessMode> methodNameToAccessMode;
|
||||
@ -1256,10 +1270,8 @@ public abstract class VarHandle {
|
||||
|
||||
final String methodName;
|
||||
final AccessType at;
|
||||
final boolean isPolyMorphicInReturnType;
|
||||
final Class<?> returnType;
|
||||
|
||||
AccessMode(final String methodName, AccessType at, Class<?> returnType) {
|
||||
AccessMode(final String methodName, AccessType at) {
|
||||
this.methodName = methodName;
|
||||
this.at = at;
|
||||
|
||||
@ -1267,10 +1279,7 @@ public abstract class VarHandle {
|
||||
assert methodName.equals(toMethodName(name()));
|
||||
// Assert that return type is correct
|
||||
// Otherwise, when disabled avoid using reflection
|
||||
assert returnType == getReturnType(methodName);
|
||||
|
||||
this.returnType = returnType;
|
||||
isPolyMorphicInReturnType = returnType != Object.class;
|
||||
assert at.returnType == getReturnType(methodName);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1324,17 +1333,21 @@ public abstract class VarHandle {
|
||||
|
||||
@ForceInline
|
||||
static MemberName getMemberName(int ordinal, VarForm vform) {
|
||||
return vform.table[ordinal];
|
||||
return vform.memberName_table[ordinal];
|
||||
}
|
||||
}
|
||||
|
||||
static final class AccessDescriptor {
|
||||
final MethodType symbolicMethodType;
|
||||
final MethodType symbolicMethodTypeErased;
|
||||
final MethodType symbolicMethodTypeInvoker;
|
||||
final Class<?> returnType;
|
||||
final int type;
|
||||
final int mode;
|
||||
|
||||
public AccessDescriptor(MethodType symbolicMethodType, int type, int mode) {
|
||||
this.symbolicMethodType = symbolicMethodType;
|
||||
this.symbolicMethodTypeErased = symbolicMethodType.erase();
|
||||
this.symbolicMethodTypeInvoker = symbolicMethodType.insertParameterTypes(0, VarHandle.class);
|
||||
this.returnType = symbolicMethodType.returnType();
|
||||
this.type = type;
|
||||
this.mode = mode;
|
||||
}
|
||||
@ -1346,6 +1359,7 @@ public abstract class VarHandle {
|
||||
* @return the variable type of variables referenced by this VarHandle
|
||||
*/
|
||||
public final Class<?> varType() {
|
||||
MethodType typeSet = accessModeType(AccessMode.SET);
|
||||
return typeSet.parameterType(typeSet.parameterCount() - 1);
|
||||
}
|
||||
|
||||
@ -1356,6 +1370,7 @@ public abstract class VarHandle {
|
||||
* list is unmodifiable
|
||||
*/
|
||||
public final List<Class<?>> coordinateTypes() {
|
||||
MethodType typeGet = accessModeType(AccessMode.GET);
|
||||
return typeGet.parameterList();
|
||||
}
|
||||
|
||||
@ -1374,9 +1389,15 @@ public abstract class VarHandle {
|
||||
* @return the access mode type for the given access mode
|
||||
*/
|
||||
public final MethodType accessModeType(AccessMode accessMode) {
|
||||
return accessMode.at.getMethodType(this);
|
||||
TypesAndInvokers tis = getTypesAndInvokers();
|
||||
MethodType mt = tis.methodType_table[accessMode.at.ordinal()];
|
||||
if (mt == null) {
|
||||
mt = tis.methodType_table[accessMode.at.ordinal()] =
|
||||
accessModeTypeUncached(accessMode);
|
||||
}
|
||||
return mt;
|
||||
}
|
||||
|
||||
abstract MethodType accessModeTypeUncached(AccessMode accessMode);
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the given access mode is supported, otherwise
|
||||
@ -1417,9 +1438,8 @@ public abstract class VarHandle {
|
||||
public final MethodHandle toMethodHandle(AccessMode accessMode) {
|
||||
MemberName mn = AccessMode.getMemberName(accessMode.ordinal(), vform);
|
||||
if (mn != null) {
|
||||
return DirectMethodHandle.make(mn).
|
||||
bindTo(this).
|
||||
asType(accessMode.at.getMethodType(this));
|
||||
MethodHandle mh = getMethodHandle(accessMode.ordinal());
|
||||
return mh.bindTo(this);
|
||||
}
|
||||
else {
|
||||
// Ensure an UnsupportedOperationException is thrown
|
||||
@ -1428,6 +1448,51 @@ public abstract class VarHandle {
|
||||
}
|
||||
}
|
||||
|
||||
@Stable
|
||||
TypesAndInvokers typesAndInvokers;
|
||||
|
||||
static class TypesAndInvokers {
|
||||
final @Stable
|
||||
MethodType[] methodType_table =
|
||||
new MethodType[VarHandle.AccessType.values().length];
|
||||
|
||||
final @Stable
|
||||
MethodHandle[] methodHandle_table =
|
||||
new MethodHandle[AccessMode.values().length];
|
||||
}
|
||||
|
||||
@ForceInline
|
||||
private final TypesAndInvokers getTypesAndInvokers() {
|
||||
TypesAndInvokers tis = typesAndInvokers;
|
||||
if (tis == null) {
|
||||
tis = typesAndInvokers = new TypesAndInvokers();
|
||||
}
|
||||
return tis;
|
||||
}
|
||||
|
||||
@ForceInline
|
||||
final MethodHandle getMethodHandle(int mode) {
|
||||
TypesAndInvokers tis = getTypesAndInvokers();
|
||||
MethodHandle mh = tis.methodHandle_table[mode];
|
||||
if (mh == null) {
|
||||
mh = tis.methodHandle_table[mode] = getMethodHandleUncached(tis, mode);
|
||||
}
|
||||
return mh;
|
||||
}
|
||||
private final MethodHandle getMethodHandleUncached(TypesAndInvokers tis, int mode) {
|
||||
MethodType mt = accessModeType(AccessMode.values()[mode]).
|
||||
insertParameterTypes(0, VarHandle.class);
|
||||
MemberName mn = vform.getMemberName(mode);
|
||||
DirectMethodHandle dmh = DirectMethodHandle.make(mn);
|
||||
// Such a method handle must not be publically exposed directly
|
||||
// otherwise it can be cracked, it must be transformed or rebound
|
||||
// before exposure
|
||||
MethodHandle mh = dmh.copyWith(mt, dmh.form);
|
||||
assert mh.type().erase() == mn.getMethodType().erase();
|
||||
return mh;
|
||||
}
|
||||
|
||||
|
||||
/*non-public*/
|
||||
final void updateVarForm(VarForm newVForm) {
|
||||
if (vform == newVForm) return;
|
||||
@ -1453,6 +1518,10 @@ public abstract class VarHandle {
|
||||
catch (ReflectiveOperationException e) {
|
||||
throw newInternalError(e);
|
||||
}
|
||||
|
||||
// The VarHandleGuards must be initialized to ensure correct
|
||||
// compilation of the guard methods
|
||||
UNSAFE.ensureClassInitialized(VarHandleGuards.class);
|
||||
}
|
||||
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -280,28 +280,29 @@ final class VarHandles {
|
||||
// "@ForceInline\n" +
|
||||
// "@LambdaForm.Compiled\n" +
|
||||
// "final static <METHOD> throws Throwable {\n" +
|
||||
// " MethodType target = VarHandle.AccessType.getMethodType(ad.type, handle);\n" +
|
||||
// " MethodType symbolic = ad.symbolicMethodType;\n" +
|
||||
// " if (target == symbolic) {\n" +
|
||||
// " <RETURN>MethodHandle.linkToStatic(<LINK_TO_STATIC_ARGS>);\n" +
|
||||
// " }\n" +
|
||||
// " else if (target.erase() == symbolic.erase()) {\n" +
|
||||
// " if (handle.vform.methodType_table[ad.type] == ad.symbolicMethodType) {\n" +
|
||||
// " <RESULT_ERASED>MethodHandle.linkToStatic(<LINK_TO_STATIC_ARGS>);<RETURN_ERASED>\n" +
|
||||
// " }\n" +
|
||||
// " else {\n" +
|
||||
// " MethodHandle vh_invoker = MethodHandles.varHandleInvoker(VarHandle.AccessMode.values()[ad.mode], symbolic);\n" +
|
||||
// " <RETURN>vh_invoker.invokeBasic(<LINK_TO_INVOKER_ARGS>);\n" +
|
||||
// " MethodHandle mh = handle.getMethodHandle(ad.mode);\n" +
|
||||
// " <RETURN>mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(<LINK_TO_INVOKER_ARGS>);\n" +
|
||||
// " }\n" +
|
||||
// "}";
|
||||
//
|
||||
// static final String GET_MEMBER_NAME_METHOD =
|
||||
// static final String GUARD_METHOD_TEMPLATE_V =
|
||||
// "@ForceInline\n" +
|
||||
// "final static MemberName getMemberName(VarHandle handle, VarHandle.AccessDescriptor ad) {\n" +
|
||||
// " MemberName mn = VarHandle.AccessMode.getMemberName(ad.mode, handle.vform);\n" +
|
||||
// " if (mn == null) {\n" +
|
||||
// " throw handle.unsupported();\n" +
|
||||
// "@LambdaForm.Compiled\n" +
|
||||
// "final static <METHOD> throws Throwable {\n" +
|
||||
// " if (handle.vform.methodType_table[ad.type] == ad.symbolicMethodType) {\n" +
|
||||
// " MethodHandle.linkToStatic(<LINK_TO_STATIC_ARGS>);\n" +
|
||||
// " }\n" +
|
||||
// " else if (handle.vform.getMethodType_V(ad.type) == ad.symbolicMethodType) {\n" +
|
||||
// " MethodHandle.linkToStatic(<LINK_TO_STATIC_ARGS>);\n" +
|
||||
// " }\n" +
|
||||
// " else {\n" +
|
||||
// " MethodHandle mh = handle.getMethodHandle(ad.mode);\n" +
|
||||
// " mh.asType(ad.symbolicMethodTypeInvoker).invokeBasic(<LINK_TO_INVOKER_ARGS>);\n" +
|
||||
// " }\n" +
|
||||
// " return mn;\n" +
|
||||
// "}";
|
||||
//
|
||||
// // A template for deriving the operations
|
||||
@ -345,8 +346,6 @@ final class VarHandles {
|
||||
// System.out.println("final class VarHandleGuards {");
|
||||
//
|
||||
// System.out.println();
|
||||
// System.out.println(GET_MEMBER_NAME_METHOD);
|
||||
// System.out.println();
|
||||
//
|
||||
// // Declare the stream of shapes
|
||||
// Stream<HandleType> hts = Stream.of(
|
||||
@ -445,7 +444,10 @@ final class VarHandles {
|
||||
//
|
||||
// List<String> LINK_TO_STATIC_ARGS = params.keySet().stream().
|
||||
// collect(toList());
|
||||
// LINK_TO_STATIC_ARGS.add("getMemberName(handle, ad)");
|
||||
// LINK_TO_STATIC_ARGS.add("handle.vform.getMemberName(ad.mode)");
|
||||
// List<String> LINK_TO_STATIC_ARGS_V = params.keySet().stream().
|
||||
// collect(toList());
|
||||
// LINK_TO_STATIC_ARGS_V.add("handle.vform.getMemberName_V(ad.mode)");
|
||||
//
|
||||
// List<String> LINK_TO_INVOKER_ARGS = params.keySet().stream().
|
||||
// collect(toList());
|
||||
@ -464,9 +466,12 @@ final class VarHandles {
|
||||
//
|
||||
// String RETURN_ERASED = returnType != Object.class
|
||||
// ? ""
|
||||
// : " return symbolic.returnType().cast(r);";
|
||||
// : " return ad.returnType.cast(r);";
|
||||
//
|
||||
// return GUARD_METHOD_TEMPLATE.
|
||||
// String template = returnType == void.class
|
||||
// ? GUARD_METHOD_TEMPLATE_V
|
||||
// : GUARD_METHOD_TEMPLATE;
|
||||
// return template.
|
||||
// replace("<METHOD>", METHOD).
|
||||
// replace("<NAME>", NAME).
|
||||
// replaceAll("<RETURN>", RETURN).
|
||||
@ -474,6 +479,8 @@ final class VarHandles {
|
||||
// replace("<RETURN_ERASED>", RETURN_ERASED).
|
||||
// replaceAll("<LINK_TO_STATIC_ARGS>", LINK_TO_STATIC_ARGS.stream().
|
||||
// collect(joining(", "))).
|
||||
// replaceAll("<LINK_TO_STATIC_ARGS_V>", LINK_TO_STATIC_ARGS_V.stream().
|
||||
// collect(joining(", "))).
|
||||
// replace("<LINK_TO_INVOKER_ARGS>", LINK_TO_INVOKER_ARGS.stream().
|
||||
// collect(joining(", ")))
|
||||
// ;
|
||||
|
@ -41,12 +41,12 @@ final class VarHandle$Type$s {
|
||||
#end[Object]
|
||||
|
||||
FieldInstanceReadOnly(Class<?> receiverType, long fieldOffset{#if[Object]?, Class<?> fieldType}) {
|
||||
this(receiverType, fieldOffset{#if[Object]?, fieldType}, FieldInstanceReadOnly.class);
|
||||
this(receiverType, fieldOffset{#if[Object]?, fieldType}, FieldInstanceReadOnly.FORM);
|
||||
}
|
||||
|
||||
protected FieldInstanceReadOnly(Class<?> receiverType, long fieldOffset{#if[Object]?, Class<?> fieldType},
|
||||
Class<? extends FieldInstanceReadOnly> handle) {
|
||||
super(VarForm.createFromStatic(handle), receiverType, {#if[Object]?fieldType:$type$.class});
|
||||
VarForm form) {
|
||||
super(form);
|
||||
this.fieldOffset = fieldOffset;
|
||||
this.receiverType = receiverType;
|
||||
#if[Object]
|
||||
@ -54,6 +54,11 @@ final class VarHandle$Type$s {
|
||||
#end[Object]
|
||||
}
|
||||
|
||||
@Override
|
||||
final MethodType accessModeTypeUncached(AccessMode accessMode) {
|
||||
return accessMode.at.accessModeType(receiverType, {#if[Object]?fieldType:$type$.class});
|
||||
}
|
||||
|
||||
@ForceInline
|
||||
static $type$ get(FieldInstanceReadOnly handle, Object holder) {
|
||||
return UNSAFE.get$Type$(Objects.requireNonNull(handle.receiverType.cast(holder)),
|
||||
@ -77,12 +82,14 @@ final class VarHandle$Type$s {
|
||||
return UNSAFE.get$Type$Acquire(Objects.requireNonNull(handle.receiverType.cast(holder)),
|
||||
handle.fieldOffset);
|
||||
}
|
||||
|
||||
static final VarForm FORM = new VarForm(FieldInstanceReadOnly.class, Object.class, $type$.class);
|
||||
}
|
||||
|
||||
static class FieldInstanceReadWrite extends FieldInstanceReadOnly {
|
||||
static final class FieldInstanceReadWrite extends FieldInstanceReadOnly {
|
||||
|
||||
FieldInstanceReadWrite(Class<?> receiverType, long fieldOffset{#if[Object]?, Class<?> fieldType}) {
|
||||
super(receiverType, fieldOffset{#if[Object]?, fieldType}, FieldInstanceReadWrite.class);
|
||||
super(receiverType, fieldOffset{#if[Object]?, fieldType}, FieldInstanceReadWrite.FORM);
|
||||
}
|
||||
|
||||
@ForceInline
|
||||
@ -202,6 +209,8 @@ final class VarHandle$Type$s {
|
||||
value) + value;
|
||||
}
|
||||
#end[AtomicAdd]
|
||||
|
||||
static final VarForm FORM = new VarForm(FieldInstanceReadWrite.class, Object.class, $type$.class);
|
||||
}
|
||||
|
||||
|
||||
@ -213,12 +222,12 @@ final class VarHandle$Type$s {
|
||||
#end[Object]
|
||||
|
||||
FieldStaticReadOnly(Object base, long fieldOffset{#if[Object]?, Class<?> fieldType}) {
|
||||
this(base, fieldOffset{#if[Object]?, fieldType}, FieldStaticReadOnly.class);
|
||||
this(base, fieldOffset{#if[Object]?, fieldType}, FieldStaticReadOnly.FORM);
|
||||
}
|
||||
|
||||
protected FieldStaticReadOnly(Object base, long fieldOffset{#if[Object]?, Class<?> fieldType},
|
||||
Class<? extends FieldStaticReadOnly> handle) {
|
||||
super(VarForm.createFromStatic(handle), null, {#if[Object]?fieldType:$type$.class});
|
||||
VarForm form) {
|
||||
super(form);
|
||||
this.base = base;
|
||||
this.fieldOffset = fieldOffset;
|
||||
#if[Object]
|
||||
@ -226,6 +235,11 @@ final class VarHandle$Type$s {
|
||||
#end[Object]
|
||||
}
|
||||
|
||||
@Override
|
||||
final MethodType accessModeTypeUncached(AccessMode accessMode) {
|
||||
return accessMode.at.accessModeType(null, {#if[Object]?fieldType:$type$.class});
|
||||
}
|
||||
|
||||
@ForceInline
|
||||
static $type$ get(FieldStaticReadOnly handle) {
|
||||
return UNSAFE.get$Type$(handle.base,
|
||||
@ -249,12 +263,14 @@ final class VarHandle$Type$s {
|
||||
return UNSAFE.get$Type$Acquire(handle.base,
|
||||
handle.fieldOffset);
|
||||
}
|
||||
|
||||
static final VarForm FORM = new VarForm(FieldStaticReadOnly.class, null, $type$.class);
|
||||
}
|
||||
|
||||
static class FieldStaticReadWrite extends FieldStaticReadOnly {
|
||||
static final class FieldStaticReadWrite extends FieldStaticReadOnly {
|
||||
|
||||
FieldStaticReadWrite(Object base, long fieldOffset{#if[Object]?, Class<?> fieldType}) {
|
||||
super(base, fieldOffset{#if[Object]?, fieldType}, FieldStaticReadWrite.class);
|
||||
super(base, fieldOffset{#if[Object]?, fieldType}, FieldStaticReadWrite.FORM);
|
||||
}
|
||||
|
||||
@ForceInline
|
||||
@ -375,6 +391,8 @@ final class VarHandle$Type$s {
|
||||
value) + value;
|
||||
}
|
||||
#end[AtomicAdd]
|
||||
|
||||
static final VarForm FORM = new VarForm(FieldStaticReadWrite.class, null, $type$.class);
|
||||
}
|
||||
|
||||
|
||||
@ -387,8 +405,7 @@ final class VarHandle$Type$s {
|
||||
#end[Object]
|
||||
|
||||
Array(int abase, int ashift{#if[Object]?, Class<?> arrayType}) {
|
||||
super(VarForm.createFromStatic(Array.class),
|
||||
{#if[Object]?arrayType:$type$[].class}, {#if[Object]?arrayType.getComponentType():$type$.class}, int.class);
|
||||
super(Array.FORM);
|
||||
this.abase = abase;
|
||||
this.ashift = ashift;
|
||||
#if[Object]
|
||||
@ -397,6 +414,11 @@ final class VarHandle$Type$s {
|
||||
#end[Object]
|
||||
}
|
||||
|
||||
@Override
|
||||
final MethodType accessModeTypeUncached(AccessMode accessMode) {
|
||||
return accessMode.at.accessModeType({#if[Object]?arrayType:$type$[].class}, {#if[Object]?arrayType.getComponentType():$type$.class}, int.class);
|
||||
}
|
||||
|
||||
@ForceInline
|
||||
static $type$ get(Array handle, Object oarray, int index) {
|
||||
#if[Object]
|
||||
@ -630,5 +652,7 @@ final class VarHandle$Type$s {
|
||||
value) + value;
|
||||
}
|
||||
#end[AtomicAdd]
|
||||
|
||||
static final VarForm FORM = new VarForm(Array.class, {#if[Object]?Object[].class:$type$[].class}, {#if[Object]?Object.class:$type$.class}, int.class);
|
||||
}
|
||||
}
|
||||
|
@ -59,13 +59,11 @@ final class VarHandleByteArrayAs$Type$s extends VarHandleByteArrayBase {
|
||||
#end[floatingPoint]
|
||||
|
||||
|
||||
private static class ByteArrayViewVarHandle extends VarHandle {
|
||||
private static abstract class ByteArrayViewVarHandle extends VarHandle {
|
||||
final boolean be;
|
||||
|
||||
ByteArrayViewVarHandle(Class<? extends ByteArrayViewVarHandle> implSubType,
|
||||
Class<?> arrayType, Class<?> component, boolean be) {
|
||||
super(VarForm.createFromStatic(implSubType),
|
||||
arrayType, component, int.class);
|
||||
ByteArrayViewVarHandle(VarForm form, boolean be) {
|
||||
super(form);
|
||||
this.be = be;
|
||||
}
|
||||
}
|
||||
@ -73,7 +71,12 @@ final class VarHandleByteArrayAs$Type$s extends VarHandleByteArrayBase {
|
||||
static final class ArrayHandle extends ByteArrayViewVarHandle {
|
||||
|
||||
ArrayHandle(boolean be) {
|
||||
super(ArrayHandle.class, byte[].class, $type$.class, be);
|
||||
super(ArrayHandle.FORM, be);
|
||||
}
|
||||
|
||||
@Override
|
||||
final MethodType accessModeTypeUncached(AccessMode accessMode) {
|
||||
return accessMode.at.accessModeType(byte[].class, $type$.class, int.class);
|
||||
}
|
||||
|
||||
@ForceInline
|
||||
@ -286,13 +289,20 @@ final class VarHandleByteArrayAs$Type$s extends VarHandleByteArrayBase {
|
||||
convEndian(handle.be, value))) + value;
|
||||
}
|
||||
#end[AtomicAdd]
|
||||
|
||||
static final VarForm FORM = new VarForm(ArrayHandle.class, byte[].class, $type$.class, int.class);
|
||||
}
|
||||
|
||||
|
||||
static final class ByteBufferHandle extends ByteArrayViewVarHandle {
|
||||
|
||||
ByteBufferHandle(boolean be) {
|
||||
super(ByteBufferHandle.class, ByteBuffer.class, $type$.class, be);
|
||||
super(ByteBufferHandle.FORM, be);
|
||||
}
|
||||
|
||||
@Override
|
||||
final MethodType accessModeTypeUncached(AccessMode accessMode) {
|
||||
return accessMode.at.accessModeType(ByteBuffer.class, $type$.class, int.class);
|
||||
}
|
||||
|
||||
@ForceInline
|
||||
@ -513,5 +523,7 @@ final class VarHandleByteArrayAs$Type$s extends VarHandleByteArrayBase {
|
||||
convEndian(handle.be, value))) + value;
|
||||
}
|
||||
#end[AtomicAdd]
|
||||
|
||||
static final VarForm FORM = new VarForm(ByteBufferHandle.class, ByteBuffer.class, $type$.class, int.class);
|
||||
}
|
||||
}
|
||||
|
@ -1536,7 +1536,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
|
||||
* be performed to generate a result with the specified scale, the
|
||||
* specified rounding mode is applied.
|
||||
*
|
||||
* <p>The new {@link #divide(BigDecimal, int, RoundingMode)} method
|
||||
* @deprecated The method {@link #divide(BigDecimal, int, RoundingMode)}
|
||||
* should be used in preference to this legacy method.
|
||||
*
|
||||
* @param divisor value by which this {@code BigDecimal} is to be divided.
|
||||
@ -1558,6 +1558,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
|
||||
* @see #ROUND_HALF_EVEN
|
||||
* @see #ROUND_UNNECESSARY
|
||||
*/
|
||||
@Deprecated(since="9")
|
||||
public BigDecimal divide(BigDecimal divisor, int scale, int roundingMode) {
|
||||
if (roundingMode < ROUND_UP || roundingMode > ROUND_UNNECESSARY)
|
||||
throw new IllegalArgumentException("Invalid rounding mode");
|
||||
@ -1602,7 +1603,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
|
||||
* rounding must be performed to generate a result with the given
|
||||
* scale, the specified rounding mode is applied.
|
||||
*
|
||||
* <p>The new {@link #divide(BigDecimal, RoundingMode)} method
|
||||
* @deprecated The method {@link #divide(BigDecimal, RoundingMode)}
|
||||
* should be used in preference to this legacy method.
|
||||
*
|
||||
* @param divisor value by which this {@code BigDecimal} is to be divided.
|
||||
@ -1623,6 +1624,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
|
||||
* @see #ROUND_HALF_EVEN
|
||||
* @see #ROUND_UNNECESSARY
|
||||
*/
|
||||
@Deprecated(since="9")
|
||||
public BigDecimal divide(BigDecimal divisor, int roundingMode) {
|
||||
return this.divide(divisor, scale, roundingMode);
|
||||
}
|
||||
@ -2267,14 +2269,20 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
|
||||
* Rounding mode to round away from zero. Always increments the
|
||||
* digit prior to a nonzero discarded fraction. Note that this rounding
|
||||
* mode never decreases the magnitude of the calculated value.
|
||||
*
|
||||
* @deprecated Use {@link RoundingMode#UP} instead.
|
||||
*/
|
||||
@Deprecated(since="9")
|
||||
public static final int ROUND_UP = 0;
|
||||
|
||||
/**
|
||||
* Rounding mode to round towards zero. Never increments the digit
|
||||
* prior to a discarded fraction (i.e., truncates). Note that this
|
||||
* rounding mode never increases the magnitude of the calculated value.
|
||||
*
|
||||
* @deprecated Use {@link RoundingMode#DOWN} instead.
|
||||
*/
|
||||
@Deprecated(since="9")
|
||||
public static final int ROUND_DOWN = 1;
|
||||
|
||||
/**
|
||||
@ -2283,7 +2291,10 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
|
||||
* {@code ROUND_UP}; if negative, behaves as for
|
||||
* {@code ROUND_DOWN}. Note that this rounding mode never
|
||||
* decreases the calculated value.
|
||||
*
|
||||
* @deprecated Use {@link RoundingMode#CEILING} instead.
|
||||
*/
|
||||
@Deprecated(since="9")
|
||||
public static final int ROUND_CEILING = 2;
|
||||
|
||||
/**
|
||||
@ -2292,7 +2303,10 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
|
||||
* {@code ROUND_DOWN}; if negative, behave as for
|
||||
* {@code ROUND_UP}. Note that this rounding mode never
|
||||
* increases the calculated value.
|
||||
*
|
||||
* @deprecated Use {@link RoundingMode#FLOOR} instead.
|
||||
*/
|
||||
@Deprecated(since="9")
|
||||
public static final int ROUND_FLOOR = 3;
|
||||
|
||||
/**
|
||||
@ -2302,7 +2316,10 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
|
||||
* ≥ 0.5; otherwise, behaves as for {@code ROUND_DOWN}. Note
|
||||
* that this is the rounding mode that most of us were taught in
|
||||
* grade school.
|
||||
*
|
||||
* @deprecated Use {@link RoundingMode#HALF_UP} instead.
|
||||
*/
|
||||
@Deprecated(since="9")
|
||||
public static final int ROUND_HALF_UP = 4;
|
||||
|
||||
/**
|
||||
@ -2311,7 +2328,10 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
|
||||
* down. Behaves as for {@code ROUND_UP} if the discarded
|
||||
* fraction is {@literal >} 0.5; otherwise, behaves as for
|
||||
* {@code ROUND_DOWN}.
|
||||
*
|
||||
* @deprecated Use {@link RoundingMode#HALF_DOWN} instead.
|
||||
*/
|
||||
@Deprecated(since="9")
|
||||
public static final int ROUND_HALF_DOWN = 5;
|
||||
|
||||
/**
|
||||
@ -2323,7 +2343,10 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
|
||||
* {@code ROUND_HALF_DOWN} if it's even. Note that this is the
|
||||
* rounding mode that minimizes cumulative error when applied
|
||||
* repeatedly over a sequence of calculations.
|
||||
*
|
||||
* @deprecated Use {@link RoundingMode#HALF_EVEN} instead.
|
||||
*/
|
||||
@Deprecated(since="9")
|
||||
public static final int ROUND_HALF_EVEN = 6;
|
||||
|
||||
/**
|
||||
@ -2331,7 +2354,10 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
|
||||
* result, hence no rounding is necessary. If this rounding mode is
|
||||
* specified on an operation that yields an inexact result, an
|
||||
* {@code ArithmeticException} is thrown.
|
||||
*
|
||||
* @deprecated Use {@link RoundingMode#UNNECESSARY} instead.
|
||||
*/
|
||||
@Deprecated(since="9")
|
||||
public static final int ROUND_UNNECESSARY = 7;
|
||||
|
||||
|
||||
@ -2408,7 +2434,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
|
||||
* Instead, {@code setScale} returns an object with the proper
|
||||
* scale; the returned object may or may not be newly allocated.
|
||||
*
|
||||
* <p>The new {@link #setScale(int, RoundingMode)} method should
|
||||
* @deprecated The method {@link #setScale(int, RoundingMode)} should
|
||||
* be used in preference to this legacy method.
|
||||
*
|
||||
* @param newScale scale of the {@code BigDecimal} value to be returned.
|
||||
@ -2431,6 +2457,7 @@ public class BigDecimal extends Number implements Comparable<BigDecimal> {
|
||||
* @see #ROUND_HALF_EVEN
|
||||
* @see #ROUND_UNNECESSARY
|
||||
*/
|
||||
@Deprecated(since="9")
|
||||
public BigDecimal setScale(int newScale, int roundingMode) {
|
||||
if (roundingMode < ROUND_UP || roundingMode > ROUND_UNNECESSARY)
|
||||
throw new IllegalArgumentException("Invalid rounding mode");
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -90,6 +90,7 @@ package java.math;
|
||||
* @author Joseph D. Darcy
|
||||
* @since 1.5
|
||||
*/
|
||||
@SuppressWarnings("deprecation") // Legacy rounding mode constants in BigDecimal
|
||||
public enum RoundingMode {
|
||||
|
||||
/**
|
||||
|
@ -0,0 +1,543 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.security;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* This class specifies the parameters used by a DRBG (Deterministic
|
||||
* Random Bit Generator).
|
||||
* <p>
|
||||
* According to
|
||||
* <a href="http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-90Ar1.pdf">
|
||||
* NIST Special Publication 800-90A Revision 1, Recommendation for Random
|
||||
* Number Generation Using Deterministic Random Bit Generators</a> (800-90Ar1),
|
||||
* <blockquote>
|
||||
* A DRBG is based on a DRBG mechanism as specified in this Recommendation
|
||||
* and includes a source of randomness. A DRBG mechanism uses an algorithm
|
||||
* (i.e., a DRBG algorithm) that produces a sequence of bits from an initial
|
||||
* value that is determined by a seed that is determined from the output of
|
||||
* the randomness source."
|
||||
* </blockquote>
|
||||
* <p>
|
||||
* The 800-90Ar1 specification allows for a variety of DRBG implementation
|
||||
* choices, such as:
|
||||
* <ul>
|
||||
* <li> an entropy source,
|
||||
* <li> a DRBG mechanism (for example, Hash_DRBG),
|
||||
* <li> a DRBG algorithm (for example, SHA-256 for Hash_DRBG and AES-256
|
||||
* for CTR_DRBG. Please note that it is not the algorithm used in
|
||||
* {@link SecureRandom#getInstance}, which we will call a
|
||||
* <em>SecureRandom algorithm</em> below),
|
||||
* <li> optionally features, including prediction resistance
|
||||
* and reseeding supports.
|
||||
* <li> highest security strength.
|
||||
* </ul>
|
||||
* <p>
|
||||
* These choices are set in each implementation and are not directly
|
||||
* managed by the {@code SecureRandom} API. Check your DRBG provider's
|
||||
* documentation to find an appropriate implementation for the situation.
|
||||
* <p>
|
||||
* On the other hand, the 800-90Ar1 specification does have some configurable
|
||||
* options, such as:
|
||||
* <ul>
|
||||
* <li> required security strength,
|
||||
* <li> if prediction resistance is required,
|
||||
* <li> personalization string and additional input.
|
||||
* </ul>
|
||||
* <p>
|
||||
* A DRBG instance can be instantiated with parameters from an
|
||||
* {@link DrbgParameters.Instantiation} object and other information
|
||||
* (for example, the nonce, which is not managed by this API). This maps
|
||||
* to the {@code Instantiate_function} defined in NIST SP 800-90Ar1.
|
||||
* <p>
|
||||
* A DRBG instance can be reseeded with parameters from a
|
||||
* {@link DrbgParameters.Reseed} object. This maps to the
|
||||
* {@code Reseed_function} defined in NIST SP 800-90Ar1. Calling
|
||||
* {@link SecureRandom#reseed()} is equivalent to calling
|
||||
* {@link SecureRandom#reseed(SecureRandomParameters)} with the effective
|
||||
* instantiated prediction resistance flag (as returned by
|
||||
* {@link SecureRandom#getParameters()}) with no additional input.
|
||||
* <p>
|
||||
* A DRBG instance generates data with additional parameters from a
|
||||
* {@link DrbgParameters.NextBytes} object. This maps to the
|
||||
* {@code Generate_function} defined in NIST SP 800-90Ar1. Calling
|
||||
* {@link SecureRandom#nextBytes(byte[])} is equivalent to calling
|
||||
* {@link SecureRandom#nextBytes(byte[], SecureRandomParameters)}
|
||||
* with the effective instantiated strength and prediction resistance flag
|
||||
* (as returned by {@link SecureRandom#getParameters()}) with no
|
||||
* additional input.
|
||||
* <p>
|
||||
* A DRBG should be implemented as a subclass of {@link SecureRandomSpi}.
|
||||
* It is recommended that the implementation contain the 1-arg
|
||||
* {@linkplain SecureRandomSpi#SecureRandomSpi(SecureRandomParameters) constructor}
|
||||
* that takes a {@code DrbgParameters.Instantiation} argument. If implemented
|
||||
* this way, this implementation can be chosen by any
|
||||
* {@code SecureRandom.getInstance()} method. If it is chosen by a
|
||||
* {@code SecureRandom.getInstance()} with a {@link SecureRandomParameters}
|
||||
* parameter, the parameter is passed into this constructor. If it is chosen
|
||||
* by a {@code SecureRandom.getInstance()} without a
|
||||
* {@code SecureRandomParameters} parameter, the constructor is called with
|
||||
* a {@code null} argument and the implementation should choose its own
|
||||
* parameters. Its {@link SecureRandom#getParameters()} must always return a
|
||||
* non-null effective {@code DrbgParameters.Instantiation} object that reflects
|
||||
* how the DRBG is actually instantiated. A caller can use this information
|
||||
* to determine whether a {@code SecureRandom} object is a DRBG and what
|
||||
* features it supports. Please note that the returned value does not
|
||||
* necessarily equal to the {@code DrbgParameters.Instantiation} object passed
|
||||
* into the {@code SecureRandom.getInstance()} call. For example,
|
||||
* the requested capability can be {@link DrbgParameters.Capability#NONE}
|
||||
* but the effective value can be {@link DrbgParameters.Capability#RESEED_ONLY}
|
||||
* if the implementation supports reseeding. The implementation must implement
|
||||
* the {@link SecureRandomSpi#engineNextBytes(byte[], SecureRandomParameters)}
|
||||
* method which takes a {@code DrbgParameters.NextBytes} parameter. Unless
|
||||
* the result of {@link SecureRandom#getParameters()} has its
|
||||
* {@linkplain DrbgParameters.Instantiation#getCapability() capability} being
|
||||
* {@link Capability#NONE NONE}, it must implement
|
||||
* {@link SecureRandomSpi#engineReseed(SecureRandomParameters)} which takes
|
||||
* a {@code DrbgParameters.Reseed} parameter.
|
||||
* <p>
|
||||
* On the other hand, if a DRBG implementation does not contain a constructor
|
||||
* that has an {@code DrbgParameters.Instantiation} argument (not recommended),
|
||||
* it can only be chosen by a {@code SecureRandom.getInstance()} without
|
||||
* a {@code SecureRandomParameters} parameter, but will not be chosen if
|
||||
* a {@code getInstance} method with a {@code SecureRandomParameters} parameter
|
||||
* is called. If implemented this way, its {@link SecureRandom#getParameters()}
|
||||
* must return {@code null}, and it does not need to implement either
|
||||
* {@link SecureRandomSpi#engineNextBytes(byte[], SecureRandomParameters)}
|
||||
* or {@link SecureRandomSpi#engineReseed(SecureRandomParameters)}.
|
||||
* <p>
|
||||
* A DRBG might reseed itself automatically if the seed period is bigger
|
||||
* than the maximum seed life defined by the DRBG mechanism.
|
||||
* <p>
|
||||
* A DRBG implementation should support serialization and deserialization
|
||||
* by retaining the configuration and effective parameters, but the internal
|
||||
* state must not be serialized and the deserialized object must be
|
||||
* reinstantiated.
|
||||
* <p>
|
||||
* Examples:
|
||||
* <blockquote><pre>
|
||||
* SecureRandom drbg;
|
||||
* byte[] buffer = new byte[32];
|
||||
*
|
||||
* // Any DRBG is OK
|
||||
* drbg = SecureRandom.getInstance("DRBG");
|
||||
* drbg.nextBytes(buffer);
|
||||
*
|
||||
* SecureRandomParameters params = drbg.getParameters();
|
||||
* if (params instanceof DrbgParameters.Instantiation) {
|
||||
* DrbgParameters.Instantiation ins = (DrbgParameters.Instantiation) params;
|
||||
* if (ins.getCapability().supportsReseeding()) {
|
||||
* drbg.reseed();
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* // The following call requests a weak DRBG instance. It is only
|
||||
* // guaranteed to support 112 bits of security strength.
|
||||
* drbg = SecureRandom.getInstance("DRBG",
|
||||
* DrbgParameters.instantiation(112, NONE, null));
|
||||
*
|
||||
* // Both the next two calls will likely fail, because drbg could be
|
||||
* // instantiated with a smaller strength with no prediction resistance
|
||||
* // support.
|
||||
* drbg.nextBytes(buffer,
|
||||
* DrbgParameters.nextBytes(256, false, "more".getBytes()));
|
||||
* drbg.nextBytes(buffer,
|
||||
* DrbgParameters.nextBytes(112, true, "more".getBytes()));
|
||||
*
|
||||
* // The following call requests a strong DRBG instance, with a
|
||||
* // personalization string. If it successfully returns an instance,
|
||||
* // that instance is guaranteed to support 256 bits of security strength
|
||||
* // with prediction resistance available.
|
||||
* drbg = SecureRandom.getInstance("DRBG", DrbgParameters.instantiation(
|
||||
* 256, PR_AND_RESEED, "hello".getBytes()));
|
||||
*
|
||||
* // Prediction resistance is not requested in this single call,
|
||||
* // but an additional input is used.
|
||||
* drbg.nextBytes(buffer,
|
||||
* DrbgParameters.nextBytes(-1, false, "more".getBytes()));
|
||||
*
|
||||
* // Same for this call.
|
||||
* drbg.reseed(DrbgParameters.reseed(false, "extra".getBytes()));</pre>
|
||||
* </blockquote>
|
||||
*
|
||||
* @implSpec
|
||||
* By convention, a provider should name its primary DRBG implementation
|
||||
* with the <a href=
|
||||
* "{@docRoot}/../technotes/guides/security/StandardNames.html#SecureRandom">
|
||||
* standard {@code SecureRandom} algorithm name</a> "DRBG".
|
||||
*
|
||||
* @implNote
|
||||
* The following notes apply to the "DRBG" implementation in the SUN provider
|
||||
* of the JDK reference implementation.
|
||||
* <p>
|
||||
* This implementation supports the Hash_DRBG and HMAC_DRBG mechanisms with
|
||||
* DRBG algorithm SHA-1, SHA-224, SHA-512/224, SHA-256, SHA-512/256,
|
||||
* SHA-384 and SHA-512, and CTR_DRBG (both using derivation function and
|
||||
* not using derivation function) with DRBG algorithm 3KeyTDEA
|
||||
* (also known as DESede in JCE), AES-128, AES-192 and AES-256.
|
||||
* <p>
|
||||
* The mechanism name and DRBG algorithm name are determined by the
|
||||
* {@linkplain Security#getProperty(String) security property}
|
||||
* {@code securerandom.drbg.config}. The default choice is Hash_DRBG
|
||||
* with SHA-256.
|
||||
* <p>
|
||||
* For each combination, the security strength can be requested from 112
|
||||
* up to the highest strength it supports. Both reseeding and prediction
|
||||
* resistance are supported.
|
||||
* <p>
|
||||
* Personalization string is supported through the
|
||||
* {@link DrbgParameters.Instantiation} class and additional input is supported
|
||||
* through the {@link DrbgParameters.NextBytes} and
|
||||
* {@link DrbgParameters.Reseed} classes.
|
||||
* <p>
|
||||
* If a DRBG is not instantiated with a {@link DrbgParameters.Instantiation}
|
||||
* object explicitly, this implementation instantiates it with a default
|
||||
* requested strength of 128 bits (112 bits for CTR_DRBG with 3KeyTDEA),
|
||||
* no prediction resistance request, and no personalization string.
|
||||
* These default instantiation parameters can also be customized with
|
||||
* the {@code securerandom.drbg.config} security property.
|
||||
* <p>
|
||||
* This implementation reads fresh entropy from the system default entropy
|
||||
* source determined by the security property {@code securerandom.source}.
|
||||
* <p>
|
||||
* Calling {@link SecureRandom#generateSeed(int)} will directly read
|
||||
* from this system default entropy source.
|
||||
* <p>
|
||||
* This implementation has passed all tests included in the 20151104 version of
|
||||
* <a href="http://csrc.nist.gov/groups/STM/cavp/documents/drbg/drbgtestvectors.zip">
|
||||
* The DRBG Test Vectors</a>.
|
||||
*
|
||||
* @since 9
|
||||
*/
|
||||
public class DrbgParameters {
|
||||
|
||||
private DrbgParameters() {
|
||||
// This class should not be instantiated
|
||||
}
|
||||
|
||||
/**
|
||||
* The reseedable and prediction resistance capabilities of a DRBG.
|
||||
* <p>
|
||||
* When this object is passed to a {@code SecureRandom.getInstance()} call,
|
||||
* it is the requested minimum capability. When it's returned from
|
||||
* {@code SecureRandom.getParameters()}, it is the effective capability.
|
||||
* <p>
|
||||
* Please note that while the {@code Instantiate_function} defined in
|
||||
* NIST SP 800-90Ar1 only includes a {@code prediction_resistance_flag}
|
||||
* parameter, the {@code Capability} type includes an extra value
|
||||
* {@link #RESEED_ONLY} because reseeding is an optional function.
|
||||
* If {@code NONE} is used in an {@code Instantiation} object in calling the
|
||||
* {@code SecureRandom.getInstance} method, the returned DRBG instance
|
||||
* is not guaranteed to support reseeding. If {@code RESEED_ONLY} or
|
||||
* {@code PR_AND_RESEED} is used, the instance must support reseeding.
|
||||
* <p>
|
||||
* The table below lists possible effective values if a certain
|
||||
* capability is requested, i.e.
|
||||
* <blockquote><pre>
|
||||
* Capability requested = ...;
|
||||
* SecureRandom s = SecureRandom.getInstance("DRBG",
|
||||
* DrbgParameters(-1, requested, null));
|
||||
* Capability effective = ((DrbgParametes.Initiate) s.getParameters())
|
||||
* .getCapability();</pre>
|
||||
* </blockquote>
|
||||
* <table border=1 summary="requested and effective capabilities">
|
||||
* <tr>
|
||||
* <th>Requested Value</th>
|
||||
* <th>Possible Effective Values</th>
|
||||
* </tr>
|
||||
* <tr><td>NONE</td><td>NONE, RESEED_ONLY, PR_AND_RESEED</td></tr>
|
||||
* <tr><td>RESEED_ONLY</td><td>RESEED_ONLY, PR_AND_RESEED</td></tr>
|
||||
* <tr><td>PR_AND_RESEED</td><td>PR_AND_RESEED</td></tr>
|
||||
* </table>
|
||||
* <p>
|
||||
* A DRBG implementation supporting prediction resistance must also
|
||||
* support reseeding.
|
||||
*
|
||||
* @since 9
|
||||
*/
|
||||
public enum Capability {
|
||||
|
||||
/**
|
||||
* Both prediction resistance and reseed.
|
||||
*/
|
||||
PR_AND_RESEED,
|
||||
|
||||
/**
|
||||
* Reseed but no prediction resistance.
|
||||
*/
|
||||
RESEED_ONLY,
|
||||
|
||||
/**
|
||||
* Neither prediction resistance nor reseed.
|
||||
*/
|
||||
NONE;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name().toLowerCase(Locale.ROOT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this capability supports reseeding.
|
||||
*
|
||||
* @return {@code true} for {@link #PR_AND_RESEED} and
|
||||
* {@link #RESEED_ONLY}, and {@code false} for {@link #NONE}
|
||||
*/
|
||||
public boolean supportsReseeding() {
|
||||
return this != NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this capability supports prediction resistance.
|
||||
*
|
||||
* @return {@code true} for {@link #PR_AND_RESEED}, and {@code false}
|
||||
* for {@link #RESEED_ONLY} and {@link #NONE}
|
||||
*/
|
||||
public boolean supportsPredictionResistance() {
|
||||
return this == PR_AND_RESEED;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* DRBG parameters for instantiation.
|
||||
* <p>
|
||||
* When used in
|
||||
* {@link SecureRandom#getInstance(String, SecureRandomParameters)}
|
||||
* or one of the other similar {@code getInstance} calls that take a
|
||||
* {@code SecureRandomParameters} parameter, it means the
|
||||
* requested instantiate parameters the newly created {@code SecureRandom}
|
||||
* object must minimally support. When used as the return value of the
|
||||
* {@link SecureRandom#getParameters()} method, it means the effective
|
||||
* instantiate parameters of the {@code SecureRandom} object.
|
||||
*
|
||||
* @since 9
|
||||
*/
|
||||
public static final class Instantiation
|
||||
implements SecureRandomParameters {
|
||||
|
||||
private final int strength;
|
||||
private final Capability capability;
|
||||
private final byte[] personalizationString;
|
||||
|
||||
/**
|
||||
* Returns the security strength in bits.
|
||||
*
|
||||
* @return If used in {@code getInstance}, returns the minimum strength
|
||||
* requested, or -1 if there is no specific request on the strength.
|
||||
* If used in {@code getParameters}, returns the effective strength.
|
||||
* The effective strength must be greater than or equal to the minimum
|
||||
* strength requested.
|
||||
*/
|
||||
public int getStrength() {
|
||||
return strength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the capability.
|
||||
*
|
||||
* @return If used in {@code getInstance}, returns the minimum
|
||||
* capability requested. If used in {@code getParameters}, returns
|
||||
* information on the effective prediction resistance flag and
|
||||
* whether it supports reseeding.
|
||||
*/
|
||||
public Capability getCapability() {
|
||||
return capability;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the personalization string as a byte array.
|
||||
*
|
||||
* @return If used in {@code getInstance}, returns the requested
|
||||
* personalization string as a newly allocated array, or {@code null}
|
||||
* if no personalization string is requested. The same string should
|
||||
* be returned in {@code getParameters} as a new copy, or {@code null}
|
||||
* if no personalization string is requested in {@code getInstance}.
|
||||
*/
|
||||
public byte[] getPersonalizationString() {
|
||||
return (personalizationString == null) ?
|
||||
null : personalizationString.clone();
|
||||
}
|
||||
|
||||
private Instantiation(int strength, Capability capability,
|
||||
byte[] personalizationString) {
|
||||
this.strength = strength;
|
||||
this.capability = capability;
|
||||
this.personalizationString = (personalizationString == null) ?
|
||||
null : personalizationString.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Human-readable string representation of this
|
||||
* {@code Instantiation}.
|
||||
*
|
||||
* @return the string representation
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
// I don't care what personalizationString looks like
|
||||
return strength + "," + capability + "," + personalizationString;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* DRBG parameters for random bits generation. It is used in
|
||||
* {@link SecureRandom#nextBytes(byte[], SecureRandomParameters)}.
|
||||
*
|
||||
* @since 9
|
||||
*/
|
||||
public static final class NextBytes
|
||||
implements SecureRandomParameters {
|
||||
private final int strength;
|
||||
private final boolean predictionResistance;
|
||||
private final byte[] additionalInput;
|
||||
|
||||
/**
|
||||
* Returns the security strength requested in bits.
|
||||
*
|
||||
* @return the strength requested, or -1 if the effective strength
|
||||
* should be used.
|
||||
*/
|
||||
public int getStrength() {
|
||||
return strength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether prediction resistance is requested.
|
||||
*
|
||||
* @return whether prediction resistance is requested
|
||||
*/
|
||||
public boolean getPredictionResistance() {
|
||||
return predictionResistance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the requested additional input.
|
||||
*
|
||||
* @return the requested additional input, {@code null} if not
|
||||
* requested. A new byte array is returned each time this method
|
||||
* is called.
|
||||
*/
|
||||
public byte[] getAdditionalInput() {
|
||||
return additionalInput == null? null: additionalInput.clone();
|
||||
}
|
||||
|
||||
private NextBytes(int strength, boolean predictionResistance,
|
||||
byte[] additionalInput) {
|
||||
this.strength = strength;
|
||||
this.predictionResistance = predictionResistance;
|
||||
this.additionalInput = (additionalInput == null) ?
|
||||
null : additionalInput.clone();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* DRBG parameters for reseed. It is used in
|
||||
* {@link SecureRandom#reseed(SecureRandomParameters)}.
|
||||
*
|
||||
* @since 9
|
||||
*/
|
||||
public static final class Reseed implements SecureRandomParameters {
|
||||
|
||||
private final byte[] additionalInput;
|
||||
private final boolean predictionResistance;
|
||||
|
||||
/**
|
||||
* Returns whether prediction resistance is requested.
|
||||
*
|
||||
* @return whether prediction resistance is requested
|
||||
*/
|
||||
public boolean getPredictionResistance() {
|
||||
return predictionResistance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the requested additional input.
|
||||
*
|
||||
* @return the requested additional input, or {@code null} if
|
||||
* not requested. A new byte array is returned each time this method
|
||||
* is called.
|
||||
*/
|
||||
public byte[] getAdditionalInput() {
|
||||
return additionalInput == null ? null : additionalInput.clone();
|
||||
}
|
||||
|
||||
private Reseed(boolean predictionResistance, byte[] additionalInput) {
|
||||
this.predictionResistance = predictionResistance;
|
||||
this.additionalInput = (additionalInput == null) ?
|
||||
null : additionalInput.clone();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a {@link DrbgParameters.Instantiation} object.
|
||||
*
|
||||
* @param strength security strength in bits, -1 for default strength
|
||||
* if used in {@code getInstance}.
|
||||
* @param capability capability
|
||||
* @param personalizationString personalization string as a byte array,
|
||||
* can be {@code null}. The content of this
|
||||
* byte array will be copied.
|
||||
* @return a new {@code Instantiation} object
|
||||
* @throws NullPointerException if {@code capability} is {@code null}
|
||||
*/
|
||||
public static Instantiation instantiation(int strength,
|
||||
Capability capability,
|
||||
byte[] personalizationString) {
|
||||
return new Instantiation(strength, Objects.requireNonNull(capability),
|
||||
personalizationString);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a {@link NextBytes} object.
|
||||
*
|
||||
* @param strength requested security strength in bits. If set to -1, the
|
||||
* effective strength will be used.
|
||||
* @param predictionResistance prediction resistance requested
|
||||
* @param additionalInput additional input, can be {@code null}.
|
||||
* The content of this byte array will be copied.
|
||||
* @return a new {@code NextBytes} object
|
||||
*/
|
||||
public static NextBytes nextBytes(int strength,
|
||||
boolean predictionResistance,
|
||||
byte[] additionalInput) {
|
||||
return new NextBytes(strength, predictionResistance, additionalInput);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a {@link Reseed} object.
|
||||
*
|
||||
* @param predictionResistance prediction resistance requested
|
||||
* @param additionalInput additional input, can be {@code null}.
|
||||
* The content of this byte array will be copied.
|
||||
* @return a new {@code Reseed} object
|
||||
*/
|
||||
public static Reseed reseed(
|
||||
boolean predictionResistance, byte[] additionalInput) {
|
||||
return new Reseed(predictionResistance, additionalInput);
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved
|
||||
* Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -142,8 +142,35 @@ public abstract class Provider extends Properties {
|
||||
Constructor<?> con = clazz.getConstructor();
|
||||
return con.newInstance();
|
||||
} else {
|
||||
Constructor<?> con = clazz.getConstructor(ctrParamClz);
|
||||
return con.newInstance(ctorParamObj);
|
||||
// Looking for the constructor with a params first and fallback
|
||||
// to one without if not found. This is to support the enhanced
|
||||
// SecureRandom where both styles of constructors are supported.
|
||||
// Before jdk9, there was no params support (only getInstance(alg))
|
||||
// and an impl only had the params-less constructor. Since jdk9,
|
||||
// there is getInstance(alg,params) and an impl can contain
|
||||
// an Impl(params) constructor.
|
||||
try {
|
||||
Constructor<?> con = clazz.getConstructor(ctrParamClz);
|
||||
return con.newInstance(ctorParamObj);
|
||||
} catch (NoSuchMethodException nsme) {
|
||||
// For pre-jdk9 SecureRandom implementations, they only
|
||||
// have params-less constructors which still works when
|
||||
// the input ctorParamObj is null.
|
||||
//
|
||||
// For other primitives using params, ctorParamObj should not
|
||||
// be null and nsme is thrown, just like before.
|
||||
if (ctorParamObj == null) {
|
||||
try {
|
||||
Constructor<?> con = clazz.getConstructor();
|
||||
return con.newInstance();
|
||||
} catch (NoSuchMethodException nsme2) {
|
||||
nsme.addSuppressed(nsme2);
|
||||
throw nsme;
|
||||
}
|
||||
} else {
|
||||
throw nsme;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1384,7 +1411,8 @@ public abstract class Provider extends Properties {
|
||||
addEngine("KeyPairGenerator", false, null);
|
||||
addEngine("KeyStore", false, null);
|
||||
addEngine("MessageDigest", false, null);
|
||||
addEngine("SecureRandom", false, null);
|
||||
addEngine("SecureRandom", false,
|
||||
"java.security.SecureRandomParameters");
|
||||
addEngine("Signature", true, null);
|
||||
addEngine("CertificateFactory", false, null);
|
||||
addEngine("CertPathBuilder", false, null);
|
||||
@ -1678,6 +1706,7 @@ public abstract class Provider extends Properties {
|
||||
}
|
||||
}
|
||||
}
|
||||
// constructorParameter can be null if not provided
|
||||
return newInstanceUtil(getImplClass(), ctrParamClz, constructorParameter);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw e;
|
||||
|
@ -38,52 +38,87 @@ import sun.security.util.Debug;
|
||||
* This class provides a cryptographically strong random number
|
||||
* generator (RNG).
|
||||
*
|
||||
* <p>A cryptographically strong random number
|
||||
* minimally complies with the statistical random number generator tests
|
||||
* specified in
|
||||
* <p>A cryptographically strong random number minimally complies with the
|
||||
* statistical random number generator tests specified in
|
||||
* <a href="http://csrc.nist.gov/publications/fips/fips140-2/fips1402.pdf">
|
||||
* <i>FIPS 140-2, Security Requirements for Cryptographic Modules</i></a>,
|
||||
* section 4.9.1.
|
||||
* Additionally, SecureRandom must produce non-deterministic output.
|
||||
* Therefore any seed material passed to a SecureRandom object must be
|
||||
* unpredictable, and all SecureRandom output sequences must be
|
||||
* Additionally, {@code SecureRandom} must produce non-deterministic output.
|
||||
* Therefore any seed material passed to a {@code SecureRandom} object must be
|
||||
* unpredictable, and all {@code SecureRandom} output sequences must be
|
||||
* cryptographically strong, as described in
|
||||
* <a href="http://tools.ietf.org/html/rfc4086">
|
||||
* <i>RFC 4086: Randomness Requirements for Security</i></a>.
|
||||
*
|
||||
* <p>A caller obtains a SecureRandom instance via the
|
||||
* no-argument constructor or one of the {@code getInstance} methods:
|
||||
*
|
||||
* <pre>
|
||||
* SecureRandom random = new SecureRandom();
|
||||
* </pre>
|
||||
*
|
||||
* <p> Many SecureRandom implementations are in the form of a pseudo-random
|
||||
* number generator (PRNG), which means they use a deterministic algorithm
|
||||
* to produce a pseudo-random sequence from a true random seed.
|
||||
* <p> Many {@code SecureRandom} implementations are in the form of a
|
||||
* pseudo-random number generator (PRNG, also known as deterministic random
|
||||
* bits generator or DRBG), which means they use a deterministic algorithm
|
||||
* to produce a pseudo-random sequence from a random seed.
|
||||
* Other implementations may produce true random numbers,
|
||||
* and yet others may use a combination of both techniques.
|
||||
*
|
||||
* <p> Typical callers of SecureRandom invoke the following methods
|
||||
* <p>A caller obtains a {@code SecureRandom} instance via the
|
||||
* no-argument constructor or one of the {@code getInstance} methods.
|
||||
* For example:
|
||||
*
|
||||
* <blockquote><pre>
|
||||
* SecureRandom r1 = new SecureRandom();
|
||||
* SecureRandom r2 = SecureRandom.getInstance("NativePRNG");
|
||||
* SecureRandom r3 = SecureRandom("DRBG",
|
||||
* DrbgParameters.Instantiation(128, RESEED_ONLY, null));</pre>
|
||||
* </blockquote>
|
||||
*
|
||||
* <p> The third statement above returns a {@code SecureRandom} object of the
|
||||
* specific algorithm supporting the specific instantiate parameters. The
|
||||
* implementation's effective instantiated parameters must match this minimum
|
||||
* request but is not necessarily the same. For example, even if the request
|
||||
* does not require a certain feature, the actual instantiation can provide
|
||||
* the feature. An implementation may lazily instantiate a {@code SecureRandom}
|
||||
* until it's actually used, but the effective instantiate parameters must be
|
||||
* determined right after it's created and {@link #getParameters()} should
|
||||
* always return the same result unchanged.
|
||||
*
|
||||
* <p> Typical callers of {@code SecureRandom} invoke the following methods
|
||||
* to retrieve random bytes:
|
||||
*
|
||||
* <pre>
|
||||
* SecureRandom random = new SecureRandom();
|
||||
* byte[] bytes = new byte[20];
|
||||
* random.nextBytes(bytes);
|
||||
* </pre>
|
||||
* <blockquote><pre>
|
||||
* SecureRandom random = new SecureRandom();
|
||||
* byte[] bytes = new byte[20];
|
||||
* random.nextBytes(bytes);</pre>
|
||||
* </blockquote>
|
||||
*
|
||||
* <p> Callers may also invoke the {@code generateSeed} method
|
||||
* <p> Callers may also invoke the {@link #generateSeed} method
|
||||
* to generate a given number of seed bytes (to seed other random number
|
||||
* generators, for example):
|
||||
* <pre>
|
||||
* byte[] seed = random.generateSeed(20);
|
||||
* </pre>
|
||||
*
|
||||
* Note: Depending on the implementation, the {@code generateSeed} and
|
||||
* {@code nextBytes} methods may block as entropy is being gathered,
|
||||
* for example, if they need to read from /dev/random on various Unix-like
|
||||
* operating systems.
|
||||
* <blockquote><pre>
|
||||
* byte[] seed = random.generateSeed(20);</pre>
|
||||
* </blockquote>
|
||||
*
|
||||
* <p> A newly created PRNG {@code SecureRandom} object is not seeded (except
|
||||
* if it is created by {@link #SecureRandom(byte[])}). The first call to
|
||||
* {@code nextBytes} will force it to seed itself from an implementation-
|
||||
* specific entropy source. This self-seeding will not occur if {@code setSeed}
|
||||
* was previously called.
|
||||
*
|
||||
* <p> A {@code SecureRandom} can be reseeded at any time by calling the
|
||||
* {@code reseed} or {@code setSeed} method. The {@code reseed} method
|
||||
* reads entropy input from its entropy source to reseed itself.
|
||||
* The {@code setSeed} method requires the caller to provide the seed.
|
||||
*
|
||||
* <p> Please note that {@code reseed} may not be supported by all
|
||||
* {@code SecureRandom} implementations.
|
||||
*
|
||||
* <p> Some {@code SecureRandom} implementations may accept a
|
||||
* {@link SecureRandomParameters} parameter in its
|
||||
* {@link #nextBytes(byte[], SecureRandomParameters)} and
|
||||
* {@link #reseed(SecureRandomParameters)} methods to further
|
||||
* control the behavior of the methods.
|
||||
*
|
||||
* <p> Note: Depending on the implementation, the {@code generateSeed},
|
||||
* {@code reseed} and {@code nextBytes} methods may block as entropy is being
|
||||
* gathered, for example, if the entropy source is /dev/random on various
|
||||
* Unix-like operating systems.
|
||||
*
|
||||
* @see java.security.SecureRandomSpi
|
||||
* @see java.util.Random
|
||||
@ -132,26 +167,19 @@ public class SecureRandom extends java.util.Random {
|
||||
*
|
||||
* <p> This constructor traverses the list of registered security Providers,
|
||||
* starting with the most preferred Provider.
|
||||
* A new SecureRandom object encapsulating the
|
||||
* SecureRandomSpi implementation from the first
|
||||
* Provider that supports a SecureRandom (RNG) algorithm is returned.
|
||||
* A new {@code SecureRandom} object encapsulating the
|
||||
* {@code SecureRandomSpi} implementation from the first
|
||||
* Provider that supports a {@code SecureRandom} (RNG) algorithm is returned.
|
||||
* If none of the Providers support a RNG algorithm,
|
||||
* then an implementation-specific default is returned.
|
||||
*
|
||||
* <p> Note that the list of registered providers may be retrieved via
|
||||
* the {@link Security#getProviders() Security.getProviders()} method.
|
||||
*
|
||||
* <p> See the SecureRandom section in the <a href=
|
||||
* <p> See the {@code SecureRandom} section in the <a href=
|
||||
* "{@docRoot}/../technotes/guides/security/StandardNames.html#SecureRandom">
|
||||
* Java Cryptography Architecture Standard Algorithm Name Documentation</a>
|
||||
* for information about standard RNG algorithm names.
|
||||
*
|
||||
* <p> The returned SecureRandom object has not been seeded. To seed the
|
||||
* returned object, call the {@code setSeed} method.
|
||||
* If {@code setSeed} is not called, the first call to
|
||||
* {@code nextBytes} will force the SecureRandom object to seed itself.
|
||||
* This self-seeding will not occur if {@code setSeed} was
|
||||
* previously called.
|
||||
*/
|
||||
public SecureRandom() {
|
||||
/*
|
||||
@ -166,20 +194,20 @@ public class SecureRandom extends java.util.Random {
|
||||
/**
|
||||
* Constructs a secure random number generator (RNG) implementing the
|
||||
* default random number algorithm.
|
||||
* The SecureRandom instance is seeded with the specified seed bytes.
|
||||
* The {@code SecureRandom} instance is seeded with the specified seed bytes.
|
||||
*
|
||||
* <p> This constructor traverses the list of registered security Providers,
|
||||
* starting with the most preferred Provider.
|
||||
* A new SecureRandom object encapsulating the
|
||||
* SecureRandomSpi implementation from the first
|
||||
* Provider that supports a SecureRandom (RNG) algorithm is returned.
|
||||
* A new {@code SecureRandom} object encapsulating the
|
||||
* {@code SecureRandomSpi} implementation from the first
|
||||
* Provider that supports a {@code SecureRandom} (RNG) algorithm is returned.
|
||||
* If none of the Providers support a RNG algorithm,
|
||||
* then an implementation-specific default is returned.
|
||||
*
|
||||
* <p> Note that the list of registered providers may be retrieved via
|
||||
* the {@link Security#getProviders() Security.getProviders()} method.
|
||||
*
|
||||
* <p> See the SecureRandom section in the <a href=
|
||||
* <p> See the {@code SecureRandom} section in the <a href=
|
||||
* "{@docRoot}/../technotes/guides/security/StandardNames.html#SecureRandom">
|
||||
* Java Cryptography Architecture Standard Algorithm Name Documentation</a>
|
||||
* for information about standard RNG algorithm names.
|
||||
@ -225,9 +253,9 @@ public class SecureRandom extends java.util.Random {
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a SecureRandom object.
|
||||
* Creates a {@code SecureRandom} object.
|
||||
*
|
||||
* @param secureRandomSpi the SecureRandom implementation.
|
||||
* @param secureRandomSpi the {@code SecureRandom} implementation.
|
||||
* @param provider the provider.
|
||||
*/
|
||||
protected SecureRandom(SecureRandomSpi secureRandomSpi,
|
||||
@ -249,25 +277,18 @@ public class SecureRandom extends java.util.Random {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a SecureRandom object that implements the specified
|
||||
* Returns a {@code SecureRandom} object that implements the specified
|
||||
* Random Number Generator (RNG) algorithm.
|
||||
*
|
||||
* <p> This method traverses the list of registered security Providers,
|
||||
* starting with the most preferred Provider.
|
||||
* A new SecureRandom object encapsulating the
|
||||
* SecureRandomSpi implementation from the first
|
||||
* A new {@code SecureRandom} object encapsulating the
|
||||
* {@code SecureRandomSpi} implementation from the first
|
||||
* Provider that supports the specified algorithm is returned.
|
||||
*
|
||||
* <p> Note that the list of registered providers may be retrieved via
|
||||
* the {@link Security#getProviders() Security.getProviders()} method.
|
||||
*
|
||||
* <p> The returned SecureRandom object has not been seeded. To seed the
|
||||
* returned object, call the {@code setSeed} method.
|
||||
* If {@code setSeed} is not called, the first call to
|
||||
* {@code nextBytes} will force the SecureRandom object to seed itself.
|
||||
* This self-seeding will not occur if {@code setSeed} was
|
||||
* previously called.
|
||||
*
|
||||
* @implNote
|
||||
* The JDK Reference Implementation additionally uses the
|
||||
* {@code jdk.security.provider.preferred}
|
||||
@ -277,15 +298,15 @@ public class SecureRandom extends java.util.Random {
|
||||
* {@link Security#getProviders() Security.getProviders()}.
|
||||
*
|
||||
* @param algorithm the name of the RNG algorithm.
|
||||
* See the SecureRandom section in the <a href=
|
||||
* See the {@code SecureRandom} section in the <a href=
|
||||
* "{@docRoot}/../technotes/guides/security/StandardNames.html#SecureRandom">
|
||||
* Java Cryptography Architecture Standard Algorithm Name Documentation</a>
|
||||
* for information about standard RNG algorithm names.
|
||||
*
|
||||
* @return the new SecureRandom object.
|
||||
* @return the new {@code SecureRandom} object.
|
||||
*
|
||||
* @exception NoSuchAlgorithmException if no Provider supports a
|
||||
* SecureRandomSpi implementation for the
|
||||
* {@code SecureRandomSpi} implementation for the
|
||||
* specified algorithm.
|
||||
*
|
||||
* @see Provider
|
||||
@ -295,49 +316,42 @@ public class SecureRandom extends java.util.Random {
|
||||
public static SecureRandom getInstance(String algorithm)
|
||||
throws NoSuchAlgorithmException {
|
||||
Instance instance = GetInstance.getInstance("SecureRandom",
|
||||
SecureRandomSpi.class, algorithm);
|
||||
SecureRandomSpi.class, algorithm);
|
||||
return new SecureRandom((SecureRandomSpi)instance.impl,
|
||||
instance.provider, algorithm);
|
||||
instance.provider, algorithm);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a SecureRandom object that implements the specified
|
||||
* Returns a {@code SecureRandom} object that implements the specified
|
||||
* Random Number Generator (RNG) algorithm.
|
||||
*
|
||||
* <p> A new SecureRandom object encapsulating the
|
||||
* SecureRandomSpi implementation from the specified provider
|
||||
* <p> A new {@code SecureRandom} object encapsulating the
|
||||
* {@code SecureRandomSpi} implementation from the specified provider
|
||||
* is returned. The specified provider must be registered
|
||||
* in the security provider list.
|
||||
*
|
||||
* <p> Note that the list of registered providers may be retrieved via
|
||||
* the {@link Security#getProviders() Security.getProviders()} method.
|
||||
*
|
||||
* <p> The returned SecureRandom object has not been seeded. To seed the
|
||||
* returned object, call the {@code setSeed} method.
|
||||
* If {@code setSeed} is not called, the first call to
|
||||
* {@code nextBytes} will force the SecureRandom object to seed itself.
|
||||
* This self-seeding will not occur if {@code setSeed} was
|
||||
* previously called.
|
||||
*
|
||||
* @param algorithm the name of the RNG algorithm.
|
||||
* See the SecureRandom section in the <a href=
|
||||
* See the {@code SecureRandom} section in the <a href=
|
||||
* "{@docRoot}/../technotes/guides/security/StandardNames.html#SecureRandom">
|
||||
* Java Cryptography Architecture Standard Algorithm Name Documentation</a>
|
||||
* for information about standard RNG algorithm names.
|
||||
*
|
||||
* @param provider the name of the provider.
|
||||
*
|
||||
* @return the new SecureRandom object.
|
||||
* @return the new {@code SecureRandom} object.
|
||||
*
|
||||
* @exception NoSuchAlgorithmException if a SecureRandomSpi
|
||||
* implementation for the specified algorithm is not
|
||||
* available from the specified provider.
|
||||
* @throws NoSuchAlgorithmException if a {@code SecureRandomSpi}
|
||||
* implementation for the specified algorithm is not
|
||||
* available from the specified provider.
|
||||
*
|
||||
* @exception NoSuchProviderException if the specified provider is not
|
||||
* registered in the security provider list.
|
||||
* @throws NoSuchProviderException if the specified provider is not
|
||||
* registered in the security provider list.
|
||||
*
|
||||
* @exception IllegalArgumentException if the provider name is null
|
||||
* or empty.
|
||||
* @throws IllegalArgumentException if the provider name is null
|
||||
* or empty.
|
||||
*
|
||||
* @see Provider
|
||||
*
|
||||
@ -352,36 +366,29 @@ public class SecureRandom extends java.util.Random {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a SecureRandom object that implements the specified
|
||||
* Returns a {@code SecureRandom} object that implements the specified
|
||||
* Random Number Generator (RNG) algorithm.
|
||||
*
|
||||
* <p> A new SecureRandom object encapsulating the
|
||||
* SecureRandomSpi implementation from the specified Provider
|
||||
* object is returned. Note that the specified Provider object
|
||||
* <p> A new {@code SecureRandom} object encapsulating the
|
||||
* {@code SecureRandomSpi} implementation from the specified {@code Provider}
|
||||
* object is returned. Note that the specified {@code Provider} object
|
||||
* does not have to be registered in the provider list.
|
||||
*
|
||||
* <p> The returned SecureRandom object has not been seeded. To seed the
|
||||
* returned object, call the {@code setSeed} method.
|
||||
* If {@code setSeed} is not called, the first call to
|
||||
* {@code nextBytes} will force the SecureRandom object to seed itself.
|
||||
* This self-seeding will not occur if {@code setSeed} was
|
||||
* previously called.
|
||||
*
|
||||
* @param algorithm the name of the RNG algorithm.
|
||||
* See the SecureRandom section in the <a href=
|
||||
* See the {@code SecureRandom} section in the <a href=
|
||||
* "{@docRoot}/../technotes/guides/security/StandardNames.html#SecureRandom">
|
||||
* Java Cryptography Architecture Standard Algorithm Name Documentation</a>
|
||||
* for information about standard RNG algorithm names.
|
||||
*
|
||||
* @param provider the provider.
|
||||
*
|
||||
* @return the new SecureRandom object.
|
||||
* @return the new {@code SecureRandom} object.
|
||||
*
|
||||
* @exception NoSuchAlgorithmException if a SecureRandomSpi
|
||||
* implementation for the specified algorithm is not available
|
||||
* from the specified Provider object.
|
||||
* @throws NoSuchAlgorithmException if a {@code SecureRandomSpi}
|
||||
* implementation for the specified algorithm is not available
|
||||
* from the specified {@code Provider} object.
|
||||
*
|
||||
* @exception IllegalArgumentException if the specified provider is null.
|
||||
* @throws IllegalArgumentException if the specified provider is null.
|
||||
*
|
||||
* @see Provider
|
||||
*
|
||||
@ -396,24 +403,178 @@ public class SecureRandom extends java.util.Random {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the SecureRandomSpi of this SecureRandom object.
|
||||
* Returns a {@code SecureRandom} object that implements the specified
|
||||
* Random Number Generator (RNG) algorithm and supports the specified
|
||||
* {@code SecureRandomParameters} request.
|
||||
*
|
||||
* <p> This method traverses the list of registered security Providers,
|
||||
* starting with the most preferred Provider.
|
||||
* A new {@code SecureRandom} object encapsulating the
|
||||
* {@code SecureRandomSpi} implementation from the first
|
||||
* Provider that supports the specified algorithm and the specified
|
||||
* {@code SecureRandomParameters} is returned.
|
||||
*
|
||||
* <p> Note that the list of registered providers may be retrieved via
|
||||
* the {@link Security#getProviders() Security.getProviders()} method.
|
||||
*
|
||||
* @implNote
|
||||
* The JDK Reference Implementation additionally uses the
|
||||
* {@code jdk.security.provider.preferred} property to determine
|
||||
* the preferred provider order for the specified algorithm. This
|
||||
* may be different than the order of providers returned by
|
||||
* {@link Security#getProviders() Security.getProviders()}.
|
||||
*
|
||||
* @param algorithm the name of the RNG algorithm.
|
||||
* See the {@code SecureRandom} section in the <a href=
|
||||
* "{@docRoot}/../technotes/guides/security/StandardNames.html#SecureRandom">
|
||||
* Java Cryptography Architecture Standard Algorithm Name Documentation</a>
|
||||
* for information about standard RNG algorithm names.
|
||||
*
|
||||
* @param params the {@code SecureRandomParameters}
|
||||
* the newly created {@code SecureRandom} object must support.
|
||||
*
|
||||
* @return the new {@code SecureRandom} object.
|
||||
*
|
||||
* @throws NoSuchAlgorithmException if no Provider supports a
|
||||
* {@code SecureRandomSpi} implementation for the specified
|
||||
* algorithm and parameters.
|
||||
*
|
||||
* @throws IllegalArgumentException if the specified params is null.
|
||||
*
|
||||
* @see Provider
|
||||
*
|
||||
* @since 9
|
||||
*/
|
||||
public static SecureRandom getInstance(
|
||||
String algorithm, SecureRandomParameters params)
|
||||
throws NoSuchAlgorithmException {
|
||||
if (params == null) {
|
||||
throw new IllegalArgumentException("params cannot be null");
|
||||
}
|
||||
Instance instance = GetInstance.getInstance("SecureRandom",
|
||||
SecureRandomSpi.class, algorithm, params);
|
||||
return new SecureRandom((SecureRandomSpi)instance.impl,
|
||||
instance.provider, algorithm);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code SecureRandom} object that implements the specified
|
||||
* Random Number Generator (RNG) algorithm and supports the specified
|
||||
* {@code SecureRandomParameters} request.
|
||||
*
|
||||
* <p> A new {@code SecureRandom} object encapsulating the
|
||||
* {@code SecureRandomSpi} implementation from the specified provider
|
||||
* is returned. The specified provider must be registered
|
||||
* in the security provider list.
|
||||
*
|
||||
* <p> Note that the list of registered providers may be retrieved via
|
||||
* the {@link Security#getProviders() Security.getProviders()} method.
|
||||
*
|
||||
* @param algorithm the name of the RNG algorithm.
|
||||
* See the {@code SecureRandom} section in the <a href=
|
||||
* "{@docRoot}/../technotes/guides/security/StandardNames.html#SecureRandom">
|
||||
* Java Cryptography Architecture Standard Algorithm Name Documentation</a>
|
||||
* for information about standard RNG algorithm names.
|
||||
*
|
||||
* @param params the {@code SecureRandomParameters}
|
||||
* the newly created {@code SecureRandom} object must support.
|
||||
*
|
||||
* @param provider the name of the provider.
|
||||
*
|
||||
* @return the new {@code SecureRandom} object.
|
||||
*
|
||||
* @throws NoSuchAlgorithmException if the specified provider does not
|
||||
* support a {@code SecureRandomSpi} implementation for the
|
||||
* specified algorithm and parameters.
|
||||
*
|
||||
* @throws NoSuchProviderException if the specified provider is not
|
||||
* registered in the security provider list.
|
||||
*
|
||||
* @throws IllegalArgumentException if the provider name is null
|
||||
* or empty, or params is null.
|
||||
*
|
||||
* @see Provider
|
||||
*
|
||||
* @since 9
|
||||
*/
|
||||
public static SecureRandom getInstance(String algorithm,
|
||||
SecureRandomParameters params, String provider)
|
||||
throws NoSuchAlgorithmException, NoSuchProviderException {
|
||||
if (params == null) {
|
||||
throw new IllegalArgumentException("params cannot be null");
|
||||
}
|
||||
Instance instance = GetInstance.getInstance("SecureRandom",
|
||||
SecureRandomSpi.class, algorithm, params, provider);
|
||||
return new SecureRandom((SecureRandomSpi)instance.impl,
|
||||
instance.provider, algorithm);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@code SecureRandom} object that implements the specified
|
||||
* Random Number Generator (RNG) algorithm and supports the specified
|
||||
* {@code SecureRandomParameters} request.
|
||||
*
|
||||
* <p> A new {@code SecureRandom} object encapsulating the
|
||||
* {@code SecureRandomSpi} implementation from the specified
|
||||
* {@code Provider} object is returned. Note that the specified
|
||||
* {@code Provider} object does not have to be registered in the
|
||||
* provider list.
|
||||
*
|
||||
* @param algorithm the name of the RNG algorithm.
|
||||
* See the {@code SecureRandom} section in the <a href=
|
||||
* "{@docRoot}/../technotes/guides/security/StandardNames.html#SecureRandom">
|
||||
* Java Cryptography Architecture Standard Algorithm Name Documentation</a>
|
||||
* for information about standard RNG algorithm names.
|
||||
*
|
||||
* @param params the {@code SecureRandomParameters}
|
||||
* the newly created {@code SecureRandom} object must support.
|
||||
*
|
||||
* @param provider the provider.
|
||||
*
|
||||
* @return the new {@code SecureRandom} object.
|
||||
*
|
||||
* @throws NoSuchAlgorithmException if the specified provider does not
|
||||
* support a {@code SecureRandomSpi} implementation for the
|
||||
* specified algorithm and parameters.
|
||||
*
|
||||
* @throws IllegalArgumentException if the specified provider or params
|
||||
* is null.
|
||||
*
|
||||
* @see Provider
|
||||
*
|
||||
* @since 9
|
||||
*/
|
||||
public static SecureRandom getInstance(String algorithm,
|
||||
SecureRandomParameters params, Provider provider)
|
||||
throws NoSuchAlgorithmException {
|
||||
if (params == null) {
|
||||
throw new IllegalArgumentException("params cannot be null");
|
||||
}
|
||||
Instance instance = GetInstance.getInstance("SecureRandom",
|
||||
SecureRandomSpi.class, algorithm, params, provider);
|
||||
return new SecureRandom((SecureRandomSpi)instance.impl,
|
||||
instance.provider, algorithm);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@code SecureRandomSpi} of this {@code SecureRandom} object.
|
||||
*/
|
||||
SecureRandomSpi getSecureRandomSpi() {
|
||||
return secureRandomSpi;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the provider of this SecureRandom object.
|
||||
* Returns the provider of this {@code SecureRandom} object.
|
||||
*
|
||||
* @return the provider of this SecureRandom object.
|
||||
* @return the provider of this {@code SecureRandom} object.
|
||||
*/
|
||||
public final Provider getProvider() {
|
||||
return provider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the algorithm implemented by this SecureRandom
|
||||
* object.
|
||||
* Returns the name of the algorithm implemented by this
|
||||
* {@code SecureRandom} object.
|
||||
*
|
||||
* @return the name of the algorithm or {@code unknown}
|
||||
* if the algorithm name cannot be determined.
|
||||
@ -424,9 +585,49 @@ public class SecureRandom extends java.util.Random {
|
||||
}
|
||||
|
||||
/**
|
||||
* Reseeds this random object. The given seed supplements, rather than
|
||||
* replaces, the existing seed. Thus, repeated calls are guaranteed
|
||||
* never to reduce randomness.
|
||||
* Returns a Human-readable string representation of this
|
||||
* {@code SecureRandom}.
|
||||
*
|
||||
* @return the string representation
|
||||
*
|
||||
* @since 9
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return secureRandomSpi.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the effective {@link SecureRandomParameters} for this
|
||||
* {@code SecureRandom} instance.
|
||||
* <p>
|
||||
* The returned value can be different from the
|
||||
* {@code SecureRandomParameters} object passed into a {@code getInstance}
|
||||
* method, but it cannot change during the lifetime of this
|
||||
* {@code SecureRandom} object.
|
||||
* <p>
|
||||
* A caller can use the returned value to find out what features this
|
||||
* {@code SecureRandom} supports.
|
||||
*
|
||||
* @return the effective {@link SecureRandomParameters} parameters,
|
||||
* or {@code null} if no parameters were used.
|
||||
*
|
||||
* @since 9
|
||||
* @see SecureRandomSpi
|
||||
*/
|
||||
public SecureRandomParameters getParameters() {
|
||||
return secureRandomSpi.engineGetParameters();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reseeds this random object with the given seed. The seed supplements,
|
||||
* rather than replaces, the existing seed. Thus, repeated calls are
|
||||
* guaranteed never to reduce randomness.
|
||||
* <p>
|
||||
* A PRNG {@code SecureRandom} will not seed itself automatically if
|
||||
* {@code setSeed} is called before any {@code nextBytes} or {@code reseed}
|
||||
* calls. The caller should make sure that the {@code seed} argument
|
||||
* contains enough entropy for the security of this {@code SecureRandom}.
|
||||
*
|
||||
* @param seed the seed.
|
||||
*
|
||||
@ -458,18 +659,13 @@ public class SecureRandom extends java.util.Random {
|
||||
* yet been initialized at that point.
|
||||
*/
|
||||
if (seed != 0) {
|
||||
secureRandomSpi.engineSetSeed(longToByteArray(seed));
|
||||
this.secureRandomSpi.engineSetSeed(longToByteArray(seed));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a user-specified number of random bytes.
|
||||
*
|
||||
* <p> If a call to {@code setSeed} had not occurred previously,
|
||||
* the first call to this method forces this SecureRandom object
|
||||
* to seed itself. This self-seeding will not occur if
|
||||
* {@code setSeed} was previously called.
|
||||
*
|
||||
* @param bytes the array to be filled in with random bytes.
|
||||
*/
|
||||
@Override
|
||||
@ -477,6 +673,28 @@ public class SecureRandom extends java.util.Random {
|
||||
secureRandomSpi.engineNextBytes(bytes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a user-specified number of random bytes with
|
||||
* additional parameters.
|
||||
*
|
||||
* @param bytes the array to be filled in with random bytes
|
||||
* @param params additional parameters
|
||||
* @throws NullPointerException if {@code bytes} is null
|
||||
* @throws UnsupportedOperationException if the underlying provider
|
||||
* implementation has not overridden this method
|
||||
* @throws IllegalArgumentException if {@code params} is {@code null},
|
||||
* illegal or unsupported by this {@code SecureRandom}
|
||||
*
|
||||
* @since 9
|
||||
*/
|
||||
public synchronized void nextBytes(
|
||||
byte[] bytes, SecureRandomParameters params) {
|
||||
if (params == null) {
|
||||
throw new IllegalArgumentException("params cannot be null");
|
||||
}
|
||||
secureRandomSpi.engineNextBytes(Objects.requireNonNull(bytes), params);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates an integer containing the user-specified number of
|
||||
* pseudo-random bits (right justified, with leading zeros). This
|
||||
@ -512,7 +730,7 @@ public class SecureRandom extends java.util.Random {
|
||||
*
|
||||
* <p>This method is only included for backwards compatibility.
|
||||
* The caller is encouraged to use one of the alternative
|
||||
* {@code getInstance} methods to obtain a SecureRandom object, and
|
||||
* {@code getInstance} methods to obtain a {@code SecureRandom} object, and
|
||||
* then call the {@code generateSeed} method to obtain seed bytes
|
||||
* from that object.
|
||||
*
|
||||
@ -537,10 +755,13 @@ public class SecureRandom extends java.util.Random {
|
||||
* call may be used to seed other random number generators.
|
||||
*
|
||||
* @param numBytes the number of seed bytes to generate.
|
||||
*
|
||||
* @throws IllegalArgumentException if {@code numBytes} is negative
|
||||
* @return the seed bytes.
|
||||
*/
|
||||
public byte[] generateSeed(int numBytes) {
|
||||
if (numBytes < 0) {
|
||||
throw new IllegalArgumentException("numBytes cannot be negative");
|
||||
}
|
||||
return secureRandomSpi.engineGenerateSeed(numBytes);
|
||||
}
|
||||
|
||||
@ -562,8 +783,8 @@ public class SecureRandom extends java.util.Random {
|
||||
/**
|
||||
* Gets a default PRNG algorithm by looking through all registered
|
||||
* providers. Returns the first PRNG algorithm of the first provider that
|
||||
* has registered a SecureRandom implementation, or null if none of the
|
||||
* registered providers supplies a SecureRandom implementation.
|
||||
* has registered a {@code SecureRandom} implementation, or null if none of
|
||||
* the registered providers supplies a {@code SecureRandom} implementation.
|
||||
*/
|
||||
private static String getPrngAlgorithm() {
|
||||
for (Provider p : Providers.getProviderList().providers()) {
|
||||
@ -667,6 +888,42 @@ public class SecureRandom extends java.util.Random {
|
||||
"No strong SecureRandom impls available: " + property);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reseeds this {@code SecureRandom} with entropy input read from its
|
||||
* entropy source.
|
||||
*
|
||||
* @throws UnsupportedOperationException if the underlying provider
|
||||
* implementation has not overridden this method.
|
||||
*
|
||||
* @since 9
|
||||
*/
|
||||
public synchronized void reseed() {
|
||||
secureRandomSpi.engineReseed(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reseeds this {@code SecureRandom} with entropy input read from its
|
||||
* entropy source with additional parameters.
|
||||
* <p>
|
||||
* Note that entropy is obtained from an entropy source. While
|
||||
* some data in {@code params} may contain entropy, its main usage is to
|
||||
* provide diversity.
|
||||
*
|
||||
* @param params extra parameters
|
||||
* @throws UnsupportedOperationException if the underlying provider
|
||||
* implementation has not overridden this method.
|
||||
* @throws IllegalArgumentException if {@code params} is {@code null},
|
||||
* illegal or unsupported by this {@code SecureRandom}
|
||||
*
|
||||
* @since 9
|
||||
*/
|
||||
public synchronized void reseed(SecureRandomParameters params) {
|
||||
if (params == null) {
|
||||
throw new IllegalArgumentException("params cannot be null");
|
||||
}
|
||||
secureRandomSpi.engineReseed(params);
|
||||
}
|
||||
|
||||
// Declare serialVersionUID to be compatible with JDK1.1
|
||||
static final long serialVersionUID = 4940670005562187L;
|
||||
|
||||
@ -685,7 +942,7 @@ public class SecureRandom extends java.util.Random {
|
||||
* We know that the MessageDigest class does not implement
|
||||
* java.io.Serializable. However, since this field is no longer
|
||||
* used, it will always be NULL and won't affect the serialization
|
||||
* of the SecureRandom class itself.
|
||||
* of the {@code SecureRandom} class itself.
|
||||
*/
|
||||
private byte[] randomBytes;
|
||||
/**
|
||||
|
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package java.security;
|
||||
|
||||
/**
|
||||
* A marker interface for parameters used in various {@code SecureRandom}
|
||||
* methods.
|
||||
* <p>
|
||||
* Some {@code SecureRandom} implementations might require additional
|
||||
* operational parameters. Objects of classes which implement this interface
|
||||
* can be passed to those implementations that support them.
|
||||
*
|
||||
* @see DrbgParameters
|
||||
*/
|
||||
public interface SecureRandomParameters {
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -27,13 +27,38 @@ package java.security;
|
||||
|
||||
/**
|
||||
* This class defines the <i>Service Provider Interface</i> (<b>SPI</b>)
|
||||
* for the {@code SecureRandom} class.
|
||||
* for the {@link SecureRandom} class.
|
||||
* <p>
|
||||
* All the abstract methods in this class must be implemented by each
|
||||
* service provider who wishes to supply the implementation
|
||||
* of a cryptographically strong pseudo-random number generator.
|
||||
*
|
||||
* @implSpec
|
||||
* If the {@link #SecureRandomSpi(SecureRandomParameters)}
|
||||
* constructor is overridden in an implementation, it will always be called
|
||||
* whenever a {@code SecureRandom} is instantiated. Precisely, if an object is
|
||||
* instantiated with one of {@code SecureRandom}'s {@code getInstance} methods
|
||||
* <em>without</em> a {@link SecureRandomParameters} parameter,
|
||||
* the constructor will be called with a {@code null} argument and the
|
||||
* implementation is responsible for creating its own
|
||||
* {@code SecureRandomParameters} parameter for use when
|
||||
* {@link #engineGetParameters()} is called. If an object
|
||||
* is instantiated with one of {@code SecureRandom}'s {@code getInstance}
|
||||
* methods <em>with</em> a {@code SecureRandomParameters} argument,
|
||||
* the constructor will be called with that argument. The
|
||||
* {@link #engineGetParameters()} method must not return {@code null}.
|
||||
* <p>
|
||||
* Otherwise, if the {@code SecureRandomSpi(SecureRandomParameters)}
|
||||
* constructor is not overridden in an implementation, the
|
||||
* {@link #SecureRandomSpi()} constructor must be overridden and it will be
|
||||
* called if an object is instantiated with one of {@code SecureRandom}'s
|
||||
* {@code getInstance} methods <em>without</em> a
|
||||
* {@code SecureRandomParameters} argument. Calling one of
|
||||
* {@code SecureRandom}'s {@code getInstance} methods <em>with</em>
|
||||
* a {@code SecureRandomParameters} argument will never
|
||||
* return an instance of this implementation. The
|
||||
* {@link #engineGetParameters()} method must return {@code null}.
|
||||
*
|
||||
* @see SecureRandom
|
||||
* @since 1.2
|
||||
*/
|
||||
|
||||
@ -42,9 +67,30 @@ public abstract class SecureRandomSpi implements java.io.Serializable {
|
||||
private static final long serialVersionUID = -2991854161009191830L;
|
||||
|
||||
/**
|
||||
* Reseeds this random object. The given seed supplements, rather than
|
||||
* replaces, the existing seed. Thus, repeated calls are guaranteed
|
||||
* never to reduce randomness.
|
||||
* Constructor without a parameter.
|
||||
*/
|
||||
public SecureRandomSpi() {
|
||||
// ignored
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor with a parameter.
|
||||
*
|
||||
* @param params the {@link SecureRandomParameters} object.
|
||||
* This argument can be {@code null}.
|
||||
* @throws IllegalArgumentException if {@code params} is
|
||||
* unrecognizable or unsupported by this {@code SecureRandom}
|
||||
*
|
||||
* @since 9
|
||||
*/
|
||||
protected SecureRandomSpi(SecureRandomParameters params) {
|
||||
// ignored
|
||||
}
|
||||
|
||||
/**
|
||||
* Reseeds this random object with the given seed. The seed supplements,
|
||||
* rather than replaces, the existing seed. Thus, repeated calls
|
||||
* are guaranteed never to reduce randomness.
|
||||
*
|
||||
* @param seed the seed.
|
||||
*/
|
||||
@ -52,16 +98,44 @@ public abstract class SecureRandomSpi implements java.io.Serializable {
|
||||
|
||||
/**
|
||||
* Generates a user-specified number of random bytes.
|
||||
*
|
||||
* <p> If a call to {@code engineSetSeed} had not occurred previously,
|
||||
* the first call to this method forces this SecureRandom implementation
|
||||
* to seed itself. This self-seeding will not occur if
|
||||
* {@code engineSetSeed} was previously called.
|
||||
* <p>
|
||||
* Some random number generators can only generate a limited amount
|
||||
* of random bytes per invocation. If the size of {@code bytes}
|
||||
* is greater than this limit, the implementation should invoke
|
||||
* its generation process multiple times to completely fill the
|
||||
* buffer before returning from this method.
|
||||
*
|
||||
* @param bytes the array to be filled in with random bytes.
|
||||
*/
|
||||
protected abstract void engineNextBytes(byte[] bytes);
|
||||
|
||||
/**
|
||||
* Generates a user-specified number of random bytes with
|
||||
* additional parameters.
|
||||
* <p>
|
||||
* Some random number generators can only generate a limited amount
|
||||
* of random bytes per invocation. If the size of {@code bytes}
|
||||
* is greater than this limit, the implementation should invoke
|
||||
* its generation process multiple times to completely fill the
|
||||
* buffer before returning from this method.
|
||||
*
|
||||
* @implSpec The default implementation throws
|
||||
* an {@link UnsupportedOperationException}.
|
||||
*
|
||||
* @param bytes the array to be filled in with random bytes
|
||||
* @param params additional parameters
|
||||
* @throws UnsupportedOperationException if the implementation
|
||||
* has not overridden this method
|
||||
* @throws IllegalArgumentException if {@code params} is {@code null},
|
||||
* illegal or unsupported by this {@code SecureRandom}
|
||||
*
|
||||
* @since 9
|
||||
*/
|
||||
protected void engineNextBytes(
|
||||
byte[] bytes, SecureRandomParameters params) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the given number of seed bytes. This call may be used to
|
||||
* seed other random number generators.
|
||||
@ -70,5 +144,58 @@ public abstract class SecureRandomSpi implements java.io.Serializable {
|
||||
*
|
||||
* @return the seed bytes.
|
||||
*/
|
||||
protected abstract byte[] engineGenerateSeed(int numBytes);
|
||||
protected abstract byte[] engineGenerateSeed(int numBytes);
|
||||
|
||||
/**
|
||||
* Reseeds this random object with entropy input read from its
|
||||
* entropy source with additional parameters.
|
||||
* <p>
|
||||
* If this method is called by {@link SecureRandom#reseed()},
|
||||
* {@code params} will be {@code null}.
|
||||
* <p>
|
||||
* Do not override this method if the implementation does not
|
||||
* support reseeding.
|
||||
*
|
||||
* @implSpec The default implementation throws
|
||||
* an {@link UnsupportedOperationException}.
|
||||
*
|
||||
* @param params extra parameters, can be {@code null}.
|
||||
* @throws UnsupportedOperationException if the implementation
|
||||
* has not overridden this method
|
||||
* @throws IllegalArgumentException if {@code params} is
|
||||
* illegal or unsupported by this {@code SecureRandom}
|
||||
*
|
||||
* @since 9
|
||||
*/
|
||||
protected void engineReseed(SecureRandomParameters params) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the effective {@link SecureRandomParameters} for this
|
||||
* {@code SecureRandom} instance.
|
||||
*
|
||||
* @implSpec The default implementation returns {@code null}.
|
||||
*
|
||||
* @return the effective {@link SecureRandomParameters} parameters,
|
||||
* or {@code null} if no parameters were used.
|
||||
*
|
||||
* @since 9
|
||||
*/
|
||||
protected SecureRandomParameters engineGetParameters() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Human-readable string representation of this
|
||||
* {@code SecureRandom}.
|
||||
*
|
||||
* @return the string representation
|
||||
*
|
||||
* @since 9
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getSimpleName();
|
||||
}
|
||||
}
|
||||
|
@ -1488,7 +1488,7 @@ public final class DateTimeFormatterBuilder {
|
||||
* d 1 appendValue(ChronoField.DAY_OF_MONTH)
|
||||
* dd 2 appendValue(ChronoField.DAY_OF_MONTH, 2)
|
||||
* D 1 appendValue(ChronoField.DAY_OF_YEAR)
|
||||
* DD 2 appendValue(ChronoField.DAY_OF_YEAR, 2)
|
||||
* DD 2 appendValue(ChronoField.DAY_OF_YEAR, 2, 3, SignStyle.NOT_NEGATIVE)
|
||||
* DDD 3 appendValue(ChronoField.DAY_OF_YEAR, 3)
|
||||
* F 1 appendValue(ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH)
|
||||
* g..g 1..n appendValue(JulianFields.MODIFIED_JULIAN_DAY, n, 19, SignStyle.NORMAL)
|
||||
@ -1527,12 +1527,9 @@ public final class DateTimeFormatterBuilder {
|
||||
* ss 2 appendValue(ChronoField.SECOND_OF_MINUTE, 2)
|
||||
*
|
||||
* S..S 1..n appendFraction(ChronoField.NANO_OF_SECOND, n, n, false)
|
||||
* A 1 appendValue(ChronoField.MILLI_OF_DAY)
|
||||
* A..A 2..n appendValue(ChronoField.MILLI_OF_DAY, n)
|
||||
* n 1 appendValue(ChronoField.NANO_OF_SECOND)
|
||||
* n..n 2..n appendValue(ChronoField.NANO_OF_SECOND, n)
|
||||
* N 1 appendValue(ChronoField.NANO_OF_DAY)
|
||||
* N..N 2..n appendValue(ChronoField.NANO_OF_DAY, n)
|
||||
* A..A 1..n appendValue(ChronoField.MILLI_OF_DAY, n, 19, SignStyle.NOT_NEGATIVE)
|
||||
* n..n 1..n appendValue(ChronoField.NANO_OF_SECOND, n, 19, SignStyle.NOT_NEGATIVE)
|
||||
* N..N 1..n appendValue(ChronoField.NANO_OF_DAY, n, 19, SignStyle.NOT_NEGATIVE)
|
||||
* </pre>
|
||||
* <p>
|
||||
* <b>Zone ID</b>: Pattern letters to output {@code ZoneId}.
|
||||
@ -1841,8 +1838,8 @@ public final class DateTimeFormatterBuilder {
|
||||
case 'D':
|
||||
if (count == 1) {
|
||||
appendValue(field);
|
||||
} else if (count <= 3) {
|
||||
appendValue(field, count);
|
||||
} else if (count == 2 || count == 3) {
|
||||
appendValue(field, count, 3, SignStyle.NOT_NEGATIVE);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Too many pattern letters: " + cur);
|
||||
}
|
||||
@ -1850,6 +1847,11 @@ public final class DateTimeFormatterBuilder {
|
||||
case 'g':
|
||||
appendValue(field, count, 19, SignStyle.NORMAL);
|
||||
break;
|
||||
case 'A':
|
||||
case 'n':
|
||||
case 'N':
|
||||
appendValue(field, count, 19, SignStyle.NOT_NEGATIVE);
|
||||
break;
|
||||
default:
|
||||
if (count == 1) {
|
||||
appendValue(field);
|
||||
|
@ -545,6 +545,33 @@ public final class Currency implements Serializable {
|
||||
return numericCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the 3 digit ISO 4217 numeric code of this currency as a {@code String}.
|
||||
* Unlike {@link getNumericCode()}, which returns the numeric code as {@code int},
|
||||
* this method always returns the numeric code as a 3 digit string.
|
||||
* e.g. a numeric value of 32 would be returned as "032",
|
||||
* and a numeric value of 6 would be returned as "006".
|
||||
*
|
||||
* @return the 3 digit ISO 4217 numeric code of this currency as a {@code String}
|
||||
* @since 9
|
||||
*/
|
||||
public String getNumericCodeAsString() {
|
||||
/* numeric code could be returned as a 3 digit string simply by using
|
||||
String.format("%03d",numericCode); which uses regex to parse the format,
|
||||
"%03d" in this case. Parsing a regex gives an extra performance overhead,
|
||||
so String.format() approach is avoided in this scenario.
|
||||
*/
|
||||
if (numericCode < 100) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append('0');
|
||||
if (numericCode < 10) {
|
||||
sb.append('0');
|
||||
}
|
||||
return sb.append(numericCode).toString();
|
||||
}
|
||||
return String.valueOf(numericCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name that is suitable for displaying this currency for
|
||||
* the default {@link Locale.Category#DISPLAY DISPLAY} locale.
|
||||
@ -788,3 +815,4 @@ public final class Currency implements Serializable {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,657 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package java.util;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InvalidObjectException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectStreamException;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Container class for immutable collections. Not part of the public API.
|
||||
* Mainly for namespace management and shared infrastructure.
|
||||
*
|
||||
* Serial warnings are suppressed throughout because all implementation
|
||||
* classes use a serial proxy and thus have no need to declare serialVersionUID.
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
class ImmutableCollections {
|
||||
/**
|
||||
* A "salt" value used for randomizing iteration order. This is initialized once
|
||||
* and stays constant for the lifetime of the JVM. It need not be truly random, but
|
||||
* it needs to vary sufficiently from one run to the next so that iteration order
|
||||
* will vary between JVM runs.
|
||||
*/
|
||||
static final int SALT;
|
||||
static {
|
||||
SALT = new Random().nextInt();
|
||||
}
|
||||
|
||||
/** No instances. */
|
||||
private ImmutableCollections() { }
|
||||
|
||||
/**
|
||||
* The reciprocal of load factor. Given a number of elements
|
||||
* to store, multiply by this factor to get the table size.
|
||||
*/
|
||||
static final double EXPAND_FACTOR = 2.0;
|
||||
|
||||
// ---------- List Implementations ----------
|
||||
|
||||
static final class List0<E> extends AbstractList<E> implements RandomAccess, Serializable {
|
||||
List0() { }
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public E get(int index) {
|
||||
Objects.checkIndex(index, 0); // always throws IndexOutOfBoundsException
|
||||
return null; // but the compiler doesn't know this
|
||||
}
|
||||
|
||||
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
|
||||
throw new InvalidObjectException("not serial proxy");
|
||||
}
|
||||
|
||||
private Object writeReplace() {
|
||||
return new CollSer(CollSer.IMM_LIST);
|
||||
}
|
||||
}
|
||||
|
||||
static final class List1<E> extends AbstractList<E> implements RandomAccess, Serializable {
|
||||
private final E e0;
|
||||
|
||||
List1(E e0) {
|
||||
this.e0 = Objects.requireNonNull(e0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public E get(int index) {
|
||||
Objects.checkIndex(index, 1);
|
||||
// assert index == 0
|
||||
return e0;
|
||||
}
|
||||
|
||||
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
|
||||
throw new InvalidObjectException("not serial proxy");
|
||||
}
|
||||
|
||||
private Object writeReplace() {
|
||||
return new CollSer(CollSer.IMM_LIST, e0);
|
||||
}
|
||||
}
|
||||
|
||||
static final class List2<E> extends AbstractList<E> implements RandomAccess, Serializable {
|
||||
private final E e0;
|
||||
private final E e1;
|
||||
|
||||
List2(E e0, E e1) {
|
||||
this.e0 = Objects.requireNonNull(e0);
|
||||
this.e1 = Objects.requireNonNull(e1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public E get(int index) {
|
||||
Objects.checkIndex(index, 2);
|
||||
if (index == 0) {
|
||||
return e0;
|
||||
} else { // index == 1
|
||||
return e1;
|
||||
}
|
||||
}
|
||||
|
||||
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
|
||||
throw new InvalidObjectException("not serial proxy");
|
||||
}
|
||||
|
||||
private Object writeReplace() {
|
||||
return new CollSer(CollSer.IMM_LIST, e0, e1);
|
||||
}
|
||||
}
|
||||
|
||||
static final class ListN<E> extends AbstractList<E> implements RandomAccess, Serializable {
|
||||
private final E[] elements;
|
||||
|
||||
@SafeVarargs
|
||||
ListN(E... input) {
|
||||
// copy and check manually to avoid TOCTOU
|
||||
@SuppressWarnings("unchecked")
|
||||
E[] tmp = (E[])new Object[input.length]; // implicit nullcheck of input
|
||||
for (int i = 0; i < input.length; i++) {
|
||||
tmp[i] = Objects.requireNonNull(input[i]);
|
||||
}
|
||||
this.elements = tmp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return elements.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public E get(int index) {
|
||||
Objects.checkIndex(index, elements.length);
|
||||
return elements[index];
|
||||
}
|
||||
|
||||
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
|
||||
throw new InvalidObjectException("not serial proxy");
|
||||
}
|
||||
|
||||
private Object writeReplace() {
|
||||
return new CollSer(CollSer.IMM_LIST, elements);
|
||||
}
|
||||
}
|
||||
|
||||
// ---------- Set Implementations ----------
|
||||
|
||||
static final class Set0<E> extends AbstractSet<E> implements Serializable {
|
||||
Set0() { }
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object o) {
|
||||
return super.contains(Objects.requireNonNull(o));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<E> iterator() {
|
||||
return Collections.emptyIterator();
|
||||
}
|
||||
|
||||
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
|
||||
throw new InvalidObjectException("not serial proxy");
|
||||
}
|
||||
|
||||
private Object writeReplace() {
|
||||
return new CollSer(CollSer.IMM_SET);
|
||||
}
|
||||
}
|
||||
|
||||
static final class Set1<E> extends AbstractSet<E> implements Serializable {
|
||||
private final E e0;
|
||||
|
||||
Set1(E e0) {
|
||||
this.e0 = Objects.requireNonNull(e0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object o) {
|
||||
return super.contains(Objects.requireNonNull(o));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<E> iterator() {
|
||||
return Collections.singletonIterator(e0);
|
||||
}
|
||||
|
||||
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
|
||||
throw new InvalidObjectException("not serial proxy");
|
||||
}
|
||||
|
||||
private Object writeReplace() {
|
||||
return new CollSer(CollSer.IMM_SET, e0);
|
||||
}
|
||||
}
|
||||
|
||||
static final class Set2<E> extends AbstractSet<E> implements Serializable {
|
||||
private final E e0;
|
||||
private final E e1;
|
||||
|
||||
Set2(E e0, E e1) {
|
||||
Objects.requireNonNull(e0);
|
||||
Objects.requireNonNull(e1);
|
||||
|
||||
if (e0.equals(e1)) {
|
||||
throw new IllegalArgumentException("duplicate element: " + e0);
|
||||
}
|
||||
|
||||
if (SALT >= 0) {
|
||||
this.e0 = e0;
|
||||
this.e1 = e1;
|
||||
} else {
|
||||
this.e0 = e1;
|
||||
this.e1 = e0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object o) {
|
||||
return super.contains(Objects.requireNonNull(o));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<E> iterator() {
|
||||
return new Iterator<E>() {
|
||||
private int idx = 0;
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return idx < 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public E next() {
|
||||
if (idx == 0) {
|
||||
idx = 1;
|
||||
return e0;
|
||||
} else if (idx == 1) {
|
||||
idx = 2;
|
||||
return e1;
|
||||
} else {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
|
||||
throw new InvalidObjectException("not serial proxy");
|
||||
}
|
||||
|
||||
private Object writeReplace() {
|
||||
return new CollSer(CollSer.IMM_SET, e0, e1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An array-based Set implementation. The element array must be strictly
|
||||
* larger than the size (the number of contained elements) so that at
|
||||
* least one null is always present.
|
||||
* @param <E> the element type
|
||||
*/
|
||||
static final class SetN<E> extends AbstractSet<E> implements Serializable {
|
||||
private final E[] elements;
|
||||
private final int size;
|
||||
|
||||
@SafeVarargs
|
||||
@SuppressWarnings("unchecked")
|
||||
SetN(E... input) {
|
||||
size = input.length; // implicit nullcheck of input
|
||||
|
||||
elements = (E[])new Object[(int)Math.ceil(EXPAND_FACTOR * input.length)];
|
||||
for (int i = 0; i < input.length; i++) {
|
||||
E e = Objects.requireNonNull(input[i]);
|
||||
int idx = probe(e);
|
||||
if (idx >= 0) {
|
||||
throw new IllegalArgumentException("duplicate element: " + e);
|
||||
} else {
|
||||
elements[-(idx + 1)] = e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object o) {
|
||||
Objects.requireNonNull(o);
|
||||
return probe(o) >= 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<E> iterator() {
|
||||
return new Iterator<E>() {
|
||||
private int idx = 0;
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
while (idx < elements.length) {
|
||||
if (elements[idx] != null)
|
||||
return true;
|
||||
idx++;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public E next() {
|
||||
if (! hasNext()) {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
return elements[idx++];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// returns index at which element is present; or if absent,
|
||||
// (-i - 1) where i is location where element should be inserted
|
||||
private int probe(Object pe) {
|
||||
int idx = Math.floorMod(pe.hashCode() ^ SALT, elements.length);
|
||||
while (true) {
|
||||
E ee = elements[idx];
|
||||
if (ee == null) {
|
||||
return -idx - 1;
|
||||
} else if (pe.equals(ee)) {
|
||||
return idx;
|
||||
} else if (++idx == elements.length) {
|
||||
idx = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
|
||||
throw new InvalidObjectException("not serial proxy");
|
||||
}
|
||||
|
||||
private Object writeReplace() {
|
||||
Object[] array = new Object[size];
|
||||
int dest = 0;
|
||||
for (Object o : elements) {
|
||||
if (o != null) {
|
||||
array[dest++] = o;
|
||||
}
|
||||
}
|
||||
return new CollSer(CollSer.IMM_SET, array);
|
||||
}
|
||||
}
|
||||
|
||||
// ---------- Map Implementations ----------
|
||||
|
||||
static final class Map0<K,V> extends AbstractMap<K,V> implements Serializable {
|
||||
Map0() { }
|
||||
|
||||
@Override
|
||||
public Set<Map.Entry<K,V>> entrySet() {
|
||||
return Set.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(Object o) {
|
||||
return super.containsKey(Objects.requireNonNull(o));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsValue(Object o) {
|
||||
return super.containsValue(Objects.requireNonNull(o));
|
||||
}
|
||||
|
||||
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
|
||||
throw new InvalidObjectException("not serial proxy");
|
||||
}
|
||||
|
||||
private Object writeReplace() {
|
||||
return new CollSer(CollSer.IMM_MAP);
|
||||
}
|
||||
}
|
||||
|
||||
static final class Map1<K,V> extends AbstractMap<K,V> implements Serializable {
|
||||
private final K k0;
|
||||
private final V v0;
|
||||
|
||||
Map1(K k0, V v0) {
|
||||
this.k0 = Objects.requireNonNull(k0);
|
||||
this.v0 = Objects.requireNonNull(v0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Map.Entry<K,V>> entrySet() {
|
||||
return Set.of(new KeyValueHolder<>(k0, v0));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(Object o) {
|
||||
return super.containsKey(Objects.requireNonNull(o));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsValue(Object o) {
|
||||
return super.containsValue(Objects.requireNonNull(o));
|
||||
}
|
||||
|
||||
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
|
||||
throw new InvalidObjectException("not serial proxy");
|
||||
}
|
||||
|
||||
private Object writeReplace() {
|
||||
return new CollSer(CollSer.IMM_MAP, k0, v0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An array-based Map implementation. There is a single array "table" that
|
||||
* contains keys and values interleaved: table[0] is kA, table[1] is vA,
|
||||
* table[2] is kB, table[3] is vB, etc. The table size must be even. It must
|
||||
* also be strictly larger than the size (the number of key-value pairs contained
|
||||
* in the map) so that at least one null key is always present.
|
||||
* @param <K> the key type
|
||||
* @param <V> the value type
|
||||
*/
|
||||
static final class MapN<K,V> extends AbstractMap<K,V> implements Serializable {
|
||||
private final Object[] table; // pairs of key, value
|
||||
private final int size; // number of pairs
|
||||
|
||||
MapN(Object... input) {
|
||||
Objects.requireNonNull(input);
|
||||
if ((input.length & 1) != 0) {
|
||||
throw new InternalError("length is odd");
|
||||
}
|
||||
size = input.length >> 1;
|
||||
|
||||
int len = (int)Math.ceil(EXPAND_FACTOR * input.length);
|
||||
len = (len + 1) & ~1; // ensure table is even length
|
||||
table = new Object[len];
|
||||
|
||||
for (int i = 0; i < input.length; i += 2) {
|
||||
@SuppressWarnings("unchecked")
|
||||
K k = Objects.requireNonNull((K)input[i]);
|
||||
@SuppressWarnings("unchecked")
|
||||
V v = Objects.requireNonNull((V)input[i+1]);
|
||||
int idx = probe(k);
|
||||
if (idx >= 0) {
|
||||
throw new IllegalArgumentException("duplicate key: " + k);
|
||||
} else {
|
||||
int dest = -(idx + 1);
|
||||
table[dest] = k;
|
||||
table[dest+1] = v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsKey(Object o) {
|
||||
return probe(Objects.requireNonNull(o)) >= 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsValue(Object o) {
|
||||
return super.containsValue(Objects.requireNonNull(o));
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public V get(Object o) {
|
||||
int i = probe(o);
|
||||
if (i >= 0) {
|
||||
return (V)table[i+1];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Map.Entry<K,V>> entrySet() {
|
||||
return new AbstractSet<Map.Entry<K,V>>() {
|
||||
@Override
|
||||
public int size() {
|
||||
return MapN.this.size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<Map.Entry<K,V>> iterator() {
|
||||
return new Iterator<Map.Entry<K,V>>() {
|
||||
int idx = 0;
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
while (idx < table.length) {
|
||||
if (table[idx] != null)
|
||||
return true;
|
||||
idx += 2;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map.Entry<K,V> next() {
|
||||
if (hasNext()) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Map.Entry<K,V> e =
|
||||
new KeyValueHolder<>((K)table[idx], (V)table[idx+1]);
|
||||
idx += 2;
|
||||
return e;
|
||||
} else {
|
||||
throw new NoSuchElementException();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// returns index at which the probe key is present; or if absent,
|
||||
// (-i - 1) where i is location where element should be inserted
|
||||
private int probe(Object pk) {
|
||||
int idx = Math.floorMod(pk.hashCode() ^ SALT, table.length >> 1) << 1;
|
||||
while (true) {
|
||||
@SuppressWarnings("unchecked")
|
||||
K ek = (K)table[idx];
|
||||
if (ek == null) {
|
||||
return -idx - 1;
|
||||
} else if (pk.equals(ek)) {
|
||||
return idx;
|
||||
} else if ((idx += 2) == table.length) {
|
||||
idx = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
|
||||
throw new InvalidObjectException("not serial proxy");
|
||||
}
|
||||
|
||||
private Object writeReplace() {
|
||||
Object[] array = new Object[2 * size];
|
||||
int len = table.length;
|
||||
int dest = 0;
|
||||
for (int i = 0; i < len; i += 2) {
|
||||
if (table[i] != null) {
|
||||
array[dest++] = table[i];
|
||||
array[dest++] = table[i+1];
|
||||
}
|
||||
}
|
||||
return new CollSer(CollSer.IMM_MAP, array);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ---------- Serialization Proxy ----------
|
||||
|
||||
/**
|
||||
* Serialization proxy class for immutable collections.
|
||||
*/
|
||||
final class CollSer implements Serializable {
|
||||
private static final long serialVersionUID = 6309168927139932177L;
|
||||
|
||||
static final int IMM_LIST = 1;
|
||||
static final int IMM_SET = 2;
|
||||
static final int IMM_MAP = 3;
|
||||
|
||||
private final int flags;
|
||||
private final Object[] array;
|
||||
|
||||
CollSer(int f, Object... a) {
|
||||
flags = f;
|
||||
array = a;
|
||||
}
|
||||
|
||||
private Object readResolve() throws ObjectStreamException {
|
||||
try {
|
||||
if (array == null) {
|
||||
throw new InvalidObjectException("null array");
|
||||
}
|
||||
|
||||
// use low order 8 bits to indicate "kind"
|
||||
// ignore high order bits
|
||||
switch (flags & 0xff) {
|
||||
case IMM_LIST:
|
||||
return List.of(array);
|
||||
case IMM_SET:
|
||||
return Set.of(array);
|
||||
case IMM_MAP:
|
||||
if (array.length == 0) {
|
||||
return new ImmutableCollections.Map0<>();
|
||||
} else if (array.length == 2) {
|
||||
return new ImmutableCollections.Map1<>(array[0], array[1]);
|
||||
} else {
|
||||
return new ImmutableCollections.MapN<>(array);
|
||||
}
|
||||
default:
|
||||
throw new InvalidObjectException(String.format("invalid flags 0x%x", flags));
|
||||
}
|
||||
} catch (NullPointerException|IllegalArgumentException ex) {
|
||||
InvalidObjectException ioe = new InvalidObjectException("invalid object");
|
||||
ioe.initCause(ex);
|
||||
throw ioe;
|
||||
}
|
||||
}
|
||||
}
|
@ -765,7 +765,7 @@ public interface List<E> extends Collection<E> {
|
||||
* @since 9
|
||||
*/
|
||||
static <E> List<E> of() {
|
||||
return Collections.emptyList();
|
||||
return new ImmutableCollections.List0<>();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -781,7 +781,7 @@ public interface List<E> extends Collection<E> {
|
||||
* @since 9
|
||||
*/
|
||||
static <E> List<E> of(E e1) {
|
||||
return Collections.singletonList(Objects.requireNonNull(e1));
|
||||
return new ImmutableCollections.List1<>(e1);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -798,9 +798,7 @@ public interface List<E> extends Collection<E> {
|
||||
* @since 9
|
||||
*/
|
||||
static <E> List<E> of(E e1, E e2) {
|
||||
return Collections.unmodifiableList(
|
||||
Arrays.asList(Objects.requireNonNull(e1),
|
||||
Objects.requireNonNull(e2)));
|
||||
return new ImmutableCollections.List2<>(e1, e2);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -818,10 +816,7 @@ public interface List<E> extends Collection<E> {
|
||||
* @since 9
|
||||
*/
|
||||
static <E> List<E> of(E e1, E e2, E e3) {
|
||||
return Collections.unmodifiableList(
|
||||
Arrays.asList(Objects.requireNonNull(e1),
|
||||
Objects.requireNonNull(e2),
|
||||
Objects.requireNonNull(e3)));
|
||||
return new ImmutableCollections.ListN<>(e1, e2, e3);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -840,11 +835,7 @@ public interface List<E> extends Collection<E> {
|
||||
* @since 9
|
||||
*/
|
||||
static <E> List<E> of(E e1, E e2, E e3, E e4) {
|
||||
return Collections.unmodifiableList(
|
||||
Arrays.asList(Objects.requireNonNull(e1),
|
||||
Objects.requireNonNull(e2),
|
||||
Objects.requireNonNull(e3),
|
||||
Objects.requireNonNull(e4)));
|
||||
return new ImmutableCollections.ListN<>(e1, e2, e3, e4);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -864,12 +855,7 @@ public interface List<E> extends Collection<E> {
|
||||
* @since 9
|
||||
*/
|
||||
static <E> List<E> of(E e1, E e2, E e3, E e4, E e5) {
|
||||
return Collections.unmodifiableList(
|
||||
Arrays.asList(Objects.requireNonNull(e1),
|
||||
Objects.requireNonNull(e2),
|
||||
Objects.requireNonNull(e3),
|
||||
Objects.requireNonNull(e4),
|
||||
Objects.requireNonNull(e5)));
|
||||
return new ImmutableCollections.ListN<>(e1, e2, e3, e4, e5);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -890,13 +876,8 @@ public interface List<E> extends Collection<E> {
|
||||
* @since 9
|
||||
*/
|
||||
static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6) {
|
||||
return Collections.unmodifiableList(
|
||||
Arrays.asList(Objects.requireNonNull(e1),
|
||||
Objects.requireNonNull(e2),
|
||||
Objects.requireNonNull(e3),
|
||||
Objects.requireNonNull(e4),
|
||||
Objects.requireNonNull(e5),
|
||||
Objects.requireNonNull(e6)));
|
||||
return new ImmutableCollections.ListN<>(e1, e2, e3, e4, e5,
|
||||
e6);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -918,14 +899,8 @@ public interface List<E> extends Collection<E> {
|
||||
* @since 9
|
||||
*/
|
||||
static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7) {
|
||||
return Collections.unmodifiableList(
|
||||
Arrays.asList(Objects.requireNonNull(e1),
|
||||
Objects.requireNonNull(e2),
|
||||
Objects.requireNonNull(e3),
|
||||
Objects.requireNonNull(e4),
|
||||
Objects.requireNonNull(e5),
|
||||
Objects.requireNonNull(e6),
|
||||
Objects.requireNonNull(e7)));
|
||||
return new ImmutableCollections.ListN<>(e1, e2, e3, e4, e5,
|
||||
e6, e7);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -948,15 +923,8 @@ public interface List<E> extends Collection<E> {
|
||||
* @since 9
|
||||
*/
|
||||
static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8) {
|
||||
return Collections.unmodifiableList(
|
||||
Arrays.asList(Objects.requireNonNull(e1),
|
||||
Objects.requireNonNull(e2),
|
||||
Objects.requireNonNull(e3),
|
||||
Objects.requireNonNull(e4),
|
||||
Objects.requireNonNull(e5),
|
||||
Objects.requireNonNull(e6),
|
||||
Objects.requireNonNull(e7),
|
||||
Objects.requireNonNull(e8)));
|
||||
return new ImmutableCollections.ListN<>(e1, e2, e3, e4, e5,
|
||||
e6, e7, e8);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -980,16 +948,8 @@ public interface List<E> extends Collection<E> {
|
||||
* @since 9
|
||||
*/
|
||||
static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9) {
|
||||
return Collections.unmodifiableList(
|
||||
Arrays.asList(Objects.requireNonNull(e1),
|
||||
Objects.requireNonNull(e2),
|
||||
Objects.requireNonNull(e3),
|
||||
Objects.requireNonNull(e4),
|
||||
Objects.requireNonNull(e5),
|
||||
Objects.requireNonNull(e6),
|
||||
Objects.requireNonNull(e7),
|
||||
Objects.requireNonNull(e8),
|
||||
Objects.requireNonNull(e9)));
|
||||
return new ImmutableCollections.ListN<>(e1, e2, e3, e4, e5,
|
||||
e6, e7, e8, e9);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1014,17 +974,8 @@ public interface List<E> extends Collection<E> {
|
||||
* @since 9
|
||||
*/
|
||||
static <E> List<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10) {
|
||||
return Collections.unmodifiableList(
|
||||
Arrays.asList(Objects.requireNonNull(e1),
|
||||
Objects.requireNonNull(e2),
|
||||
Objects.requireNonNull(e3),
|
||||
Objects.requireNonNull(e4),
|
||||
Objects.requireNonNull(e5),
|
||||
Objects.requireNonNull(e6),
|
||||
Objects.requireNonNull(e7),
|
||||
Objects.requireNonNull(e8),
|
||||
Objects.requireNonNull(e9),
|
||||
Objects.requireNonNull(e10)));
|
||||
return new ImmutableCollections.ListN<>(e1, e2, e3, e4, e5,
|
||||
e6, e7, e8, e9, e10);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1055,10 +1006,16 @@ public interface List<E> extends Collection<E> {
|
||||
@SafeVarargs
|
||||
@SuppressWarnings("varargs")
|
||||
static <E> List<E> of(E... elements) {
|
||||
elements = elements.clone(); // throws NPE if es is null
|
||||
for (E e : elements) {
|
||||
Objects.requireNonNull(e);
|
||||
Objects.requireNonNull(elements);
|
||||
switch (elements.length) {
|
||||
case 0:
|
||||
return new ImmutableCollections.List0<>();
|
||||
case 1:
|
||||
return new ImmutableCollections.List1<>(elements[0]);
|
||||
case 2:
|
||||
return new ImmutableCollections.List2<>(elements[0], elements[1]);
|
||||
default:
|
||||
return new ImmutableCollections.ListN<>(elements);
|
||||
}
|
||||
return Collections.unmodifiableList(Arrays.asList(elements));
|
||||
}
|
||||
}
|
||||
|
@ -1282,7 +1282,7 @@ public interface Map<K, V> {
|
||||
* @since 9
|
||||
*/
|
||||
static <K, V> Map<K, V> of() {
|
||||
return Collections.emptyMap();
|
||||
return new ImmutableCollections.Map0<>();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1299,7 +1299,7 @@ public interface Map<K, V> {
|
||||
* @since 9
|
||||
*/
|
||||
static <K, V> Map<K, V> of(K k1, V v1) {
|
||||
return Collections.singletonMap(Objects.requireNonNull(k1), Objects.requireNonNull(v1));
|
||||
return new ImmutableCollections.Map1<>(k1, v1);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1319,13 +1319,7 @@ public interface Map<K, V> {
|
||||
* @since 9
|
||||
*/
|
||||
static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2) {
|
||||
Map<K, V> map = new HashMap<>(3); // specify number of buckets to avoid resizing
|
||||
map.put(Objects.requireNonNull(k1), Objects.requireNonNull(v1));
|
||||
map.put(Objects.requireNonNull(k2), Objects.requireNonNull(v2));
|
||||
if (map.size() != 2) {
|
||||
throw new IllegalArgumentException("duplicate keys");
|
||||
}
|
||||
return Collections.unmodifiableMap(map);
|
||||
return new ImmutableCollections.MapN<>(k1, v1, k2, v2);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1347,14 +1341,7 @@ public interface Map<K, V> {
|
||||
* @since 9
|
||||
*/
|
||||
static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3) {
|
||||
Map<K, V> map = new HashMap<>(5); // specify number of buckets to avoid resizing
|
||||
map.put(Objects.requireNonNull(k1), Objects.requireNonNull(v1));
|
||||
map.put(Objects.requireNonNull(k2), Objects.requireNonNull(v2));
|
||||
map.put(Objects.requireNonNull(k3), Objects.requireNonNull(v3));
|
||||
if (map.size() != 3) {
|
||||
throw new IllegalArgumentException("duplicate keys");
|
||||
}
|
||||
return Collections.unmodifiableMap(map);
|
||||
return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1378,15 +1365,7 @@ public interface Map<K, V> {
|
||||
* @since 9
|
||||
*/
|
||||
static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) {
|
||||
Map<K, V> map = new HashMap<>(6); // specify number of buckets to avoid resizing
|
||||
map.put(Objects.requireNonNull(k1), Objects.requireNonNull(v1));
|
||||
map.put(Objects.requireNonNull(k2), Objects.requireNonNull(v2));
|
||||
map.put(Objects.requireNonNull(k3), Objects.requireNonNull(v3));
|
||||
map.put(Objects.requireNonNull(k4), Objects.requireNonNull(v4));
|
||||
if (map.size() != 4) {
|
||||
throw new IllegalArgumentException("duplicate keys");
|
||||
}
|
||||
return Collections.unmodifiableMap(map);
|
||||
return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1412,16 +1391,7 @@ public interface Map<K, V> {
|
||||
* @since 9
|
||||
*/
|
||||
static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) {
|
||||
Map<K, V> map = new HashMap<>(7); // specify number of buckets to avoid resizing
|
||||
map.put(Objects.requireNonNull(k1), Objects.requireNonNull(v1));
|
||||
map.put(Objects.requireNonNull(k2), Objects.requireNonNull(v2));
|
||||
map.put(Objects.requireNonNull(k3), Objects.requireNonNull(v3));
|
||||
map.put(Objects.requireNonNull(k4), Objects.requireNonNull(v4));
|
||||
map.put(Objects.requireNonNull(k5), Objects.requireNonNull(v5));
|
||||
if (map.size() != 5) {
|
||||
throw new IllegalArgumentException("duplicate keys");
|
||||
}
|
||||
return Collections.unmodifiableMap(map);
|
||||
return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1450,17 +1420,8 @@ public interface Map<K, V> {
|
||||
*/
|
||||
static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5,
|
||||
K k6, V v6) {
|
||||
Map<K, V> map = new HashMap<>(9); // specify number of buckets to avoid resizing
|
||||
map.put(Objects.requireNonNull(k1), Objects.requireNonNull(v1));
|
||||
map.put(Objects.requireNonNull(k2), Objects.requireNonNull(v2));
|
||||
map.put(Objects.requireNonNull(k3), Objects.requireNonNull(v3));
|
||||
map.put(Objects.requireNonNull(k4), Objects.requireNonNull(v4));
|
||||
map.put(Objects.requireNonNull(k5), Objects.requireNonNull(v5));
|
||||
map.put(Objects.requireNonNull(k6), Objects.requireNonNull(v6));
|
||||
if (map.size() != 6) {
|
||||
throw new IllegalArgumentException("duplicate keys");
|
||||
}
|
||||
return Collections.unmodifiableMap(map);
|
||||
return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5,
|
||||
k6, v6);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1491,18 +1452,8 @@ public interface Map<K, V> {
|
||||
*/
|
||||
static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5,
|
||||
K k6, V v6, K k7, V v7) {
|
||||
Map<K, V> map = new HashMap<>(10); // specify number of buckets to avoid resizing
|
||||
map.put(Objects.requireNonNull(k1), Objects.requireNonNull(v1));
|
||||
map.put(Objects.requireNonNull(k2), Objects.requireNonNull(v2));
|
||||
map.put(Objects.requireNonNull(k3), Objects.requireNonNull(v3));
|
||||
map.put(Objects.requireNonNull(k4), Objects.requireNonNull(v4));
|
||||
map.put(Objects.requireNonNull(k5), Objects.requireNonNull(v5));
|
||||
map.put(Objects.requireNonNull(k6), Objects.requireNonNull(v6));
|
||||
map.put(Objects.requireNonNull(k7), Objects.requireNonNull(v7));
|
||||
if (map.size() != 7) {
|
||||
throw new IllegalArgumentException("duplicate keys");
|
||||
}
|
||||
return Collections.unmodifiableMap(map);
|
||||
return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5,
|
||||
k6, v6, k7, v7);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1535,19 +1486,8 @@ public interface Map<K, V> {
|
||||
*/
|
||||
static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5,
|
||||
K k6, V v6, K k7, V v7, K k8, V v8) {
|
||||
Map<K, V> map = new HashMap<>(11); // specify number of buckets to avoid resizing
|
||||
map.put(Objects.requireNonNull(k1), Objects.requireNonNull(v1));
|
||||
map.put(Objects.requireNonNull(k2), Objects.requireNonNull(v2));
|
||||
map.put(Objects.requireNonNull(k3), Objects.requireNonNull(v3));
|
||||
map.put(Objects.requireNonNull(k4), Objects.requireNonNull(v4));
|
||||
map.put(Objects.requireNonNull(k5), Objects.requireNonNull(v5));
|
||||
map.put(Objects.requireNonNull(k6), Objects.requireNonNull(v6));
|
||||
map.put(Objects.requireNonNull(k7), Objects.requireNonNull(v7));
|
||||
map.put(Objects.requireNonNull(k8), Objects.requireNonNull(v8));
|
||||
if (map.size() != 8) {
|
||||
throw new IllegalArgumentException("duplicate keys");
|
||||
}
|
||||
return Collections.unmodifiableMap(map);
|
||||
return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5,
|
||||
k6, v6, k7, v7, k8, v8);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1582,20 +1522,8 @@ public interface Map<K, V> {
|
||||
*/
|
||||
static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5,
|
||||
K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9) {
|
||||
Map<K, V> map = new HashMap<>(13); // specify number of buckets to avoid resizing
|
||||
map.put(Objects.requireNonNull(k1), Objects.requireNonNull(v1));
|
||||
map.put(Objects.requireNonNull(k2), Objects.requireNonNull(v2));
|
||||
map.put(Objects.requireNonNull(k3), Objects.requireNonNull(v3));
|
||||
map.put(Objects.requireNonNull(k4), Objects.requireNonNull(v4));
|
||||
map.put(Objects.requireNonNull(k5), Objects.requireNonNull(v5));
|
||||
map.put(Objects.requireNonNull(k6), Objects.requireNonNull(v6));
|
||||
map.put(Objects.requireNonNull(k7), Objects.requireNonNull(v7));
|
||||
map.put(Objects.requireNonNull(k8), Objects.requireNonNull(v8));
|
||||
map.put(Objects.requireNonNull(k9), Objects.requireNonNull(v9));
|
||||
if (map.size() != 9) {
|
||||
throw new IllegalArgumentException("duplicate keys");
|
||||
}
|
||||
return Collections.unmodifiableMap(map);
|
||||
return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5,
|
||||
k6, v6, k7, v7, k8, v8, k9, v9);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1632,21 +1560,8 @@ public interface Map<K, V> {
|
||||
*/
|
||||
static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5,
|
||||
K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10) {
|
||||
Map<K, V> map = new HashMap<>(14); // specify number of buckets to avoid resizing
|
||||
map.put(Objects.requireNonNull(k1), Objects.requireNonNull(v1));
|
||||
map.put(Objects.requireNonNull(k2), Objects.requireNonNull(v2));
|
||||
map.put(Objects.requireNonNull(k3), Objects.requireNonNull(v3));
|
||||
map.put(Objects.requireNonNull(k4), Objects.requireNonNull(v4));
|
||||
map.put(Objects.requireNonNull(k5), Objects.requireNonNull(v5));
|
||||
map.put(Objects.requireNonNull(k6), Objects.requireNonNull(v6));
|
||||
map.put(Objects.requireNonNull(k7), Objects.requireNonNull(v7));
|
||||
map.put(Objects.requireNonNull(k8), Objects.requireNonNull(v8));
|
||||
map.put(Objects.requireNonNull(k9), Objects.requireNonNull(v9));
|
||||
map.put(Objects.requireNonNull(k10), Objects.requireNonNull(v10));
|
||||
if (map.size() != 10) {
|
||||
throw new IllegalArgumentException("duplicate keys");
|
||||
}
|
||||
return Collections.unmodifiableMap(map);
|
||||
return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5,
|
||||
k6, v6, k7, v7, k8, v8, k9, v9, k10, v10);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1683,15 +1598,21 @@ public interface Map<K, V> {
|
||||
@SafeVarargs
|
||||
@SuppressWarnings("varargs")
|
||||
static <K, V> Map<K, V> ofEntries(Entry<? extends K, ? extends V>... entries) {
|
||||
Map<K, V> map = new HashMap<>(entries.length * 4 / 3 + 1); // throws NPE if entries is null
|
||||
for (Entry<? extends K, ? extends V> e : entries) {
|
||||
// next line throws NPE if e is null
|
||||
map.put(Objects.requireNonNull(e.getKey()), Objects.requireNonNull(e.getValue()));
|
||||
Objects.requireNonNull(entries);
|
||||
if (entries.length == 0) {
|
||||
return new ImmutableCollections.Map0<>();
|
||||
} else if (entries.length == 1) {
|
||||
return new ImmutableCollections.Map1<>(entries[0].getKey(),
|
||||
entries[0].getValue());
|
||||
} else {
|
||||
Object[] kva = new Object[entries.length << 1];
|
||||
int a = 0;
|
||||
for (Entry<? extends K, ? extends V> entry : entries) {
|
||||
kva[a++] = entry.getKey();
|
||||
kva[a++] = entry.getValue();
|
||||
}
|
||||
return new ImmutableCollections.MapN<>(kva);
|
||||
}
|
||||
if (map.size() != entries.length) {
|
||||
throw new IllegalArgumentException("duplicate keys");
|
||||
}
|
||||
return Collections.unmodifiableMap(map);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -444,7 +444,7 @@ public interface Set<E> extends Collection<E> {
|
||||
* @since 9
|
||||
*/
|
||||
static <E> Set<E> of() {
|
||||
return Collections.emptySet();
|
||||
return new ImmutableCollections.Set0<>();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -459,7 +459,7 @@ public interface Set<E> extends Collection<E> {
|
||||
* @since 9
|
||||
*/
|
||||
static <E> Set<E> of(E e1) {
|
||||
return Collections.singleton(Objects.requireNonNull(e1));
|
||||
return new ImmutableCollections.Set1<>(e1);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -476,12 +476,7 @@ public interface Set<E> extends Collection<E> {
|
||||
* @since 9
|
||||
*/
|
||||
static <E> Set<E> of(E e1, E e2) {
|
||||
Set<E> set = new HashSet<>(Arrays.asList(Objects.requireNonNull(e1),
|
||||
Objects.requireNonNull(e2)));
|
||||
if (set.size() != 2) {
|
||||
throw new IllegalArgumentException("duplicate elements");
|
||||
}
|
||||
return Collections.unmodifiableSet(set);
|
||||
return new ImmutableCollections.Set2<>(e1, e2);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -499,13 +494,7 @@ public interface Set<E> extends Collection<E> {
|
||||
* @since 9
|
||||
*/
|
||||
static <E> Set<E> of(E e1, E e2, E e3) {
|
||||
Set<E> set = new HashSet<>(Arrays.asList(Objects.requireNonNull(e1),
|
||||
Objects.requireNonNull(e2),
|
||||
Objects.requireNonNull(e3)));
|
||||
if (set.size() != 3) {
|
||||
throw new IllegalArgumentException("duplicate elements");
|
||||
}
|
||||
return Collections.unmodifiableSet(set);
|
||||
return new ImmutableCollections.SetN<>(e1, e2, e3);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -524,14 +513,7 @@ public interface Set<E> extends Collection<E> {
|
||||
* @since 9
|
||||
*/
|
||||
static <E> Set<E> of(E e1, E e2, E e3, E e4) {
|
||||
Set<E> set = new HashSet<>(Arrays.asList(Objects.requireNonNull(e1),
|
||||
Objects.requireNonNull(e2),
|
||||
Objects.requireNonNull(e3),
|
||||
Objects.requireNonNull(e4)));
|
||||
if (set.size() != 4) {
|
||||
throw new IllegalArgumentException("duplicate elements");
|
||||
}
|
||||
return Collections.unmodifiableSet(set);
|
||||
return new ImmutableCollections.SetN<>(e1, e2, e3, e4);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -551,15 +533,7 @@ public interface Set<E> extends Collection<E> {
|
||||
* @since 9
|
||||
*/
|
||||
static <E> Set<E> of(E e1, E e2, E e3, E e4, E e5) {
|
||||
Set<E> set = new HashSet<>(Arrays.asList(Objects.requireNonNull(e1),
|
||||
Objects.requireNonNull(e2),
|
||||
Objects.requireNonNull(e3),
|
||||
Objects.requireNonNull(e4),
|
||||
Objects.requireNonNull(e5)));
|
||||
if (set.size() != 5) {
|
||||
throw new IllegalArgumentException("duplicate elements");
|
||||
}
|
||||
return Collections.unmodifiableSet(set);
|
||||
return new ImmutableCollections.SetN<>(e1, e2, e3, e4, e5);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -580,16 +554,8 @@ public interface Set<E> extends Collection<E> {
|
||||
* @since 9
|
||||
*/
|
||||
static <E> Set<E> of(E e1, E e2, E e3, E e4, E e5, E e6) {
|
||||
Set<E> set = new HashSet<>(Arrays.asList(Objects.requireNonNull(e1),
|
||||
Objects.requireNonNull(e2),
|
||||
Objects.requireNonNull(e3),
|
||||
Objects.requireNonNull(e4),
|
||||
Objects.requireNonNull(e5),
|
||||
Objects.requireNonNull(e6)));
|
||||
if (set.size() != 6) {
|
||||
throw new IllegalArgumentException("duplicate elements");
|
||||
}
|
||||
return Collections.unmodifiableSet(set);
|
||||
return new ImmutableCollections.SetN<>(e1, e2, e3, e4, e5,
|
||||
e6);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -611,17 +577,8 @@ public interface Set<E> extends Collection<E> {
|
||||
* @since 9
|
||||
*/
|
||||
static <E> Set<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7) {
|
||||
Set<E> set = new HashSet<>(Arrays.asList(Objects.requireNonNull(e1),
|
||||
Objects.requireNonNull(e2),
|
||||
Objects.requireNonNull(e3),
|
||||
Objects.requireNonNull(e4),
|
||||
Objects.requireNonNull(e5),
|
||||
Objects.requireNonNull(e6),
|
||||
Objects.requireNonNull(e7)));
|
||||
if (set.size() != 7) {
|
||||
throw new IllegalArgumentException("duplicate elements");
|
||||
}
|
||||
return Collections.unmodifiableSet(set);
|
||||
return new ImmutableCollections.SetN<>(e1, e2, e3, e4, e5,
|
||||
e6, e7);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -644,18 +601,8 @@ public interface Set<E> extends Collection<E> {
|
||||
* @since 9
|
||||
*/
|
||||
static <E> Set<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8) {
|
||||
Set<E> set = new HashSet<>(Arrays.asList(Objects.requireNonNull(e1),
|
||||
Objects.requireNonNull(e2),
|
||||
Objects.requireNonNull(e3),
|
||||
Objects.requireNonNull(e4),
|
||||
Objects.requireNonNull(e5),
|
||||
Objects.requireNonNull(e6),
|
||||
Objects.requireNonNull(e7),
|
||||
Objects.requireNonNull(e8)));
|
||||
if (set.size() != 8) {
|
||||
throw new IllegalArgumentException("duplicate elements");
|
||||
}
|
||||
return Collections.unmodifiableSet(set);
|
||||
return new ImmutableCollections.SetN<>(e1, e2, e3, e4, e5,
|
||||
e6, e7, e8);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -679,19 +626,8 @@ public interface Set<E> extends Collection<E> {
|
||||
* @since 9
|
||||
*/
|
||||
static <E> Set<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9) {
|
||||
Set<E> set = new HashSet<>(Arrays.asList(Objects.requireNonNull(e1),
|
||||
Objects.requireNonNull(e2),
|
||||
Objects.requireNonNull(e3),
|
||||
Objects.requireNonNull(e4),
|
||||
Objects.requireNonNull(e5),
|
||||
Objects.requireNonNull(e6),
|
||||
Objects.requireNonNull(e7),
|
||||
Objects.requireNonNull(e8),
|
||||
Objects.requireNonNull(e9)));
|
||||
if (set.size() != 9) {
|
||||
throw new IllegalArgumentException("duplicate elements");
|
||||
}
|
||||
return Collections.unmodifiableSet(set);
|
||||
return new ImmutableCollections.SetN<>(e1, e2, e3, e4, e5,
|
||||
e6, e7, e8, e9);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -716,20 +652,8 @@ public interface Set<E> extends Collection<E> {
|
||||
* @since 9
|
||||
*/
|
||||
static <E> Set<E> of(E e1, E e2, E e3, E e4, E e5, E e6, E e7, E e8, E e9, E e10) {
|
||||
Set<E> set = new HashSet<>(Arrays.asList(Objects.requireNonNull(e1),
|
||||
Objects.requireNonNull(e2),
|
||||
Objects.requireNonNull(e3),
|
||||
Objects.requireNonNull(e4),
|
||||
Objects.requireNonNull(e5),
|
||||
Objects.requireNonNull(e6),
|
||||
Objects.requireNonNull(e7),
|
||||
Objects.requireNonNull(e8),
|
||||
Objects.requireNonNull(e9),
|
||||
Objects.requireNonNull(e10)));
|
||||
if (set.size() != 10) {
|
||||
throw new IllegalArgumentException("duplicate elements");
|
||||
}
|
||||
return Collections.unmodifiableSet(set);
|
||||
return new ImmutableCollections.SetN<>(e1, e2, e3, e4, e5,
|
||||
e6, e7, e8, e9, e10);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -759,15 +683,18 @@ public interface Set<E> extends Collection<E> {
|
||||
* @since 9
|
||||
*/
|
||||
@SafeVarargs
|
||||
@SuppressWarnings("varargs")
|
||||
static <E> Set<E> of(E... elements) {
|
||||
for (E e : elements) { // throws NPE if es is null
|
||||
Objects.requireNonNull(e);
|
||||
Objects.requireNonNull(elements);
|
||||
switch (elements.length) {
|
||||
case 0:
|
||||
return new ImmutableCollections.Set0<>();
|
||||
case 1:
|
||||
return new ImmutableCollections.Set1<>(elements[0]);
|
||||
case 2:
|
||||
return new ImmutableCollections.Set2<>(elements[0], elements[1]);
|
||||
default:
|
||||
return new ImmutableCollections.SetN<>(elements);
|
||||
}
|
||||
@SuppressWarnings("varargs")
|
||||
Set<E> set = new HashSet<>(Arrays.asList(elements));
|
||||
if (set.size() != elements.length) {
|
||||
throw new IllegalArgumentException("duplicate elements");
|
||||
}
|
||||
return Collections.unmodifiableSet(set);
|
||||
}
|
||||
}
|
||||
|
@ -658,6 +658,28 @@ class JarFile extends ZipFile {
|
||||
return vze == null ? ze : vze;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the real name of a {@code JarEntry}. If this {@code JarFile} is
|
||||
* a multi-release jar file and is configured to be processed as such, the
|
||||
* name returned by this method is the path name of the versioned entry
|
||||
* that the {@code JarEntry} represents, rather than the path name of the
|
||||
* base entry that {@link JarEntry#getName()} returns. If the
|
||||
* {@code JarEntry} does not represent a versioned entry, or the
|
||||
* jar file is not a multi-release jar file or {@code JarFile} is not
|
||||
* configured for processing a multi-release jar file, this method returns
|
||||
* the same name that {@link JarEntry#getName()} returns.
|
||||
*
|
||||
* @param entry the JarEntry
|
||||
* @return the real name of the JarEntry
|
||||
* @since 9
|
||||
*/
|
||||
String getRealName(JarEntry entry) {
|
||||
if (entry instanceof JarFileEntry) {
|
||||
return ((JarFileEntry)entry).realName();
|
||||
}
|
||||
return entry.getName();
|
||||
}
|
||||
|
||||
private class JarFileEntry extends JarEntry {
|
||||
final private String name;
|
||||
|
||||
@ -684,7 +706,7 @@ class JarFile extends ZipFile {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
if (certs == null && jv != null) {
|
||||
certs = jv.getCerts(JarFile.this, reifiedEntry());
|
||||
certs = jv.getCerts(JarFile.this, realEntry());
|
||||
}
|
||||
return certs == null ? null : certs.clone();
|
||||
}
|
||||
@ -695,17 +717,20 @@ class JarFile extends ZipFile {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
if (signers == null && jv != null) {
|
||||
signers = jv.getCodeSigners(JarFile.this, reifiedEntry());
|
||||
signers = jv.getCodeSigners(JarFile.this, realEntry());
|
||||
}
|
||||
return signers == null ? null : signers.clone();
|
||||
}
|
||||
JarFileEntry reifiedEntry() {
|
||||
JarFileEntry realEntry() {
|
||||
if (isMultiRelease()) {
|
||||
String entryName = super.getName();
|
||||
return entryName.equals(this.name) ? this : new JarFileEntry(entryName, this);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
String realName() {
|
||||
return super.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
@ -876,11 +901,11 @@ class JarFile extends ZipFile {
|
||||
private JarEntry verifiableEntry(ZipEntry ze) {
|
||||
if (ze instanceof JarFileEntry) {
|
||||
// assure the name and entry match for verification
|
||||
return ((JarFileEntry)ze).reifiedEntry();
|
||||
return ((JarFileEntry)ze).realEntry();
|
||||
}
|
||||
ze = getJarEntry(ze.getName());
|
||||
if (ze instanceof JarFileEntry) {
|
||||
return ((JarFileEntry)ze).reifiedEntry();
|
||||
return ((JarFileEntry)ze).realEntry();
|
||||
}
|
||||
return (JarEntry)ze;
|
||||
}
|
||||
|
@ -60,4 +60,8 @@ class JavaUtilJarAccessImpl implements JavaUtilJarAccess {
|
||||
public List<Object> getManifestDigests(JarFile jar) {
|
||||
return jar.getManifestDigests();
|
||||
}
|
||||
|
||||
public String getRealName(JarFile jar, JarEntry entry) {
|
||||
return jar.getRealName(entry);
|
||||
}
|
||||
}
|
||||
|
@ -372,9 +372,15 @@ public class URLClassPath {
|
||||
return java.security.AccessController.doPrivileged(
|
||||
new java.security.PrivilegedExceptionAction<>() {
|
||||
public Loader run() throws IOException {
|
||||
String protocol = url.getProtocol(); // lower cased in URL
|
||||
String file = url.getFile();
|
||||
if (file != null && file.endsWith("/")) {
|
||||
if ("file".equals(url.getProtocol())) {
|
||||
if ("jar".equals(protocol)
|
||||
&& file != null && (file.indexOf("!/") == file.length() - 2)) {
|
||||
// extract the nested URL
|
||||
URL nestedUrl = new URL(file.substring(0, file.length() - 2));
|
||||
return new JarLoader(nestedUrl, jarHandler, lmap);
|
||||
} else if (file != null && file.endsWith("/")) {
|
||||
if ("file".equals(protocol)) {
|
||||
return new FileLoader(url);
|
||||
} else {
|
||||
return new Loader(url);
|
||||
@ -718,13 +724,13 @@ public class URLClassPath {
|
||||
|
||||
final URL url;
|
||||
try {
|
||||
String nm;
|
||||
if (jar.isMultiRelease()) {
|
||||
// add #runtime fragment to tell JarURLConnection to use
|
||||
// runtime versioning if the underlying jar file is multi-release
|
||||
url = new URL(getBaseURL(), ParseUtil.encodePath(name, false) + "#runtime");
|
||||
nm = SharedSecrets.javaUtilJarAccess().getRealName(jar, entry);
|
||||
} else {
|
||||
url = new URL(getBaseURL(), ParseUtil.encodePath(name, false));
|
||||
nm = name;
|
||||
}
|
||||
url = new URL(getBaseURL(), ParseUtil.encodePath(nm, false));
|
||||
if (check) {
|
||||
URLClassPath.check(url);
|
||||
}
|
||||
@ -940,7 +946,8 @@ public class URLClassPath {
|
||||
|
||||
ensureOpen();
|
||||
|
||||
if (SharedSecrets.javaUtilJarAccess().jarFileHasClassPathAttribute(jar)) { // Only get manifest when necessary
|
||||
// Only get manifest when necessary
|
||||
if (SharedSecrets.javaUtilJarAccess().jarFileHasClassPathAttribute(jar)) {
|
||||
Manifest man = jar.getManifest();
|
||||
if (man != null) {
|
||||
Attributes attr = man.getMainAttributes();
|
||||
|
@ -41,4 +41,5 @@ public interface JavaUtilJarAccess {
|
||||
public Enumeration<JarEntry> entries2(JarFile jar);
|
||||
public void setEagerValidation(JarFile jar, boolean eager);
|
||||
public List<Object> getManifestDigests(JarFile jar);
|
||||
public String getRealName(JarFile jar, JarEntry entry);
|
||||
}
|
||||
|
@ -145,6 +145,8 @@ module java.base {
|
||||
jdk.scripting.nashorn;
|
||||
exports jdk.internal.org.objectweb.asm.signature to
|
||||
jdk.scripting.nashorn;
|
||||
exports jdk.internal.loader to
|
||||
java.instrument;
|
||||
exports jdk.internal.math to
|
||||
java.desktop;
|
||||
exports jdk.internal.module to
|
||||
|
@ -84,8 +84,10 @@ import java.util.jar.Manifest;
|
||||
import jdk.internal.misc.VM;
|
||||
|
||||
|
||||
public enum LauncherHelper {
|
||||
INSTANCE;
|
||||
public final class LauncherHelper {
|
||||
|
||||
// No instantiation
|
||||
private LauncherHelper() {}
|
||||
|
||||
// used to identify JavaFX applications
|
||||
private static final String JAVAFX_APPLICATION_MARKER =
|
||||
|
@ -0,0 +1,771 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.provider;
|
||||
|
||||
import sun.security.util.Debug;
|
||||
|
||||
import java.security.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
import static java.security.DrbgParameters.Capability.*;
|
||||
|
||||
/**
|
||||
* The abstract base class for all DRBGs.
|
||||
* <p>
|
||||
* This class creates 5 new abstract methods. 3 are defined by the SP800-90A:
|
||||
* <ol>
|
||||
* <li>{@link #generateAlgorithm(byte[], byte[])}
|
||||
* <li>{@link #reseedAlgorithm(byte[], byte[])} (might not be supported)
|
||||
* <li>{@link #instantiateAlgorithm(byte[])}
|
||||
* </ol>
|
||||
* and 2 for implementation purpose:
|
||||
* <ol>
|
||||
* <li>{@link #initEngine()}
|
||||
* <li>{@link #chooseAlgorithmAndStrength}
|
||||
* </ol>
|
||||
* All existing {@link SecureRandomSpi} methods are implemented based on the
|
||||
* methods above as final. The initialization process is divided into 2 phases:
|
||||
* configuration is eagerly called to set up parameters, and instantiation
|
||||
* is lazily called only when nextBytes or reseed is called.
|
||||
* <p>
|
||||
* Synchronized keyword should be added to all externally callable engine
|
||||
* methods including {@link #engineReseed}, {@link #engineSetSeed}, and
|
||||
* {@link #engineNextBytes} (but not {@link #engineGenerateSeed}).
|
||||
* Internal methods like {@link #configure} and {@link #instantiateAlgorithm}
|
||||
* are not synchronized. They will either be called in a constructor or
|
||||
* in another synchronized method.
|
||||
*/
|
||||
public abstract class AbstractDrbg extends SecureRandomSpi {
|
||||
|
||||
private static final long serialVersionUID = 9L;
|
||||
|
||||
/**
|
||||
* This field is not null if {@code -Djava.security.debug=securerandom} is
|
||||
* specified on the command line. An implementation can print useful
|
||||
* debug info.
|
||||
*/
|
||||
protected static final Debug debug = Debug.getInstance(
|
||||
"securerandom", "drbg");
|
||||
|
||||
// Common working status
|
||||
|
||||
private transient boolean instantiated = false;
|
||||
|
||||
/**
|
||||
* Reseed counter of a DRBG instance. A mechanism should increment it
|
||||
* after each random bits generation and reset it in reseed. A mechanism
|
||||
* does <em>not</em> need to compare it to {@link #reseedInterval}.
|
||||
*/
|
||||
protected transient int reseedCounter = 0;
|
||||
|
||||
// Mech features. If not same as below, must be redefined in constructor.
|
||||
|
||||
/**
|
||||
* Default strength of a DRBG instance if it is not configured.
|
||||
* 128 is considered secure enough now. A mechanism
|
||||
* can change it in a constructor.
|
||||
*
|
||||
* Remember to sync with "securerandom.drbg.config" in java.security.
|
||||
*/
|
||||
protected static final int DEFAULT_STRENGTH = 128;
|
||||
|
||||
/**
|
||||
* Mechanism name, say, {@code HashDRBG}. Must be set in constructor.
|
||||
* This value will be used in {@code toString}.
|
||||
*/
|
||||
protected String mechName = "DRBG";
|
||||
|
||||
/**
|
||||
* highest_supported_security_strength of this mechanism for all algorithms
|
||||
* it supports. A mechanism should update the value in its constructor
|
||||
* if the value is not 256.
|
||||
*/
|
||||
protected int highestSupportedSecurityStrength = 256;
|
||||
|
||||
/**
|
||||
* Whether prediction resistance is supported. A mechanism should update
|
||||
* the value in its constructor if it is <em>not</em> supported.
|
||||
*/
|
||||
protected boolean supportPredictionResistance = true;
|
||||
|
||||
/**
|
||||
* Whether reseed is supported. A mechanism should update
|
||||
* the value in its constructor if it is <em>not</em> supported.
|
||||
*/
|
||||
protected boolean supportReseeding = true;
|
||||
|
||||
// Strength features. If not same as below, must be redefined in
|
||||
// chooseAlgorithmAndStrength. Among these, minLength and seedLen have no
|
||||
// default value and must be redefined. If personalization string or
|
||||
// additional input is not supported, set maxPersonalizationStringLength
|
||||
// or maxAdditionalInputLength to -1.
|
||||
|
||||
/**
|
||||
* Minimum entropy input length in bytes for this DRBG instance.
|
||||
* Must be assigned in {@link #chooseAlgorithmAndStrength}.
|
||||
*/
|
||||
protected int minLength;
|
||||
|
||||
/**
|
||||
* Maximum entropy input length in bytes for this DRBG instance.
|
||||
* Should be assigned in {@link #chooseAlgorithmAndStrength} if it is not
|
||||
* {@link Integer#MAX_VALUE}.
|
||||
* <p>
|
||||
* In theory this value (and the values below) can be bigger than
|
||||
* {@code Integer.MAX_VALUE} but a Java array can only have an int32 index.
|
||||
*/
|
||||
protected int maxLength = Integer.MAX_VALUE;
|
||||
|
||||
/**
|
||||
* Maximum personalization string length in bytes for this DRBG instance.
|
||||
* Should be assigned in {@link #chooseAlgorithmAndStrength} if it is not
|
||||
* {@link Integer#MAX_VALUE}.
|
||||
*/
|
||||
protected int maxPersonalizationStringLength = Integer.MAX_VALUE;
|
||||
|
||||
/**
|
||||
* Maximum additional input length in bytes for this DRBG instance.
|
||||
* Should be assigned in {@link #chooseAlgorithmAndStrength} if it is not
|
||||
* {@link Integer#MAX_VALUE}.
|
||||
*/
|
||||
protected int maxAdditionalInputLength = Integer.MAX_VALUE;
|
||||
|
||||
/**
|
||||
* max_number_of_bits_per_request in bytes for this DRBG instance.
|
||||
* Should be assigned in {@link #chooseAlgorithmAndStrength} if it is not
|
||||
* {@link Integer#MAX_VALUE}.
|
||||
*/
|
||||
protected int maxNumberOfBytesPerRequest = Integer.MAX_VALUE;
|
||||
|
||||
/**
|
||||
* Maximum number of requests between reseeds for this DRBG instance.
|
||||
* Should be assigned in {@link #chooseAlgorithmAndStrength} if it is not
|
||||
* {@link Integer#MAX_VALUE}.
|
||||
*/
|
||||
protected int reseedInterval = Integer.MAX_VALUE;
|
||||
|
||||
|
||||
/**
|
||||
* Algorithm used by this instance (SHA-512 or AES-256). Must be assigned
|
||||
* in {@link #chooseAlgorithmAndStrength}. This field is used in
|
||||
* {@link #toString()} and {@link DRBG#algorithmName}.
|
||||
*/
|
||||
protected String algorithm;
|
||||
|
||||
// Configurable parameters
|
||||
|
||||
/**
|
||||
* Security strength for this instance. Must be assigned in
|
||||
* {@link #chooseAlgorithmAndStrength}. Should be at least the requested
|
||||
* strength. Might be smaller than the highest strength
|
||||
* {@link #algorithm} supports. Must not be -1.
|
||||
*/
|
||||
protected int securityStrength; // in bits
|
||||
|
||||
/**
|
||||
* Strength requested in {@link DrbgParameters.Instantiation}.
|
||||
* The real strength is based on it. Do not modify it in a mechanism.
|
||||
*/
|
||||
protected int requestedInstantiationSecurityStrength = -1;
|
||||
|
||||
/**
|
||||
* The personalization string used by this instance. Set inside
|
||||
* {@link #configure(SecureRandomParameters)} and
|
||||
* can be used in a mechanism. Do not modify it in a mechanism.
|
||||
*/
|
||||
protected byte[] personalizationString;
|
||||
|
||||
/**
|
||||
* The prediction resistance flag used by this instance. Set inside
|
||||
* {@link #configure(SecureRandomParameters)}.
|
||||
*/
|
||||
private boolean predictionResistanceFlag;
|
||||
|
||||
// Non-standard configurable parameters
|
||||
|
||||
/**
|
||||
* Whether a derivation function is used. Requested in
|
||||
* {@link MoreDrbgParameters}. Only CtrDRBG uses it.
|
||||
* Do not modify it in a mechanism.
|
||||
*/
|
||||
protected boolean usedf;
|
||||
|
||||
/**
|
||||
* The nonce for this instance. Set in {@link #instantiateIfNecessary}.
|
||||
* After instantiation, this field is not null. Do not modify it
|
||||
* in a mechanism.
|
||||
*/
|
||||
protected transient byte[] nonce;
|
||||
|
||||
/**
|
||||
* Requested nonce in {@link MoreDrbgParameters}. If set to null,
|
||||
* nonce will be chosen by system, and a reinstantiated DRBG will get a
|
||||
* new system-provided nonce.
|
||||
*/
|
||||
private byte[] requestedNonce;
|
||||
|
||||
/**
|
||||
* Requested algorithm in {@link MoreDrbgParameters}.
|
||||
* Do not modify it in a mechanism.
|
||||
*/
|
||||
protected String requestedAlgorithm;
|
||||
|
||||
/**
|
||||
* The entropy source used by this instance. Set inside
|
||||
* {@link #configure(SecureRandomParameters)}. This field
|
||||
* can be null. {@link #getEntropyInput} will take care of null check.
|
||||
*/
|
||||
private transient EntropySource es;
|
||||
|
||||
// Five abstract methods for SP 800-90A DRBG
|
||||
|
||||
/**
|
||||
* Decides what algorithm and strength to use (SHA-256 or AES-256,
|
||||
* 128 or 256). Strength related fields must also be defined or redefined
|
||||
* here. Called in {@link #configure}. A mechanism uses
|
||||
* {@link #requestedAlgorithm},
|
||||
* {@link #requestedInstantiationSecurityStrength}, and
|
||||
* {@link #DEFAULT_STRENGTH} to decide which algorithm and strength to use.
|
||||
* <p>
|
||||
* If {@code requestedAlgorithm} is provided, it will always be used.
|
||||
* If {@code requestedInstantiationSecurityStrength} is also provided,
|
||||
* the algorithm will use the strength (an exception will be thrown if
|
||||
* the strength is not supported), otherwise, the smaller one of
|
||||
* the highest supported strength of the algorithm and the default strength
|
||||
* will be used.
|
||||
* <p>
|
||||
* If {@code requestedAlgorithm} is not provided, an algorithm will be
|
||||
* chosen that supports {@code requestedInstantiationSecurityStrength}
|
||||
* (or {@code DEFAULT_STRENGTH} if there is no request).
|
||||
* <p>
|
||||
* Since every call to {@link #configure} will call this method,
|
||||
* make sure to the calls do not contradict with each other.
|
||||
* <p>
|
||||
* Here are some examples of the algorithm and strength chosen (suppose
|
||||
* {@code DEFAULT_STRENGTH} is 128) for HashDRBG:
|
||||
* <pre>
|
||||
* requested effective
|
||||
* (SHA-1, -1) (SHA-1,128)
|
||||
* (SHA-1, 112) (SHA-1,112)
|
||||
* (SHA-1, 192) IAE
|
||||
* (SHA-256, -1) (SHA-256,128)
|
||||
* (SHA-256, 128) (SHA-256,128)
|
||||
* (SHA-3, -1) IAE
|
||||
* (null, -1) (SHA-256,128)
|
||||
* (null, 112) (SHA-256,112)
|
||||
* (null, 192) (SHA-256,192)
|
||||
* (null, 256) (SHA-256,256)
|
||||
* (null, 384) IAE
|
||||
* </pre>
|
||||
*
|
||||
* @throws IllegalArgumentException if the requested parameters
|
||||
* can not be supported or contradict with each other.
|
||||
*/
|
||||
protected abstract void chooseAlgorithmAndStrength();
|
||||
|
||||
/**
|
||||
* Initiates security engines ({@code MessageDigest}, {@code Mac},
|
||||
* or {@code Cipher}). Must be called in deserialization. Please note
|
||||
* that before instantiation the algorithm might not be available yet.
|
||||
* In this case, just return and this method will be called
|
||||
* automatically at instantiation.
|
||||
*/
|
||||
protected abstract void initEngine();
|
||||
|
||||
/**
|
||||
* Instantiates a DRBG. Called automatically before the first
|
||||
* {@code nextBytes} call.
|
||||
* <p>
|
||||
* Note that the other parameters (nonce, strength, ps) are already
|
||||
* stored inside at configuration.
|
||||
*
|
||||
* @param ei the entropy input, its length is already conditioned to be
|
||||
* between {@link #minLength} and {@link #maxLength}.
|
||||
*/
|
||||
protected abstract void instantiateAlgorithm(byte[] ei);
|
||||
|
||||
/**
|
||||
* The generate function.
|
||||
*
|
||||
* @param result fill result here, not null
|
||||
* @param additionalInput additional input, can be null. If not null,
|
||||
* its length is smaller than {@link #maxAdditionalInputLength}
|
||||
*/
|
||||
protected abstract void generateAlgorithm(
|
||||
byte[] result, byte[] additionalInput);
|
||||
|
||||
/**
|
||||
* The reseed function.
|
||||
*
|
||||
* @param ei the entropy input, its length is already conditioned to be
|
||||
* between {@link #minLength} and {@link #maxLength}.
|
||||
* @param additionalInput additional input, can be null. If not null,
|
||||
* its length is smaller than {@link #maxAdditionalInputLength}
|
||||
* @throws UnsupportedOperationException if reseed is not supported
|
||||
*/
|
||||
protected void reseedAlgorithm(
|
||||
byte[] ei, byte[] additionalInput) {
|
||||
throw new UnsupportedOperationException("No reseed function");
|
||||
}
|
||||
|
||||
// SecureRandomSpi methods taken care of here. All final.
|
||||
|
||||
@Override
|
||||
protected final void engineNextBytes(byte[] result) {
|
||||
engineNextBytes(result, DrbgParameters.nextBytes(
|
||||
-1, predictionResistanceFlag, null));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final void engineNextBytes(
|
||||
byte[] result, SecureRandomParameters params) {
|
||||
|
||||
Objects.requireNonNull(result);
|
||||
|
||||
if (debug != null) {
|
||||
debug.println(this, "nextBytes");
|
||||
}
|
||||
if (params instanceof DrbgParameters.NextBytes) {
|
||||
|
||||
// 800-90Ar1 9.3: Generate Process.
|
||||
|
||||
DrbgParameters.NextBytes dp = (DrbgParameters.NextBytes) params;
|
||||
|
||||
// Step 2: max_number_of_bits_per_request
|
||||
if (result.length > maxNumberOfBytesPerRequest) {
|
||||
// generateAlgorithm should be called multiple times to fill
|
||||
// up result. Unimplemented since maxNumberOfBytesPerRequest
|
||||
// is now Integer.MAX_VALUE.
|
||||
}
|
||||
|
||||
// Step 3: check requested_security_strength
|
||||
if (dp.getStrength() > securityStrength) {
|
||||
throw new IllegalArgumentException("strength too high: "
|
||||
+ dp.getStrength());
|
||||
}
|
||||
|
||||
// Step 4: check max_additional_input_length
|
||||
byte[] ai = dp.getAdditionalInput();
|
||||
if (ai != null && ai.length > maxAdditionalInputLength) {
|
||||
throw new IllegalArgumentException("ai too long: "
|
||||
+ ai.length);
|
||||
}
|
||||
|
||||
// Step 5: check prediction_resistance_flag
|
||||
boolean pr = dp.getPredictionResistance();
|
||||
if (!predictionResistanceFlag && pr) {
|
||||
throw new IllegalArgumentException("pr not available");
|
||||
}
|
||||
|
||||
instantiateIfNecessary(null);
|
||||
|
||||
// Step 7: Auto reseed
|
||||
if (reseedCounter > reseedInterval || pr) {
|
||||
reseedAlgorithm(getEntropyInput(pr), ai);
|
||||
ai = null;
|
||||
}
|
||||
|
||||
// Step 8, 10: Generate_algorithm
|
||||
// Step 9: Unnecessary. reseedCounter only updated after generation
|
||||
generateAlgorithm(result, ai);
|
||||
|
||||
// Step 11: Return
|
||||
} else {
|
||||
throw new IllegalArgumentException("unknown params type:"
|
||||
+ params.getClass());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void engineReseed(SecureRandomParameters params) {
|
||||
if (debug != null) {
|
||||
debug.println(this, "reseed with params");
|
||||
}
|
||||
if (!supportReseeding) {
|
||||
throw new UnsupportedOperationException("Reseed not supported");
|
||||
}
|
||||
if (params == null) {
|
||||
params = DrbgParameters.reseed(predictionResistanceFlag, null);
|
||||
}
|
||||
if (params instanceof DrbgParameters.Reseed) {
|
||||
DrbgParameters.Reseed dp = (DrbgParameters.Reseed) params;
|
||||
|
||||
// 800-90Ar1 9.2: Reseed Process.
|
||||
|
||||
// Step 2: Check prediction_resistance_request
|
||||
boolean pr = dp.getPredictionResistance();
|
||||
if (!predictionResistanceFlag && pr) {
|
||||
throw new IllegalArgumentException("pr not available");
|
||||
}
|
||||
|
||||
// Step 3: Check additional_input length
|
||||
byte[] ai = dp.getAdditionalInput();
|
||||
if (ai != null && ai.length > maxAdditionalInputLength) {
|
||||
throw new IllegalArgumentException("ai too long: "
|
||||
+ ai.length);
|
||||
}
|
||||
instantiateIfNecessary(null);
|
||||
|
||||
// Step 4: Get_entropy_input
|
||||
// Step 5: Check step 4
|
||||
// Step 6-7: Reseed_algorithm
|
||||
reseedAlgorithm(getEntropyInput(pr), ai);
|
||||
|
||||
// Step 8: Return
|
||||
} else {
|
||||
throw new IllegalArgumentException("unknown params type: "
|
||||
+ params.getClass());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the given number of seed bytes. A DRBG always uses
|
||||
* {@link SeedGenerator} to get an array with full-entropy.
|
||||
* <p>
|
||||
* The implementation is identical to SHA1PRNG's
|
||||
* {@link SecureRandom#engineGenerateSeed}.
|
||||
*
|
||||
* @param numBytes the number of seed bytes to generate.
|
||||
* @return the seed bytes.
|
||||
*/
|
||||
@Override
|
||||
public final byte[] engineGenerateSeed(int numBytes) {
|
||||
byte[] b = new byte[numBytes];
|
||||
SeedGenerator.generateSeed(b);
|
||||
return b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reseeds this random object with the given seed. A DRBG always expands
|
||||
* or truncates the input to be between {@link #minLength} and
|
||||
* {@link #maxLength} and uses it to instantiate or reseed itself
|
||||
* (depending on whether the DRBG is instantiated).
|
||||
*
|
||||
* @param input the seed
|
||||
*/
|
||||
@Override
|
||||
public final synchronized void engineSetSeed(byte[] input) {
|
||||
if (debug != null) {
|
||||
debug.println(this, "setSeed");
|
||||
}
|
||||
if (input.length < minLength) {
|
||||
input = Arrays.copyOf(input, minLength);
|
||||
} else if (input.length > maxLength) {
|
||||
input = Arrays.copyOf(input, maxLength);
|
||||
}
|
||||
if (!instantiated) {
|
||||
instantiateIfNecessary(input);
|
||||
} else {
|
||||
reseedAlgorithm(input, null);
|
||||
}
|
||||
}
|
||||
|
||||
// get_entropy_input
|
||||
|
||||
private byte[] getEntropyInput(boolean isPr) {
|
||||
// Should the 1st arg be minEntropy or minLength?
|
||||
//
|
||||
// Technically it should be minEntropy, but CtrDRBG
|
||||
// (not using derivation function) is so confusing
|
||||
// (does it need only strength or seedlen of entropy?)
|
||||
// that it's safer to assume minLength. In all other
|
||||
// cases minLength equals to minEntropy.
|
||||
return getEntropyInput(minLength, minLength, maxLength, isPr);
|
||||
}
|
||||
|
||||
private byte[] getEntropyInput(int minEntropy, int minLength,
|
||||
int maxLength, boolean pr) {
|
||||
if (debug != null) {
|
||||
debug.println(this, "getEntropy(" + minEntropy + "," + minLength +
|
||||
"," + maxLength + "," + pr + ")");
|
||||
}
|
||||
EntropySource esNow = es;
|
||||
if (esNow == null) {
|
||||
esNow = pr ? SeederHolder.prseeder : SeederHolder.seeder;
|
||||
}
|
||||
return esNow.getEntropy(minEntropy, minLength, maxLength, pr);
|
||||
}
|
||||
|
||||
// Defaults
|
||||
|
||||
/**
|
||||
* The default {@code EntropySource} determined by system property
|
||||
* "java.security.egd" or security property "securerandom.source".
|
||||
* <p>
|
||||
* This object uses {@link SeedGenerator#generateSeed(byte[])} to
|
||||
* return a byte array containing {@code minLength} bytes. It is
|
||||
* assumed to support prediction resistance and always contains
|
||||
* full-entropy. A trusted application can update this field.
|
||||
*/
|
||||
private final static EntropySource defaultES =
|
||||
(minE, minLen, maxLen, pr) -> {
|
||||
byte[] result = new byte[minLen];
|
||||
SeedGenerator.generateSeed(result);
|
||||
return result;
|
||||
};
|
||||
|
||||
private static class SeederHolder {
|
||||
|
||||
/**
|
||||
* Default EntropySource for SecureRandom with prediction resistance,
|
||||
*/
|
||||
static final EntropySource prseeder;
|
||||
|
||||
/**
|
||||
* Default EntropySource for SecureRandom without prediction resistance,
|
||||
* which is backed by a DRBG whose EntropySource is {@link #prseeder}.
|
||||
*/
|
||||
static final EntropySource seeder;
|
||||
|
||||
static {
|
||||
prseeder = defaultES;
|
||||
// According to SP800-90C section 7, a DRBG without live
|
||||
// entropy (drbg here, with pr being false) can instantiate
|
||||
// another DRBG with weaker strength. So we choose highest
|
||||
// strength we support.
|
||||
HashDrbg first = new HashDrbg(new MoreDrbgParameters(
|
||||
prseeder, null, "SHA-256", null, false,
|
||||
DrbgParameters.instantiation(
|
||||
256, NONE,
|
||||
SeedGenerator.getSystemEntropy())));
|
||||
seeder = (entropy, minLen, maxLen, pr) -> {
|
||||
if (pr) {
|
||||
// This SEI does not support pr
|
||||
throw new IllegalArgumentException("pr not supported");
|
||||
}
|
||||
byte[] result = new byte[minLen];
|
||||
first.engineNextBytes(result);
|
||||
return result;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Constructor called by overridden methods, initializer...
|
||||
|
||||
/**
|
||||
* A constructor without argument so that an implementation does not
|
||||
* need to always write {@code super(params)}.
|
||||
*/
|
||||
protected AbstractDrbg() {
|
||||
// Nothing
|
||||
}
|
||||
|
||||
/**
|
||||
* A mechanism shall override this constructor to setup {@link #mechName},
|
||||
* {@link #highestSupportedSecurityStrength},
|
||||
* {@link #supportPredictionResistance}, {@link #supportReseeding}
|
||||
* or other features like {@link #DEFAULT_STRENGTH}. Finally it shall
|
||||
* call {@link #configure} on {@code params}.
|
||||
*
|
||||
* @param params the {@link SecureRandomParameters} object.
|
||||
* This argument can be {@code null}.
|
||||
* @throws IllegalArgumentException if {@code params} is
|
||||
* inappropriate for this SecureRandom.
|
||||
*/
|
||||
protected AbstractDrbg(SecureRandomParameters params) {
|
||||
// Nothing
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current configuration as a {@link DrbgParameters.Instantiation}
|
||||
* object.
|
||||
*
|
||||
* @return the curent configuration
|
||||
*/
|
||||
@Override
|
||||
protected SecureRandomParameters engineGetParameters() {
|
||||
// Or read from variable.
|
||||
return DrbgParameters.instantiation(
|
||||
securityStrength,
|
||||
predictionResistanceFlag ? PR_AND_RESEED :
|
||||
(supportReseeding ? RESEED_ONLY : NONE),
|
||||
personalizationString);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure this DRBG. This method calls
|
||||
* {@link #chooseAlgorithmAndStrength()} and {@link #initEngine()}
|
||||
* but does not do the actual instantiation.
|
||||
*
|
||||
* @param params configuration, if null, default configuration (default
|
||||
* strength, pr_false, no personalization string) is used.
|
||||
* @throws IllegalArgumentException if {@code params} is
|
||||
* inappropriate for this SecureRandom.
|
||||
*/
|
||||
protected final synchronized void configure(
|
||||
SecureRandomParameters params) {
|
||||
if (debug != null) {
|
||||
debug.println(this, "configure " + this + " with " + params);
|
||||
}
|
||||
if (params == null) {
|
||||
params = DrbgParameters.instantiation(-1, RESEED_ONLY, null);
|
||||
}
|
||||
if (params instanceof MoreDrbgParameters) {
|
||||
MoreDrbgParameters m = (MoreDrbgParameters)params;
|
||||
this.requestedNonce = m.nonce;
|
||||
this.es = m.es;
|
||||
this.requestedAlgorithm = m.algorithm;
|
||||
this.usedf = m.usedf;
|
||||
params = m.config;
|
||||
}
|
||||
if (params != null) {
|
||||
if (params instanceof DrbgParameters.Instantiation) {
|
||||
DrbgParameters.Instantiation inst =
|
||||
(DrbgParameters.Instantiation) params;
|
||||
|
||||
// 800-90Ar1 9.1: Instantiate Process. Steps 1-5.
|
||||
|
||||
// Step 1: Check requested_instantiation_security_strength
|
||||
if (inst.getStrength() > highestSupportedSecurityStrength) {
|
||||
throw new IllegalArgumentException("strength too big: "
|
||||
+ inst.getStrength());
|
||||
}
|
||||
|
||||
// Step 2: Check prediction_resistance_flag
|
||||
if (inst.getCapability().supportsPredictionResistance()
|
||||
&& !supportPredictionResistance) {
|
||||
throw new IllegalArgumentException("pr not supported");
|
||||
}
|
||||
|
||||
// Step 3: Check personalization_string
|
||||
byte[] ps = inst.getPersonalizationString();
|
||||
if (ps != null && ps.length > maxPersonalizationStringLength) {
|
||||
throw new IllegalArgumentException("ps too long: "
|
||||
+ ps.length);
|
||||
}
|
||||
|
||||
if (inst.getCapability().supportsReseeding()
|
||||
&& !supportReseeding) {
|
||||
throw new IllegalArgumentException("reseed not supported");
|
||||
}
|
||||
this.personalizationString = ps;
|
||||
this.predictionResistanceFlag =
|
||||
inst.getCapability().supportsPredictionResistance();
|
||||
this.requestedInstantiationSecurityStrength = inst.getStrength();
|
||||
} else {
|
||||
throw new IllegalArgumentException("unknown params: "
|
||||
+ params.getClass());
|
||||
}
|
||||
}
|
||||
|
||||
// Step 4: Set security_strength
|
||||
chooseAlgorithmAndStrength();
|
||||
instantiated = false;
|
||||
|
||||
// Step 5: no-op.
|
||||
|
||||
if (debug != null) {
|
||||
debug.println(this, "configured " + this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiate if necessary,
|
||||
*
|
||||
* @param entropy a user-provided entropy, the length is already good.
|
||||
* If null, will fetch entropy input automatically.
|
||||
*/
|
||||
private synchronized void instantiateIfNecessary(byte[] entropy) {
|
||||
if (!instantiated) {
|
||||
|
||||
// 800-90Ar1 9.1: Instantiate Process. Steps 6-12.
|
||||
|
||||
// Step 6: Get_entropy_input
|
||||
// Step 7: check error (getEntropyInput throw no exception now)
|
||||
if (entropy == null) {
|
||||
entropy = getEntropyInput(predictionResistanceFlag);
|
||||
}
|
||||
|
||||
// Step 8. nonce
|
||||
if (requestedNonce != null) {
|
||||
nonce = requestedNonce;
|
||||
} else {
|
||||
nonce = NonceProvider.next();
|
||||
}
|
||||
initEngine();
|
||||
|
||||
// Step 9-11: Instantiate_algorithm
|
||||
instantiateAlgorithm(entropy);
|
||||
instantiated = true;
|
||||
|
||||
// Step 12: Return
|
||||
}
|
||||
}
|
||||
|
||||
// Nonce provider
|
||||
|
||||
private static class NonceProvider {
|
||||
|
||||
// 128 bits of nonce can be used by 256-bit strength DRBG
|
||||
private static final byte[] block = new byte[16];
|
||||
|
||||
private static synchronized byte[] next() {
|
||||
int k = 15;
|
||||
while ((k >= 0) && (++block[k] == 0)) {
|
||||
k--;
|
||||
}
|
||||
return block.clone();
|
||||
}
|
||||
}
|
||||
|
||||
// Misc
|
||||
|
||||
/** A handy method returning hexdump string with no colon or new line.
|
||||
*
|
||||
* @param in input byte array
|
||||
* @return the hexdump string
|
||||
*/
|
||||
protected static String hex(byte[] in) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (byte b : in) {
|
||||
sb.append(String.format("%02x", b&0xff));
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the smallest standard strength (112, 128, 192, 256) that is
|
||||
* greater or equal to the input.
|
||||
*
|
||||
* @param input the input strength
|
||||
* @return the standard strength
|
||||
*/
|
||||
protected static int getStandardStrength(int input) {
|
||||
if (input <= 112) return 112;
|
||||
if (input <= 128) return 128;
|
||||
if (input <= 192) return 192;
|
||||
if (input <= 256) return 256;
|
||||
throw new IllegalArgumentException("input too big: " + input);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return mechName + "," + algorithm
|
||||
+ "," + securityStrength + ","
|
||||
+ (predictionResistanceFlag ? "pr_and_reseed"
|
||||
: (supportReseeding ? "reseed_only" : "none"));
|
||||
}
|
||||
}
|
@ -0,0 +1,160 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.provider;
|
||||
|
||||
import sun.security.util.HexDumpEncoder;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Locale;
|
||||
|
||||
public abstract class AbstractHashDrbg extends AbstractDrbg {
|
||||
|
||||
private static final long serialVersionUID = 9L;
|
||||
|
||||
protected int outLen;
|
||||
protected int seedLen;
|
||||
|
||||
private static int alg2strength(String algorithm) {
|
||||
switch (algorithm.toUpperCase(Locale.ROOT)) {
|
||||
case "SHA-1":
|
||||
return 128;
|
||||
case "SHA-224":
|
||||
case "SHA-512/224":
|
||||
return 192;
|
||||
case "SHA-256":
|
||||
case "SHA-512/256":
|
||||
case "SHA-384":
|
||||
case "SHA-512":
|
||||
return 256;
|
||||
default:
|
||||
throw new IllegalArgumentException(algorithm +
|
||||
" not supported in Hash_DBRG");
|
||||
}
|
||||
}
|
||||
|
||||
protected void chooseAlgorithmAndStrength() {
|
||||
if (requestedAlgorithm != null) {
|
||||
algorithm = requestedAlgorithm.toUpperCase(Locale.ROOT);
|
||||
int supportedStrength = alg2strength(algorithm);
|
||||
if (requestedInstantiationSecurityStrength >= 0) {
|
||||
int tryStrength = getStandardStrength(
|
||||
requestedInstantiationSecurityStrength);
|
||||
if (tryStrength > supportedStrength) {
|
||||
throw new IllegalArgumentException(algorithm +
|
||||
" does not support strength " +
|
||||
requestedInstantiationSecurityStrength);
|
||||
}
|
||||
this.securityStrength = tryStrength;
|
||||
} else {
|
||||
this.securityStrength = DEFAULT_STRENGTH > supportedStrength ?
|
||||
supportedStrength : DEFAULT_STRENGTH;
|
||||
}
|
||||
} else {
|
||||
int tryStrength = (requestedInstantiationSecurityStrength < 0) ?
|
||||
DEFAULT_STRENGTH : requestedInstantiationSecurityStrength;
|
||||
tryStrength = getStandardStrength(tryStrength);
|
||||
// The default algorithm which is enough for all strengths.
|
||||
// Remember to sync with "securerandom.drbg.config" in java.security
|
||||
algorithm = "SHA-256";
|
||||
this.securityStrength = tryStrength;
|
||||
}
|
||||
switch (algorithm.toUpperCase(Locale.ROOT)) {
|
||||
case "SHA-1":
|
||||
this.seedLen = 440 / 8;
|
||||
this.outLen = 160 / 8;
|
||||
break;
|
||||
case "SHA-224":
|
||||
case "SHA-512/224":
|
||||
this.seedLen = 440 / 8;
|
||||
this.outLen = 224 / 8;
|
||||
break;
|
||||
case "SHA-256":
|
||||
case "SHA-512/256":
|
||||
this.seedLen = 440 / 8;
|
||||
this.outLen = 256 / 8;
|
||||
break;
|
||||
case "SHA-384":
|
||||
this.seedLen = 888 / 8;
|
||||
this.outLen = 384 / 8;
|
||||
break;
|
||||
case "SHA-512":
|
||||
this.seedLen = 888 / 8;
|
||||
this.outLen = 512 / 8;
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException(algorithm +
|
||||
" not supported in Hash_DBRG");
|
||||
}
|
||||
this.minLength = this.securityStrength / 8;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void instantiateAlgorithm(byte[] entropy) {
|
||||
if (debug != null) {
|
||||
debug.println(this, "instantiate");
|
||||
}
|
||||
|
||||
// 800-90Ar1 10.1.1.2: Hash_DRBG Instantiate Process.
|
||||
// 800-90Ar1 10.1.2.3: Hmac_DRBG Instantiate Process.
|
||||
|
||||
// Step 1: entropy_input || nonce || personalization_string.
|
||||
byte[] seed = Arrays.copyOf(entropy, entropy.length + nonce.length +
|
||||
((personalizationString == null) ? 0
|
||||
: personalizationString.length));
|
||||
System.arraycopy(nonce, 0, seed, entropy.length, nonce.length);
|
||||
if (personalizationString != null) {
|
||||
System.arraycopy(personalizationString, 0,
|
||||
seed, entropy.length + nonce.length,
|
||||
personalizationString.length);
|
||||
}
|
||||
hashReseedInternal(seed);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void reseedAlgorithm(
|
||||
byte[] ei,
|
||||
byte[] additionalInput) {
|
||||
if (debug != null) {
|
||||
debug.println(this, "reseedAlgorithm\n" +
|
||||
new HexDumpEncoder().encodeBuffer(ei) + "\n" +
|
||||
((additionalInput == null) ? "" :
|
||||
new HexDumpEncoder().encodeBuffer(additionalInput)));
|
||||
}
|
||||
|
||||
// 800-90Ar1 10.1.1.3: Hash_DRBG Reseed Process.
|
||||
// 800-90Ar1 10.1.2.4: Hmac_DRBG Reseed Process.
|
||||
|
||||
// Step 1: entropy_input || additional_input.
|
||||
if (additionalInput != null) {
|
||||
ei = Arrays.copyOf(ei, ei.length + additionalInput.length);
|
||||
System.arraycopy(additionalInput, 0, ei,
|
||||
ei.length - additionalInput.length, additionalInput.length);
|
||||
}
|
||||
hashReseedInternal(ei);
|
||||
}
|
||||
|
||||
protected abstract void hashReseedInternal(byte[] seed);
|
||||
}
|
@ -0,0 +1,530 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.provider;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.NoSuchPaddingException;
|
||||
import javax.crypto.SecretKey;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.io.IOException;
|
||||
import java.security.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.Locale;
|
||||
|
||||
public class CtrDrbg extends AbstractDrbg {
|
||||
|
||||
private static final long serialVersionUID = 9L;
|
||||
private static final int AES_LIMIT;
|
||||
|
||||
static {
|
||||
try {
|
||||
AES_LIMIT = Cipher.getMaxAllowedKeyLength("AES");
|
||||
} catch (Exception e) {
|
||||
// should not happen
|
||||
throw new AssertionError("Cannot detect AES", e);
|
||||
}
|
||||
}
|
||||
|
||||
private transient Cipher cipher;
|
||||
|
||||
private String cipherAlg;
|
||||
private String keyAlg;
|
||||
|
||||
private int ctrLen;
|
||||
private int blockLen;
|
||||
private int keyLen;
|
||||
private int seedLen;
|
||||
|
||||
private transient byte[] v;
|
||||
private transient byte[] k;
|
||||
|
||||
public CtrDrbg(SecureRandomParameters params) {
|
||||
mechName = "CTR_DRBG";
|
||||
configure(params);
|
||||
}
|
||||
|
||||
private static int alg2strength(String algorithm) {
|
||||
switch (algorithm.toUpperCase(Locale.ROOT)) {
|
||||
case "TDEA":
|
||||
case "3KEYTDEA":
|
||||
case "3 KEY TDEA":
|
||||
case "DESEDE":
|
||||
return 112;
|
||||
case "AES-128":
|
||||
return 128;
|
||||
case "AES-192":
|
||||
return 192;
|
||||
case "AES-256":
|
||||
return 256;
|
||||
default:
|
||||
throw new IllegalArgumentException(algorithm +
|
||||
" not supported in CTR_DBRG");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void chooseAlgorithmAndStrength() {
|
||||
if (requestedAlgorithm != null) {
|
||||
algorithm = requestedAlgorithm.toUpperCase();
|
||||
int supportedStrength = alg2strength(algorithm);
|
||||
if (requestedInstantiationSecurityStrength >= 0) {
|
||||
int tryStrength = getStandardStrength(
|
||||
requestedInstantiationSecurityStrength);
|
||||
if (tryStrength > supportedStrength) {
|
||||
throw new IllegalArgumentException(algorithm +
|
||||
" does not support strength " +
|
||||
requestedInstantiationSecurityStrength);
|
||||
}
|
||||
this.securityStrength = tryStrength;
|
||||
} else {
|
||||
this.securityStrength = (DEFAULT_STRENGTH > supportedStrength) ?
|
||||
supportedStrength : DEFAULT_STRENGTH;
|
||||
}
|
||||
} else {
|
||||
int tryStrength = (requestedInstantiationSecurityStrength < 0) ?
|
||||
DEFAULT_STRENGTH : requestedInstantiationSecurityStrength;
|
||||
tryStrength = getStandardStrength(tryStrength);
|
||||
// Default algorithm, use AES-128 if AES-256 is not available.
|
||||
// Remember to sync with "securerandom.drbg.config" in java.security
|
||||
if (tryStrength <= 128 && AES_LIMIT < 256) {
|
||||
algorithm = "AES-128";
|
||||
} else if (AES_LIMIT >= 256) {
|
||||
algorithm = "AES-256";
|
||||
} else {
|
||||
throw new IllegalArgumentException("unsupported strength " +
|
||||
requestedInstantiationSecurityStrength);
|
||||
}
|
||||
this.securityStrength = tryStrength;
|
||||
}
|
||||
switch (algorithm.toUpperCase(Locale.ROOT)) {
|
||||
case "TDEA":
|
||||
case "3KEYTDEA":
|
||||
case "3 KEY TDEA":
|
||||
case "DESEDE":
|
||||
algorithm = "DESede";
|
||||
this.keyAlg = "DESede";
|
||||
this.cipherAlg = "DESede/ECB/NoPadding";
|
||||
this.blockLen = 64 / 8;
|
||||
this.keyLen = 168 / 8;
|
||||
break;
|
||||
case "AES-128":
|
||||
case "AES-192":
|
||||
case "AES-256":
|
||||
this.keyAlg = "AES";
|
||||
this.cipherAlg = "AES/ECB/NoPadding";
|
||||
switch (algorithm) {
|
||||
case "AES-128":
|
||||
this.keyLen = 128 / 8;
|
||||
break;
|
||||
case "AES-192":
|
||||
this.keyLen = 192 / 8;
|
||||
if (AES_LIMIT < 192) {
|
||||
throw new IllegalArgumentException(algorithm +
|
||||
" not available (because policy) in CTR_DBRG");
|
||||
}
|
||||
break;
|
||||
case "AES-256":
|
||||
this.keyLen = 256 / 8;
|
||||
if (AES_LIMIT < 256) {
|
||||
throw new IllegalArgumentException(algorithm +
|
||||
" not available (because policy) in CTR_DBRG");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException(algorithm +
|
||||
" not supported in CTR_DBRG");
|
||||
}
|
||||
this.blockLen = 128 / 8;
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException(algorithm +
|
||||
" not supported in CTR_DBRG");
|
||||
}
|
||||
this.seedLen = this.blockLen + this.keyLen;
|
||||
this.ctrLen = this.blockLen; // TODO
|
||||
if (usedf) {
|
||||
this.minLength = this.securityStrength / 8;
|
||||
} else {
|
||||
this.minLength = this.maxLength =
|
||||
this.maxPersonalizationStringLength =
|
||||
this.maxAdditionalInputLength = seedLen;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This call, used by the constructors, instantiates the digest.
|
||||
*/
|
||||
@Override
|
||||
protected void initEngine() {
|
||||
try {
|
||||
/*
|
||||
* Use the local SUN implementation to avoid native
|
||||
* performance overhead.
|
||||
*/
|
||||
cipher = Cipher.getInstance(cipherAlg, "SunJCE");
|
||||
} catch (NoSuchProviderException | NoSuchAlgorithmException
|
||||
| NoSuchPaddingException e) {
|
||||
// Fallback to any available.
|
||||
try {
|
||||
cipher = Cipher.getInstance(cipherAlg);
|
||||
} catch (NoSuchAlgorithmException | NoSuchPaddingException exc) {
|
||||
throw new InternalError(
|
||||
"internal error: " + cipherAlg + " not available.", exc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void status() {
|
||||
if (debug != null) {
|
||||
debug.println(this, "Key = " + hex(k));
|
||||
debug.println(this, "V = " + hex(v));
|
||||
debug.println(this, "reseed counter = " + reseedCounter);
|
||||
}
|
||||
}
|
||||
|
||||
// 800-90Ar1 10.2.1.2. CTR_DRBG_Update
|
||||
private void update(byte[] input) {
|
||||
if (input.length != seedLen) {
|
||||
// Should not happen
|
||||
throw new IllegalArgumentException("input length not seedLen: "
|
||||
+ input.length);
|
||||
}
|
||||
try {
|
||||
|
||||
int m = (seedLen + blockLen - 1) / blockLen;
|
||||
byte[] temp = new byte[m * blockLen];
|
||||
|
||||
// Step 1. temp = Null.
|
||||
|
||||
// Step 2. Loop
|
||||
for (int i = 0; i < m; i++) {
|
||||
// Step 2.1. Increment
|
||||
addOne(v, ctrLen);
|
||||
// Step 2.2. Block_Encrypt
|
||||
cipher.init(Cipher.ENCRYPT_MODE, getKey(keyAlg, k));
|
||||
// Step 2.3. Encrypt into right position, no need to cat
|
||||
cipher.doFinal(v, 0, blockLen, temp, i * blockLen);
|
||||
}
|
||||
|
||||
// Step 3. Truncate
|
||||
temp = Arrays.copyOf(temp, seedLen);
|
||||
|
||||
// Step 4: Add
|
||||
for (int i = 0; i < seedLen; i++) {
|
||||
temp[i] ^= input[i];
|
||||
}
|
||||
|
||||
// Step 5: leftmost
|
||||
k = Arrays.copyOf(temp, keyLen);
|
||||
|
||||
// Step 6: rightmost
|
||||
v = Arrays.copyOfRange(temp, seedLen - blockLen, seedLen);
|
||||
|
||||
// Step 7. Return
|
||||
} catch (GeneralSecurityException e) {
|
||||
throw new InternalError(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void instantiateAlgorithm(byte[] ei) {
|
||||
if (debug != null) {
|
||||
debug.println(this, "instantiate");
|
||||
}
|
||||
byte[] more;
|
||||
if (usedf) {
|
||||
// 800-90Ar1 10.2.1.3.2 Step 1-2. cat bytes
|
||||
if (personalizationString == null) {
|
||||
more = nonce;
|
||||
} else {
|
||||
more = Arrays.copyOf(
|
||||
nonce, nonce.length + personalizationString.length);
|
||||
System.arraycopy(personalizationString, 0, more, nonce.length,
|
||||
personalizationString.length);
|
||||
}
|
||||
} else {
|
||||
// 800-90Ar1 10.2.1.3.1
|
||||
// Step 1-2, no need to expand personalizationString, we only XOR
|
||||
// with shorter length
|
||||
more = personalizationString;
|
||||
}
|
||||
reseedAlgorithm(ei, more);
|
||||
}
|
||||
|
||||
private byte[] df(byte[] input) {
|
||||
int l = input.length;
|
||||
int n = seedLen;
|
||||
int slen = 4 + 4 + l + 1;
|
||||
byte[] s = new byte[(slen + blockLen - 1) / blockLen * blockLen];
|
||||
s[0] = (byte)(l >> 24);
|
||||
s[1] = (byte)(l >> 16);
|
||||
s[2] = (byte)(l >> 8);
|
||||
s[3] = (byte)(l);
|
||||
s[4] = (byte)(n >> 24);
|
||||
s[5] = (byte)(n >> 16);
|
||||
s[6] = (byte)(n >> 8);
|
||||
s[7] = (byte)(n);
|
||||
System.arraycopy(input, 0, s, 8, l);
|
||||
s[8+l] = (byte)0x80;
|
||||
|
||||
byte[] k = new byte[keyLen];
|
||||
for (int i = 0; i < k.length; i++) {
|
||||
k[i] = (byte)i;
|
||||
}
|
||||
|
||||
byte[] temp = new byte[seedLen];
|
||||
|
||||
for (int i = 0; i * blockLen < temp.length; i++) {
|
||||
byte[] iv = new byte[blockLen + s.length];
|
||||
iv[0] = (byte)(i >> 24);
|
||||
iv[1] = (byte)(i >> 16);
|
||||
iv[2] = (byte)(i >> 8);
|
||||
iv[3] = (byte)(i);
|
||||
System.arraycopy(s, 0, iv, blockLen, s.length);
|
||||
int tailLen = temp.length - blockLen*i;
|
||||
if (tailLen > blockLen) {
|
||||
tailLen = blockLen;
|
||||
}
|
||||
System.arraycopy(bcc(k, iv), 0, temp, blockLen*i, tailLen);
|
||||
}
|
||||
|
||||
k = Arrays.copyOf(temp, keyLen);
|
||||
byte[] x = Arrays.copyOfRange(temp, keyLen, temp.length);
|
||||
|
||||
for (int i = 0; i * blockLen < seedLen; i++) {
|
||||
try {
|
||||
cipher.init(Cipher.ENCRYPT_MODE, getKey(keyAlg, k));
|
||||
int tailLen = temp.length - blockLen*i;
|
||||
if (tailLen > blockLen) {
|
||||
tailLen = blockLen;
|
||||
}
|
||||
x = cipher.doFinal(x);
|
||||
System.arraycopy(x, 0, temp, blockLen * i, tailLen);
|
||||
} catch (GeneralSecurityException e) {
|
||||
throw new InternalError(e);
|
||||
}
|
||||
}
|
||||
return temp;
|
||||
}
|
||||
|
||||
private byte[] bcc(byte[] k, byte[] data) {
|
||||
byte[] chain = new byte[blockLen];
|
||||
int n = data.length / blockLen;
|
||||
for (int i = 0; i < n; i++) {
|
||||
byte[] inputBlock = Arrays.copyOfRange(
|
||||
data, i * blockLen, i * blockLen + blockLen);
|
||||
for (int j = 0; j < blockLen; j++) {
|
||||
inputBlock[j] ^= chain[j];
|
||||
}
|
||||
try {
|
||||
cipher.init(Cipher.ENCRYPT_MODE, getKey(keyAlg, k));
|
||||
chain = cipher.doFinal(inputBlock);
|
||||
} catch (GeneralSecurityException e) {
|
||||
throw new InternalError(e);
|
||||
}
|
||||
}
|
||||
return chain;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void reseedAlgorithm(
|
||||
byte[] ei,
|
||||
byte[] additionalInput) {
|
||||
if (usedf) {
|
||||
// 800-90Ar1 10.2.1.3.2 Instantiate.
|
||||
// 800-90Ar1 10.2.1.4.2 Reseed.
|
||||
|
||||
// Step 1: cat bytes
|
||||
if (additionalInput != null) {
|
||||
byte[] temp = Arrays.copyOf(
|
||||
ei, ei.length + additionalInput.length);
|
||||
System.arraycopy(additionalInput, 0, temp, ei.length,
|
||||
additionalInput.length);
|
||||
ei = temp;
|
||||
}
|
||||
// Step 2. df (seed_material, seedlen).
|
||||
ei = df(ei);
|
||||
} else {
|
||||
// 800-90Ar1 10.2.1.3.1 Instantiate
|
||||
// 800-90Ar1 10.2.1.4.1 Reseed
|
||||
// Step 1-2. Needless
|
||||
// Step 3. seed_material = entropy_input XOR more
|
||||
if (additionalInput != null) {
|
||||
// additionalInput.length <= seedLen
|
||||
for (int i = 0; i < additionalInput.length; i++) {
|
||||
ei[i] ^= additionalInput[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (v == null) {
|
||||
// 800-90Ar1 10.2.1.3.2 Instantiate. Step 3-4
|
||||
// 800-90Ar1 10.2.1.3.1 Instantiate. Step 4-5
|
||||
k = new byte[keyLen];
|
||||
v = new byte[blockLen];
|
||||
}
|
||||
//status();
|
||||
|
||||
// 800-90Ar1 10.2.1.3.1 Instantiate. Step 6
|
||||
// 800-90Ar1 10.2.1.3.2 Instantiate. Step 5
|
||||
// 800-90Ar1 10.2.1.4.1 Reseed. Step 4
|
||||
// 800-90Ar1 10.2.1.4.2 Reseed. Step 3
|
||||
update(ei);
|
||||
// 800-90Ar1 10.2.1.3.1 Instantiate. Step 7
|
||||
// 800-90Ar1 10.2.1.3.2 Instantiate. Step 6
|
||||
// 800-90Ar1 10.2.1.4.1 Reseed. Step 5
|
||||
// 800-90Ar1 10.2.1.4.2 Reseed. Step 4
|
||||
reseedCounter = 1;
|
||||
//status();
|
||||
|
||||
// Whatever step. Return
|
||||
}
|
||||
|
||||
/**
|
||||
* Add one to data, only touch the last len bytes.
|
||||
*/
|
||||
private static void addOne(byte[] data, int len) {
|
||||
for (int i = 0; i < len; i++) {
|
||||
data[data.length - 1 - i]++;
|
||||
if (data[data.length - 1 - i] != 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void generateAlgorithm(
|
||||
byte[] result, byte[] additionalInput) {
|
||||
|
||||
if (debug != null) {
|
||||
debug.println(this, "generateAlgorithm");
|
||||
}
|
||||
|
||||
// 800-90Ar1 10.2.1.5.1 Generate
|
||||
// 800-90Ar1 10.2.1.5.2 Generate
|
||||
|
||||
// Step 1: Check reseed_counter. Will not fail. Already checked in
|
||||
// AbstractDrbg#engineNextBytes.
|
||||
|
||||
if (additionalInput != null) {
|
||||
if (usedf) {
|
||||
// 10.2.1.5.2 Step 2.1
|
||||
additionalInput = df(additionalInput);
|
||||
} else {
|
||||
// 10.2.1.5.1 Step 2.1-2.2
|
||||
additionalInput = Arrays.copyOf(additionalInput, seedLen);
|
||||
}
|
||||
// 10.2.1.5.1 Step 2.3
|
||||
// 10.2.1.5.2 Step 2.2
|
||||
update(additionalInput);
|
||||
} else {
|
||||
// 10.2.1.5.1 Step 2 Else
|
||||
// 10.2.1.5.2 Step 2 Else
|
||||
additionalInput = new byte[seedLen];
|
||||
}
|
||||
|
||||
// Step 3. temp = Null
|
||||
int pos = 0;
|
||||
|
||||
// Step 4. Loop
|
||||
while (pos < result.length) {
|
||||
int tailLen = result.length - pos;
|
||||
// Step 4.1. Increment
|
||||
addOne(v, ctrLen);
|
||||
try {
|
||||
// Step 4.2. Encrypt
|
||||
cipher.init(Cipher.ENCRYPT_MODE, getKey(keyAlg, k));
|
||||
byte[] out = cipher.doFinal(v);
|
||||
|
||||
// Step 4.3 and 5. Cat bytes and leftmost
|
||||
System.arraycopy(out, 0, result, pos,
|
||||
(tailLen > blockLen) ? blockLen : tailLen);
|
||||
} catch (GeneralSecurityException e) {
|
||||
throw new InternalError(e);
|
||||
}
|
||||
pos += blockLen;
|
||||
}
|
||||
|
||||
// Step 6. Update
|
||||
update(additionalInput);
|
||||
|
||||
// Step 7. reseed_counter++
|
||||
reseedCounter++;
|
||||
|
||||
//status();
|
||||
|
||||
// Step 8. Return
|
||||
}
|
||||
|
||||
private static void des7to8(
|
||||
byte[] key56, int off56, byte[] key64, int off64) {
|
||||
key64[off64 + 0] = (byte)
|
||||
(key56[off56 + 0] & 0xFE); // << 0
|
||||
key64[off64 + 1] = (byte)
|
||||
((key56[off56 + 0] << 7) | ((key56[off56 + 1] & 0xFF) >>> 1));
|
||||
key64[off64 + 2] = (byte)
|
||||
((key56[off56 + 1] << 6) | ((key56[off56 + 2] & 0xFF) >>> 2));
|
||||
key64[off64 + 3] = (byte)
|
||||
((key56[off56 + 2] << 5) | ((key56[off56 + 3] & 0xFF) >>> 3));
|
||||
key64[off64 + 4] = (byte)
|
||||
((key56[off56 + 3] << 4) | ((key56[off56 + 4] & 0xFF) >>> 4));
|
||||
key64[off64 + 5] = (byte)
|
||||
((key56[off56 + 4] << 3) | ((key56[off56 + 5] & 0xFF) >>> 5));
|
||||
key64[off64 + 6] = (byte)
|
||||
((key56[off56 + 5] << 2) | ((key56[off56 + 6] & 0xFF) >>> 6));
|
||||
key64[off64 + 7] = (byte)
|
||||
(key56[off56 + 6] << 1);
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
// if even # bits, make uneven, XOR with 1 (uneven & 1)
|
||||
// for uneven # bits, make even, XOR with 0 (even & 1)
|
||||
key64[off64 + i] ^= Integer.bitCount(key64[off64 + i] ^ 1) & 1;
|
||||
}
|
||||
}
|
||||
|
||||
private static SecretKey getKey(String keyAlg, byte[] k) {
|
||||
if (keyAlg.equals("DESede")) {
|
||||
byte[] k2 = new byte[24];
|
||||
des7to8(k, 0, k2, 0);
|
||||
des7to8(k, 7, k2, 8);
|
||||
des7to8(k, 14, k2, 16);
|
||||
k = k2;
|
||||
}
|
||||
return new SecretKeySpec(k, keyAlg);
|
||||
}
|
||||
|
||||
private void readObject(java.io.ObjectInputStream s)
|
||||
throws IOException, ClassNotFoundException {
|
||||
s.defaultReadObject ();
|
||||
initEngine();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return super.toString() + "/"
|
||||
+ (usedf ? "use_df" : "no_df");
|
||||
}
|
||||
}
|
271
jdk/src/java.base/share/classes/sun/security/provider/DRBG.java
Normal file
271
jdk/src/java.base/share/classes/sun/security/provider/DRBG.java
Normal file
@ -0,0 +1,271 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.provider;
|
||||
|
||||
import java.security.AccessController;
|
||||
import java.security.DrbgParameters;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.security.SecureRandomParameters;
|
||||
import java.security.SecureRandomSpi;
|
||||
import java.security.Security;
|
||||
import java.util.Locale;
|
||||
import static java.security.DrbgParameters.Capability.*;
|
||||
|
||||
/**
|
||||
* Implement the "SecureRandom.DRBG" algorithm.
|
||||
*
|
||||
* About the default "securerandom.drbg.config" value:
|
||||
*
|
||||
* The default value in java.security is set to "". This is because
|
||||
* the default values of different aspects are dependent (For example,
|
||||
* strength depends on algorithm) and if we write a full string there
|
||||
* it will be difficult to modify one and keep all others legal.
|
||||
*
|
||||
* When changing default values, touch all places including:
|
||||
*
|
||||
* 1. comments of the security property in java.security
|
||||
* 2. Default mech, cap, usedf set in this class
|
||||
* 3. Default algorithm set in final implementation of each mech
|
||||
* 4. Default strength set in AbstractDrbg, but the effective
|
||||
* value can be smaller if an algorithm does not support it.
|
||||
*
|
||||
* The default value is also mentioned in the @implNote part of
|
||||
* {@link DrbgParameters} class.
|
||||
*/
|
||||
public final class DRBG extends SecureRandomSpi {
|
||||
|
||||
private static final String PROP_NAME = "securerandom.drbg.config";
|
||||
|
||||
private static final long serialVersionUID = 9L;
|
||||
|
||||
private final AbstractDrbg impl;
|
||||
|
||||
private final String mechName;
|
||||
|
||||
private final String algorithmName;
|
||||
|
||||
public DRBG(SecureRandomParameters params) {
|
||||
|
||||
// All parameters at unset status (null or -1).
|
||||
|
||||
// Configurable with the "securerandom.drbg.config" security property
|
||||
String mech = null;
|
||||
Boolean usedf = null;
|
||||
String algorithm = null;
|
||||
|
||||
// Default instantiate parameters also configurable with
|
||||
// "securerandom.drbg.config", and can be changed with params
|
||||
// in getInstance("drbg", params)
|
||||
int strength = -1;
|
||||
DrbgParameters.Capability cap = null;
|
||||
byte[] ps = null;
|
||||
|
||||
// Not configurable with public interfaces, but is a part of
|
||||
// MoreDrbgParameters
|
||||
EntropySource es = null;
|
||||
byte[] nonce = null;
|
||||
|
||||
// Can be configured with a security property
|
||||
|
||||
String config = AccessController.doPrivileged((PrivilegedAction<String>)
|
||||
() -> Security.getProperty(PROP_NAME));
|
||||
|
||||
if (config != null && !config.isEmpty()) {
|
||||
for (String part : config.split(",")) {
|
||||
part = part.trim();
|
||||
switch (part.toLowerCase(Locale.ROOT)) {
|
||||
case "":
|
||||
throw new IllegalArgumentException(
|
||||
"aspect in " + PROP_NAME + " cannot be empty");
|
||||
case "pr_and_reseed":
|
||||
checkTwice(cap != null, "capability");
|
||||
cap = PR_AND_RESEED;
|
||||
break;
|
||||
case "reseed_only":
|
||||
checkTwice(cap != null, "capability");
|
||||
cap = RESEED_ONLY;
|
||||
break;
|
||||
case "none":
|
||||
checkTwice(cap != null, "capability");
|
||||
cap = NONE;
|
||||
break;
|
||||
case "hash_drbg":
|
||||
case "hmac_drbg":
|
||||
case "ctr_drbg":
|
||||
checkTwice(mech != null, "mechanism name");
|
||||
mech = part;
|
||||
break;
|
||||
case "no_df":
|
||||
checkTwice(usedf != null, "usedf flag");
|
||||
usedf = false;
|
||||
break;
|
||||
case "use_df":
|
||||
checkTwice(usedf != null, "usedf flag");
|
||||
usedf = true;
|
||||
break;
|
||||
default:
|
||||
// For all other parts of the property, it is
|
||||
// either an algorithm name or a strength
|
||||
try {
|
||||
int tmp = Integer.parseInt(part);
|
||||
if (tmp < 0) {
|
||||
throw new IllegalArgumentException(
|
||||
"strength in " + PROP_NAME +
|
||||
" cannot be negative: " + part);
|
||||
}
|
||||
checkTwice(strength >= 0, "strength");
|
||||
strength = tmp;
|
||||
} catch (NumberFormatException e) {
|
||||
checkTwice(algorithm != null, "algorithm name");
|
||||
algorithm = part;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Can be updated by params
|
||||
|
||||
if (params != null) {
|
||||
// MoreDrbgParameters is used for testing.
|
||||
if (params instanceof MoreDrbgParameters) {
|
||||
MoreDrbgParameters m = (MoreDrbgParameters)params;
|
||||
params = m.config;
|
||||
|
||||
// No need to check null for es and nonce, they are still null
|
||||
es = m.es;
|
||||
nonce = m.nonce;
|
||||
|
||||
if (m.mech != null) {
|
||||
mech = m.mech;
|
||||
}
|
||||
if (m.algorithm != null) {
|
||||
algorithm = m.algorithm;
|
||||
}
|
||||
usedf = m.usedf;
|
||||
}
|
||||
if (params instanceof DrbgParameters.Instantiation) {
|
||||
DrbgParameters.Instantiation dp =
|
||||
(DrbgParameters.Instantiation) params;
|
||||
|
||||
// ps is still null by now
|
||||
ps = dp.getPersonalizationString();
|
||||
|
||||
int tmp = dp.getStrength();
|
||||
if (tmp != -1) {
|
||||
strength = tmp;
|
||||
}
|
||||
cap = dp.getCapability();
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unsupported params: "
|
||||
+ params.getClass());
|
||||
}
|
||||
}
|
||||
|
||||
// Hardcoded defaults.
|
||||
// Remember to sync with "securerandom.drbg.config" in java.security.
|
||||
|
||||
if (cap == null) {
|
||||
cap = NONE;
|
||||
}
|
||||
if (mech == null) {
|
||||
mech = "Hash_DRBG";
|
||||
}
|
||||
if (usedf == null) {
|
||||
usedf = true;
|
||||
}
|
||||
|
||||
MoreDrbgParameters m = new MoreDrbgParameters(
|
||||
es, mech, algorithm, nonce, usedf,
|
||||
DrbgParameters.instantiation(strength, cap, ps));
|
||||
|
||||
switch (mech.toLowerCase(Locale.ROOT)) {
|
||||
case "hash_drbg":
|
||||
impl = new HashDrbg(m);
|
||||
break;
|
||||
case "hmac_drbg":
|
||||
impl = new HmacDrbg(m);
|
||||
break;
|
||||
case "ctr_drbg":
|
||||
impl = new CtrDrbg(m);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unsupported mech: " + mech);
|
||||
}
|
||||
|
||||
mechName = mech;
|
||||
algorithmName = impl.algorithm;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void engineSetSeed(byte[] seed) {
|
||||
impl.engineSetSeed(seed);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void engineNextBytes(byte[] bytes) {
|
||||
impl.engineNextBytes(bytes);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected byte[] engineGenerateSeed(int numBytes) {
|
||||
return impl.engineGenerateSeed(numBytes);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void engineNextBytes(
|
||||
byte[] bytes, SecureRandomParameters params) {
|
||||
impl.engineNextBytes(bytes, params);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void engineReseed(SecureRandomParameters params) {
|
||||
impl.engineReseed(params);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SecureRandomParameters engineGetParameters() {
|
||||
return impl.engineGetParameters();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return impl.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures an aspect is not set more than once.
|
||||
*
|
||||
* @param flag true if set more than once
|
||||
* @param name the name of aspect shown in IAE
|
||||
* @throws IllegalArgumentException if it happens
|
||||
*/
|
||||
private static void checkTwice(boolean flag, String name) {
|
||||
if (flag) {
|
||||
throw new IllegalArgumentException(name
|
||||
+ " cannot be provided more than once in " + PROP_NAME);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.provider;
|
||||
|
||||
/**
|
||||
* An interface of a source of entropy input.
|
||||
*
|
||||
* @since 9
|
||||
*/
|
||||
public interface EntropySource {
|
||||
/**
|
||||
* Returns a byte array containing entropy.
|
||||
* <p>
|
||||
* This maps to the {@code Get_entropy_input} function defined in
|
||||
* Section 9 of NIST SP 800-90Ar1.
|
||||
*
|
||||
* @param minEntropy minimum entropy required, in bytes
|
||||
* @param minLength minimum length of output, in bytes
|
||||
* @param maxLength maximum length of output, in bytes
|
||||
* @param pr whether prediction resistance is required
|
||||
* @return the byte array containing entropy
|
||||
*/
|
||||
byte[] getEntropy(int minEntropy, int minLength, int maxLength, boolean pr);
|
||||
}
|
@ -0,0 +1,276 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.provider;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.math.BigInteger;
|
||||
import java.security.DigestException;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.NoSuchProviderException;
|
||||
import java.security.SecureRandomParameters;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class HashDrbg extends AbstractHashDrbg {
|
||||
|
||||
private static final long serialVersionUID = 9L;
|
||||
|
||||
private static final byte[] ZERO = new byte[1];
|
||||
private static final byte[] ONE = new byte[]{1};
|
||||
|
||||
private transient MessageDigest digest;
|
||||
|
||||
private transient byte[] v;
|
||||
private transient byte[] c;
|
||||
|
||||
public HashDrbg(SecureRandomParameters params) {
|
||||
mechName = "Hash_DRBG";
|
||||
configure(params);
|
||||
}
|
||||
|
||||
/**
|
||||
* This call, used by the constructors, instantiates the digest.
|
||||
*/
|
||||
@Override
|
||||
protected void initEngine() {
|
||||
try {
|
||||
/*
|
||||
* Use the local SUN implementation to avoid native
|
||||
* performance overhead.
|
||||
*/
|
||||
digest = MessageDigest.getInstance(algorithm, "SUN");
|
||||
} catch (NoSuchProviderException | NoSuchAlgorithmException e) {
|
||||
// Fallback to any available.
|
||||
try {
|
||||
digest = MessageDigest.getInstance(algorithm);
|
||||
} catch (NoSuchAlgorithmException exc) {
|
||||
throw new InternalError(
|
||||
"internal error: " + algorithm + " not available.", exc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] hashDf(int requested, byte[]... inputs) {
|
||||
return hashDf(digest, outLen, requested, inputs);
|
||||
}
|
||||
|
||||
/**
|
||||
* A hash-based derivation function defined in NIST SP 800-90Ar1 10.3.1.
|
||||
* The function is used inside Hash_DRBG, and can also be used as an
|
||||
* approved conditioning function as described in 800-90B 6.4.2.2.
|
||||
*
|
||||
* @param digest a {@code MessageDigest} object in reset state
|
||||
* @param outLen {@link MessageDigest#getDigestLength} of {@code digest}
|
||||
* @param requested requested output length, in bytes
|
||||
* @param inputs input data
|
||||
* @return the condensed/expanded output
|
||||
*/
|
||||
public static byte[] hashDf(MessageDigest digest, int outLen,
|
||||
int requested, byte[]... inputs) {
|
||||
int len = (requested + outLen - 1) / outLen;
|
||||
byte[] temp = new byte[len * outLen];
|
||||
int counter = 1;
|
||||
|
||||
for (int i=0; i<len; i++) {
|
||||
digest.update((byte) counter);
|
||||
digest.update((byte)(requested >> 21)); // requested*8 as int32
|
||||
digest.update((byte)(requested >> 13));
|
||||
digest.update((byte)(requested >> 5));
|
||||
digest.update((byte)(requested << 3));
|
||||
for (byte[] input : inputs) {
|
||||
digest.update(input);
|
||||
}
|
||||
try {
|
||||
digest.digest(temp, i * outLen, outLen);
|
||||
} catch (DigestException e) {
|
||||
throw new AssertionError("will not happen", e);
|
||||
}
|
||||
counter++;
|
||||
}
|
||||
return temp.length == requested? temp: Arrays.copyOf(temp, requested);
|
||||
}
|
||||
|
||||
// This method is used by both instantiation and reseeding.
|
||||
@Override
|
||||
protected final void hashReseedInternal(byte[] input) {
|
||||
|
||||
// 800-90Ar1 10.1.1.2: Instantiate Process.
|
||||
// 800-90Ar1 10.1.1.3: Reseed Process.
|
||||
byte[] seed;
|
||||
|
||||
// Step 2: seed = Hash_df (seed_material, seedlen).
|
||||
if (v != null) {
|
||||
// Step 1 of 10.1.1.3: Prepend 0x01 || V
|
||||
seed = hashDf(seedLen, ONE, v, input);
|
||||
} else {
|
||||
seed = hashDf(seedLen, input);
|
||||
}
|
||||
|
||||
// Step 3. V = seed.
|
||||
v = seed;
|
||||
|
||||
// Step 4. C = Hash_df ((0x00 || V), seedlen).
|
||||
c = hashDf(seedLen, ZERO, v);
|
||||
|
||||
// Step 5. reseed_counter = 1.
|
||||
reseedCounter = 1;
|
||||
|
||||
//status();
|
||||
|
||||
// Step 6: Return
|
||||
}
|
||||
|
||||
private void status() {
|
||||
if (debug != null) {
|
||||
debug.println(this, "V = " + hex(v));
|
||||
debug.println(this, "C = " + hex(c));
|
||||
debug.println(this, "reseed counter = " + reseedCounter);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds byte arrays into an existing one.
|
||||
*
|
||||
* @param out existing array
|
||||
* @param data more arrays, can be of different length
|
||||
*/
|
||||
private static void addBytes(byte[] out, int len, byte[]... data) {
|
||||
for (byte[] d: data) {
|
||||
int dlen = d.length;
|
||||
int carry = 0;
|
||||
for (int i = 0; i < len; i++) {
|
||||
int sum = (out[len - i - 1] & 0xff) + carry;
|
||||
if (i < dlen) {
|
||||
sum += (d[dlen - i - 1] & 0xff);
|
||||
}
|
||||
out[len - i - 1] = (byte) sum;
|
||||
carry = sum >> 8;
|
||||
if (i >= dlen - 1 && carry == 0) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a user-specified number of random bytes.
|
||||
*
|
||||
* @param result the array to be filled in with random bytes.
|
||||
*/
|
||||
@Override
|
||||
public final synchronized void generateAlgorithm(
|
||||
byte[] result, byte[] additionalInput) {
|
||||
|
||||
if (debug != null) {
|
||||
debug.println(this, "generateAlgorithm");
|
||||
}
|
||||
|
||||
// 800-90Ar1 10.1.1.4: Hash_DRBG_Generate Process
|
||||
|
||||
// Step 1: Check reseed_counter. Will not fail. Already checked in
|
||||
// AbstractDrbg#engineNextBytes.
|
||||
|
||||
// Step 2: additional_input
|
||||
if (additionalInput != null) {
|
||||
digest.update((byte)2);
|
||||
digest.update(v);
|
||||
digest.update(additionalInput);
|
||||
addBytes(v, seedLen, digest.digest());
|
||||
}
|
||||
|
||||
// Step 3. Hashgen (requested_number_of_bits, V).
|
||||
hashGen(result, result.length, v);
|
||||
|
||||
// Step 4. H = Hash (0x03 || V).
|
||||
digest.update((byte)3);
|
||||
digest.update(v);
|
||||
byte[] h = digest.digest();
|
||||
|
||||
// Step 5. V = (V + H + C + reseed_counter) mod 2seedlen.
|
||||
byte[] rcBytes;
|
||||
if (reseedCounter < 256) {
|
||||
rcBytes = new byte[]{(byte)reseedCounter};
|
||||
} else {
|
||||
rcBytes = BigInteger.valueOf(reseedCounter).toByteArray();
|
||||
}
|
||||
addBytes(v, seedLen, h, c, rcBytes);
|
||||
|
||||
// Step 6. reseed_counter = reseed_counter + 1.
|
||||
reseedCounter++;
|
||||
|
||||
//status();
|
||||
|
||||
// Step 7: Return.
|
||||
}
|
||||
|
||||
// 800-90Ar1 10.1.1.4: Hashgen
|
||||
private void hashGen(byte[] output, int len, byte[] v) {
|
||||
|
||||
// Step 1. m
|
||||
int m = (len + outLen - 1) / outLen;
|
||||
|
||||
// Step 2. data = V
|
||||
byte[] data = v;
|
||||
|
||||
// Step 3: W is output not filled
|
||||
|
||||
// Step 4: For i = 1 to m
|
||||
for (int i = 0; i < m; i++) {
|
||||
int tailLen = len - i * outLen;
|
||||
if (tailLen < outLen) {
|
||||
// Step 4.1 w = Hash (data).
|
||||
// Step 4.2 W = W || w.
|
||||
System.arraycopy(digest.digest(data), 0, output, i * outLen,
|
||||
tailLen);
|
||||
} else {
|
||||
try {
|
||||
// Step 4.1 w = Hash (data).
|
||||
digest.update(data);
|
||||
// Step 4.2 digest into right position, no need to cat
|
||||
digest.digest(output, i*outLen, outLen);
|
||||
} catch (DigestException e) {
|
||||
throw new AssertionError("will not happen", e);
|
||||
}
|
||||
}
|
||||
// Unless this is the last around, we will need to increment data.
|
||||
// but we cannot change v, so a copy is made.
|
||||
if (i != m - 1) {
|
||||
if (data == v) {
|
||||
data = Arrays.copyOf(v, v.length);
|
||||
}
|
||||
// Step 4.3 data = (data + 1) mod 2^seedlen.
|
||||
addBytes(data, seedLen, ONE);
|
||||
}
|
||||
}
|
||||
|
||||
// Step 5: No need to truncate
|
||||
// Step 6: Return
|
||||
}
|
||||
|
||||
private void readObject(java.io.ObjectInputStream s)
|
||||
throws IOException, ClassNotFoundException {
|
||||
s.defaultReadObject ();
|
||||
initEngine();
|
||||
}
|
||||
}
|
@ -0,0 +1,203 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.provider;
|
||||
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.io.IOException;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.NoSuchProviderException;
|
||||
import java.security.SecureRandomParameters;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class HmacDrbg extends AbstractHashDrbg {
|
||||
|
||||
private static final long serialVersionUID = 9L;
|
||||
|
||||
private transient Mac mac;
|
||||
|
||||
private String macAlg;
|
||||
|
||||
private transient byte[] v;
|
||||
private transient byte[] k;
|
||||
|
||||
public HmacDrbg(SecureRandomParameters params) {
|
||||
mechName = "HMAC_DRBG";
|
||||
configure(params);
|
||||
}
|
||||
|
||||
private void status() {
|
||||
if (debug != null) {
|
||||
debug.println(this, "V = " + hex(v));
|
||||
debug.println(this, "Key = " + hex(k));
|
||||
debug.println(this, "reseed counter = " + reseedCounter);
|
||||
}
|
||||
}
|
||||
|
||||
// 800-90Ar1 10.1.2.2: HMAC_DRBG Update Process
|
||||
private void update(byte[]... inputs) {
|
||||
try {
|
||||
// Step 1. K = HMAC (K, V || 0x00 || provided_data).
|
||||
mac.init(new SecretKeySpec(k, macAlg));
|
||||
mac.update(v);
|
||||
mac.update((byte) 0);
|
||||
for (byte[] input: inputs) {
|
||||
mac.update(input);
|
||||
}
|
||||
k = mac.doFinal();
|
||||
|
||||
// Step 2. V = HMAC (K, V).
|
||||
mac.init(new SecretKeySpec(k, macAlg));
|
||||
v = mac.doFinal(v);
|
||||
|
||||
if (inputs.length != 0) {
|
||||
// Step 4. K = HMAC (K, V || 0x01 || provided_data).
|
||||
mac.update(v);
|
||||
mac.update((byte) 1);
|
||||
for (byte[] input: inputs) {
|
||||
mac.update(input);
|
||||
}
|
||||
k = mac.doFinal();
|
||||
|
||||
// Step 5. V=HMAC(K,V).
|
||||
mac.init(new SecretKeySpec(k, macAlg));
|
||||
v = mac.doFinal(v);
|
||||
} // else Step 3
|
||||
|
||||
// Step 6. Return
|
||||
} catch (InvalidKeyException e) {
|
||||
throw new InternalError(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This call, used by the constructors, instantiates the digest.
|
||||
*/
|
||||
@Override
|
||||
protected void initEngine() {
|
||||
macAlg = "HmacSHA" + algorithm.substring(4);
|
||||
try {
|
||||
mac = Mac.getInstance(macAlg, "SunJCE");
|
||||
} catch (NoSuchProviderException | NoSuchAlgorithmException e) {
|
||||
// Fallback to any available.
|
||||
try {
|
||||
mac = Mac.getInstance(macAlg);
|
||||
} catch (NoSuchAlgorithmException exc) {
|
||||
throw new InternalError(
|
||||
"internal error: " + macAlg + " not available.", exc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This method is used by both instantiation and reseeding.
|
||||
@Override
|
||||
protected final void hashReseedInternal(byte[] input) {
|
||||
|
||||
// 800-90Ar1 10.1.2.3: Instantiate Process.
|
||||
// 800-90Ar1 10.1.2.4: Reseed Process.
|
||||
if (v == null) {
|
||||
k = new byte[outLen];
|
||||
v = new byte[outLen];
|
||||
Arrays.fill(v, (byte) 1);
|
||||
}
|
||||
|
||||
// Step 2: HMAC_DRBG_Update
|
||||
update(input);
|
||||
|
||||
// Step 3: reseed_counter = 1.
|
||||
reseedCounter = 1;
|
||||
//status();
|
||||
|
||||
// Step 4: Return
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a user-specified number of random bytes.
|
||||
*
|
||||
* @param result the array to be filled in with random bytes.
|
||||
*/
|
||||
@Override
|
||||
public synchronized void generateAlgorithm(
|
||||
byte[] result, byte[] additionalInput) {
|
||||
|
||||
if (debug != null) {
|
||||
debug.println(this, "generateAlgorithm");
|
||||
}
|
||||
|
||||
// 800-90Ar1 10.1.2.5: HMAC_DRBG_Generate Process
|
||||
|
||||
// Step 1: Check reseed_counter. Will not fail. Already checked in
|
||||
// AbstractDrbg#engineNextBytes.
|
||||
|
||||
// Step 2. HMAC_DRBG_Update
|
||||
if (additionalInput != null) {
|
||||
update(additionalInput);
|
||||
}
|
||||
|
||||
// Step 3. temp = Null.
|
||||
int pos = 0;
|
||||
|
||||
// Step 4. Loop
|
||||
while (pos < result.length) {
|
||||
int tailLen = result.length - pos;
|
||||
|
||||
// Step 4.1 V = HMAC (Key, V).
|
||||
try {
|
||||
mac.init(new SecretKeySpec(k, macAlg));
|
||||
} catch (InvalidKeyException e) {
|
||||
throw new InternalError(e);
|
||||
}
|
||||
v = mac.doFinal(v);
|
||||
// Step 4.2 temp = temp || V.
|
||||
System.arraycopy(v, 0, result, pos,
|
||||
tailLen > outLen ? outLen : tailLen);
|
||||
pos += outLen;
|
||||
}
|
||||
|
||||
// Step 5: No need to truncate
|
||||
|
||||
// Step 6. HMAC_DRBG_Update (additional_input, Key, V).
|
||||
if (additionalInput != null) {
|
||||
update(additionalInput);
|
||||
} else {
|
||||
update();
|
||||
}
|
||||
|
||||
// Step 7. reseed_counter = reseed_counter + 1.
|
||||
reseedCounter++;
|
||||
|
||||
//status();
|
||||
|
||||
// Step 8. Return
|
||||
}
|
||||
|
||||
private void readObject(java.io.ObjectInputStream s)
|
||||
throws IOException, ClassNotFoundException {
|
||||
s.defaultReadObject ();
|
||||
initEngine();
|
||||
}
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.security.provider;
|
||||
|
||||
import java.security.DrbgParameters;
|
||||
import java.security.SecureRandomParameters;
|
||||
|
||||
/**
|
||||
* Extra non-standard parameters that can be used by DRBGs.
|
||||
*/
|
||||
public class MoreDrbgParameters implements SecureRandomParameters {
|
||||
|
||||
final String mech;
|
||||
final String algorithm;
|
||||
final EntropySource es;
|
||||
final byte[] nonce;
|
||||
final boolean usedf;
|
||||
final DrbgParameters.Instantiation config;
|
||||
|
||||
/**
|
||||
* Creates a new {@code MoreDrbgParameters} object.
|
||||
*
|
||||
* @param es the {@link EntropySource} to use. If set to {@code null},
|
||||
* a default entropy source will be used.
|
||||
* @param mech mech name. If set to {@code null}, the one in
|
||||
* securerandom.drbg.config is used. This argument is ignored
|
||||
* when passing to HashDrbg/HmacDrbg/CtrDrbg.
|
||||
* @param algorithm the requested algorithm to use. If set to {@code null},
|
||||
* the algorithm will be decided by strength.
|
||||
* @param nonce the nonce to use. If set to {@code null},
|
||||
* a nonce will be assigned.
|
||||
* @param usedf whether a derivation function should be used
|
||||
* @param config a {@link DrbgParameters.Instantiation} object
|
||||
*/
|
||||
public MoreDrbgParameters(EntropySource es, String mech,
|
||||
String algorithm, byte[] nonce, boolean usedf,
|
||||
DrbgParameters.Instantiation config) {
|
||||
this.mech = mech;
|
||||
this.algorithm = algorithm;
|
||||
this.es = es;
|
||||
this.nonce = nonce;
|
||||
this.usedf = usedf;
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return mech + "," + algorithm + "," + usedf + "," + config;
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -25,9 +25,7 @@
|
||||
|
||||
package sun.security.provider;
|
||||
|
||||
import java.security.*;
|
||||
import java.util.Objects;
|
||||
import java.math.BigInteger;
|
||||
|
||||
import jdk.internal.HotSpotIntrinsicCandidate;
|
||||
import static sun.security.provider.ByteArrayAccess.*;
|
||||
@ -118,7 +116,14 @@ abstract class SHA5 extends DigestBase {
|
||||
i2bBig4((int)bitsProcessed, buffer, 124);
|
||||
implCompress(buffer, 0);
|
||||
|
||||
l2bBig(state, 0, out, ofs, engineGetDigestLength());
|
||||
int len = engineGetDigestLength();
|
||||
if (len == 28) {
|
||||
// Special case for SHA-512/224
|
||||
l2bBig(state, 0, out, ofs, 24);
|
||||
i2bBig4((int)(state[3] >> 32), out, ofs + 24);
|
||||
} else {
|
||||
l2bBig(state, 0, out, ofs, len);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -306,4 +311,31 @@ abstract class SHA5 extends DigestBase {
|
||||
super("SHA-384", 48, INITIAL_HASHES);
|
||||
}
|
||||
}
|
||||
public static final class SHA512_224 extends SHA5 {
|
||||
|
||||
private static final long[] INITIAL_HASHES = {
|
||||
0x8C3D37C819544DA2L, 0x73E1996689DCD4D6L,
|
||||
0x1DFAB7AE32FF9C82L, 0x679DD514582F9FCFL,
|
||||
0x0F6D2B697BD44DA8L, 0x77E36F7304C48942L,
|
||||
0x3F9D85A86A1D36C8L, 0x1112E6AD91D692A1L
|
||||
};
|
||||
|
||||
public SHA512_224() {
|
||||
super("SHA-512/224", 28, INITIAL_HASHES);
|
||||
}
|
||||
}
|
||||
|
||||
public static final class SHA512_256 extends SHA5 {
|
||||
|
||||
private static final long[] INITIAL_HASHES = {
|
||||
0x22312194FC2BF72CL, 0x9F555FA3C84C64C2L,
|
||||
0x2393B86B6F53B151L, 0x963877195940EABDL,
|
||||
0x96283EE2A88EFFE3L, 0xBE5E1E2553863992L,
|
||||
0x2B0199FC2C85B8AAL, 0x0EB72DDC81C52CA2L
|
||||
};
|
||||
|
||||
public SHA512_256() {
|
||||
super("SHA-512/256", 32, INITIAL_HASHES);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -97,6 +97,9 @@ final class SunEntries {
|
||||
map.put("SecureRandom.NativePRNG",
|
||||
"sun.security.provider.NativePRNG");
|
||||
}
|
||||
|
||||
map.put("SecureRandom.DRBG", "sun.security.provider.DRBG");
|
||||
|
||||
map.put("SecureRandom.SHA1PRNG",
|
||||
"sun.security.provider.SecureRandom");
|
||||
if (nativeAvailable && !useNativePRNG) {
|
||||
@ -199,6 +202,14 @@ final class SunEntries {
|
||||
map.put("Alg.Alias.MessageDigest.2.16.840.1.101.3.4.2.3", "SHA-512");
|
||||
map.put("Alg.Alias.MessageDigest.OID.2.16.840.1.101.3.4.2.3",
|
||||
"SHA-512");
|
||||
map.put("MessageDigest.SHA-512/224", "sun.security.provider.SHA5$SHA512_224");
|
||||
map.put("Alg.Alias.MessageDigest.2.16.840.1.101.3.4.2.5", "SHA-512/224");
|
||||
map.put("Alg.Alias.MessageDigest.OID.2.16.840.1.101.3.4.2.5",
|
||||
"SHA-512/224");
|
||||
map.put("MessageDigest.SHA-512/256", "sun.security.provider.SHA5$SHA512_256");
|
||||
map.put("Alg.Alias.MessageDigest.2.16.840.1.101.3.4.2.6", "SHA-512/256");
|
||||
map.put("Alg.Alias.MessageDigest.OID.2.16.840.1.101.3.4.2.6",
|
||||
"SHA-512/256");
|
||||
|
||||
/*
|
||||
* Algorithm Parameter Generator engines
|
||||
|
@ -933,10 +933,8 @@ final class ClientHandshaker extends Handshaker {
|
||||
ECParameterSpec params =
|
||||
((ECPublicKey)publicKey).getParams();
|
||||
int index =
|
||||
SupportedEllipticCurvesExtension.getCurveIndex(
|
||||
params);
|
||||
if (!SupportedEllipticCurvesExtension.isSupported(
|
||||
index)) {
|
||||
EllipticCurvesExtension.getCurveIndex(params);
|
||||
if (!EllipticCurvesExtension.isSupported(index)) {
|
||||
publicKey = null;
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2006, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -32,10 +32,10 @@ import java.util.Map;
|
||||
|
||||
import javax.net.ssl.SSLProtocolException;
|
||||
|
||||
final class SupportedEllipticCurvesExtension extends HelloExtension {
|
||||
final class EllipticCurvesExtension extends HelloExtension {
|
||||
|
||||
// the extension value to send in the ClientHello message
|
||||
static final SupportedEllipticCurvesExtension DEFAULT;
|
||||
static final EllipticCurvesExtension DEFAULT;
|
||||
|
||||
private static final boolean fips;
|
||||
|
||||
@ -56,17 +56,17 @@ final class SupportedEllipticCurvesExtension extends HelloExtension {
|
||||
23, 1, 3, 19, 21, 6, 7, 9, 10, 24, 11, 12, 25, 13, 14,
|
||||
};
|
||||
}
|
||||
DEFAULT = new SupportedEllipticCurvesExtension(ids);
|
||||
DEFAULT = new EllipticCurvesExtension(ids);
|
||||
}
|
||||
|
||||
private final int[] curveIds;
|
||||
|
||||
private SupportedEllipticCurvesExtension(int[] curveIds) {
|
||||
private EllipticCurvesExtension(int[] curveIds) {
|
||||
super(ExtensionType.EXT_ELLIPTIC_CURVES);
|
||||
this.curveIds = curveIds;
|
||||
}
|
||||
|
||||
SupportedEllipticCurvesExtension(HandshakeInStream s, int len)
|
||||
EllipticCurvesExtension(HandshakeInStream s, int len)
|
||||
throws IOException {
|
||||
super(ExtensionType.EXT_ELLIPTIC_CURVES);
|
||||
int k = s.getInt16();
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2006, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2006, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -31,24 +31,23 @@ import java.util.List;
|
||||
|
||||
import javax.net.ssl.SSLProtocolException;
|
||||
|
||||
final class SupportedEllipticPointFormatsExtension extends HelloExtension {
|
||||
final class EllipticPointFormatsExtension extends HelloExtension {
|
||||
|
||||
static final int FMT_UNCOMPRESSED = 0;
|
||||
static final int FMT_ANSIX962_COMPRESSED_PRIME = 1;
|
||||
static final int FMT_ANSIX962_COMPRESSED_CHAR2 = 2;
|
||||
|
||||
static final HelloExtension DEFAULT =
|
||||
new SupportedEllipticPointFormatsExtension(
|
||||
new byte[] {FMT_UNCOMPRESSED});
|
||||
new EllipticPointFormatsExtension(new byte[] {FMT_UNCOMPRESSED});
|
||||
|
||||
private final byte[] formats;
|
||||
|
||||
private SupportedEllipticPointFormatsExtension(byte[] formats) {
|
||||
private EllipticPointFormatsExtension(byte[] formats) {
|
||||
super(ExtensionType.EXT_EC_POINT_FORMATS);
|
||||
this.formats = formats;
|
||||
}
|
||||
|
||||
SupportedEllipticPointFormatsExtension(HandshakeInStream s, int len)
|
||||
EllipticPointFormatsExtension(HandshakeInStream s, int len)
|
||||
throws IOException {
|
||||
super(ExtensionType.EXT_EC_POINT_FORMATS);
|
||||
formats = s.getBytes8();
|
@ -314,8 +314,8 @@ static final class ClientHello extends HandshakeMessage {
|
||||
}
|
||||
|
||||
if (cipherSuites.containsEC()) {
|
||||
extensions.add(SupportedEllipticCurvesExtension.DEFAULT);
|
||||
extensions.add(SupportedEllipticPointFormatsExtension.DEFAULT);
|
||||
extensions.add(EllipticCurvesExtension.DEFAULT);
|
||||
extensions.add(EllipticPointFormatsExtension.DEFAULT);
|
||||
}
|
||||
|
||||
clnt_random = new RandomCookie(generator);
|
||||
@ -1401,7 +1401,7 @@ class ECDH_ServerKeyExchange extends ServerKeyExchange {
|
||||
ECParameterSpec params = publicKey.getParams();
|
||||
ECPoint point = publicKey.getW();
|
||||
pointBytes = JsseJce.encodePoint(point, params.getCurve());
|
||||
curveId = SupportedEllipticCurvesExtension.getCurveIndex(params);
|
||||
curveId = EllipticCurvesExtension.getCurveIndex(params);
|
||||
|
||||
if (privateKey == null) {
|
||||
// ECDH_anon
|
||||
@ -1439,13 +1439,11 @@ class ECDH_ServerKeyExchange extends ServerKeyExchange {
|
||||
// the supported curves during the exchange of the Hello messages.
|
||||
if (curveType == CURVE_NAMED_CURVE) {
|
||||
curveId = input.getInt16();
|
||||
if (SupportedEllipticCurvesExtension.isSupported(curveId)
|
||||
== false) {
|
||||
if (!EllipticCurvesExtension.isSupported(curveId)) {
|
||||
throw new SSLHandshakeException(
|
||||
"Unsupported curveId: " + curveId);
|
||||
}
|
||||
String curveOid =
|
||||
SupportedEllipticCurvesExtension.getCurveOid(curveId);
|
||||
String curveOid = EllipticCurvesExtension.getCurveOid(curveId);
|
||||
if (curveOid == null) {
|
||||
throw new SSLHandshakeException(
|
||||
"Unknown named curve: " + curveId);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2006, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -49,8 +49,8 @@ import javax.net.ssl.*;
|
||||
* explicitly support.
|
||||
* . ServerNameExtension: the server_name extension.
|
||||
* . SignatureAlgorithmsExtension: the signature_algorithms extension.
|
||||
* . SupportedEllipticCurvesExtension: the ECC supported curves extension.
|
||||
* . SupportedEllipticPointFormatsExtension: the ECC supported point formats
|
||||
* . EllipticCurvesExtension: the ECC supported curves extension.
|
||||
* . EllipticPointFormatsExtension: the ECC supported point formats
|
||||
* (compressed/uncompressed) extension.
|
||||
* . ALPNExtension: the application_layer_protocol_negotiation extension.
|
||||
*
|
||||
@ -80,10 +80,9 @@ final class HelloExtensions {
|
||||
} else if (extType == ExtensionType.EXT_SIGNATURE_ALGORITHMS) {
|
||||
extension = new SignatureAlgorithmsExtension(s, extlen);
|
||||
} else if (extType == ExtensionType.EXT_ELLIPTIC_CURVES) {
|
||||
extension = new SupportedEllipticCurvesExtension(s, extlen);
|
||||
extension = new EllipticCurvesExtension(s, extlen);
|
||||
} else if (extType == ExtensionType.EXT_EC_POINT_FORMATS) {
|
||||
extension =
|
||||
new SupportedEllipticPointFormatsExtension(s, extlen);
|
||||
extension = new EllipticPointFormatsExtension(s, extlen);
|
||||
} else if (extType == ExtensionType.EXT_RENEGOTIATION_INFO) {
|
||||
extension = new RenegotiationInfoExtension(s, extlen);
|
||||
} else if (extType == ExtensionType.EXT_ALPN) {
|
||||
|
@ -94,7 +94,7 @@ final class ServerHandshaker extends Handshaker {
|
||||
// we remember it for the RSA premaster secret version check
|
||||
private ProtocolVersion clientRequestedVersion;
|
||||
|
||||
private SupportedEllipticCurvesExtension supportedCurves;
|
||||
private EllipticCurvesExtension supportedCurves;
|
||||
|
||||
// the preferable signature algorithm used by ServerKeyExchange message
|
||||
SignatureAndHashAlgorithm preferableSignatureAlgorithm;
|
||||
@ -741,7 +741,7 @@ final class ServerHandshaker extends Handshaker {
|
||||
throw new SSLException("Client did not resume a session");
|
||||
}
|
||||
|
||||
supportedCurves = (SupportedEllipticCurvesExtension)
|
||||
supportedCurves = (EllipticCurvesExtension)
|
||||
mesg.extensions.get(ExtensionType.EXT_ELLIPTIC_CURVES);
|
||||
|
||||
// We only need to handle the "signature_algorithm" extension
|
||||
@ -1577,7 +1577,7 @@ final class ServerHandshaker extends Handshaker {
|
||||
// if the client sent the supported curves extension, pick the
|
||||
// first one that we support;
|
||||
for (int curveId : supportedCurves.curveIds()) {
|
||||
if (SupportedEllipticCurvesExtension.isSupported(curveId)) {
|
||||
if (EllipticCurvesExtension.isSupported(curveId)) {
|
||||
index = curveId;
|
||||
break;
|
||||
}
|
||||
@ -1588,9 +1588,9 @@ final class ServerHandshaker extends Handshaker {
|
||||
}
|
||||
} else {
|
||||
// pick our preference
|
||||
index = SupportedEllipticCurvesExtension.DEFAULT.curveIds()[0];
|
||||
index = EllipticCurvesExtension.DEFAULT.curveIds()[0];
|
||||
}
|
||||
String oid = SupportedEllipticCurvesExtension.getCurveOid(index);
|
||||
String oid = EllipticCurvesExtension.getCurveOid(index);
|
||||
ecdh = new ECDHCrypt(oid, sslContext.getSecureRandom());
|
||||
return true;
|
||||
}
|
||||
@ -1633,15 +1633,15 @@ final class ServerHandshaker extends Handshaker {
|
||||
return false;
|
||||
}
|
||||
// For ECC certs, check whether we support the EC domain parameters.
|
||||
// If the client sent a SupportedEllipticCurves ClientHello extension,
|
||||
// If the client sent a EllipticCurves ClientHello extension,
|
||||
// check against that too.
|
||||
if (keyAlgorithm.equals("EC")) {
|
||||
if (publicKey instanceof ECPublicKey == false) {
|
||||
return false;
|
||||
}
|
||||
ECParameterSpec params = ((ECPublicKey)publicKey).getParams();
|
||||
int index = SupportedEllipticCurvesExtension.getCurveIndex(params);
|
||||
if (SupportedEllipticCurvesExtension.isSupported(index) == false) {
|
||||
int index = EllipticCurvesExtension.getCurveIndex(params);
|
||||
if (!EllipticCurvesExtension.isSupported(index)) {
|
||||
return false;
|
||||
}
|
||||
if ((supportedCurves != null) && !supportedCurves.contains(index)) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -87,6 +87,7 @@ public class Debug {
|
||||
System.err.println("pkcs12 PKCS12 KeyStore debugging");
|
||||
System.err.println("sunpkcs11 SunPKCS11 provider debugging");
|
||||
System.err.println("scl permissions SecureClassLoader assigns");
|
||||
System.err.println("securerandom SecureRandom");
|
||||
System.err.println("ts timestamping");
|
||||
System.err.println();
|
||||
System.err.println("The following can be used with access:");
|
||||
@ -174,6 +175,16 @@ public class Debug {
|
||||
System.err.println(prefix + ": "+message);
|
||||
}
|
||||
|
||||
/**
|
||||
* print a message to stderr that is prefixed with the prefix
|
||||
* created from the call to getInstance and obj.
|
||||
*/
|
||||
public void println(Object obj, String message)
|
||||
{
|
||||
System.err.println(prefix + " [" + obj.getClass().getSimpleName() +
|
||||
"@" + System.identityHashCode(obj) + "]: "+message);
|
||||
}
|
||||
|
||||
/**
|
||||
* print a blank line to stderr that is prefixed with the prefix.
|
||||
*/
|
||||
|
@ -8,6 +8,19 @@ grant codeBase "jrt:/java.corba" {
|
||||
permission java.security.AllPermission;
|
||||
};
|
||||
|
||||
grant codeBase "jrt:/java.compiler" {
|
||||
permission java.security.AllPermission;
|
||||
};
|
||||
|
||||
grant codeBase "jrt:/jdk.charsets" {
|
||||
permission java.io.FilePermission "${java.home}/-", "read";
|
||||
permission java.util.PropertyPermission "os.name", "read";
|
||||
permission java.util.PropertyPermission "sun.nio.cs.map", "read";
|
||||
permission java.lang.RuntimePermission "charsetProvider";
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.jdk.internal.misc";
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.sun.nio.cs";
|
||||
};
|
||||
|
||||
grant codeBase "jrt:/jdk.crypto.ucrypto" {
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.sun.security.*";
|
||||
permission java.lang.RuntimePermission "accessClassInPackage.sun.nio.ch";
|
||||
|
@ -120,30 +120,30 @@ jdk.security.provider.preferred=AES:SunJCE, RSA:SunRsaSign
|
||||
#
|
||||
# Sun Provider SecureRandom seed source.
|
||||
#
|
||||
# Select the primary source of seed data for the "SHA1PRNG" and
|
||||
# "NativePRNG" SecureRandom implementations in the "Sun" provider.
|
||||
# Select the primary source of seed data for the "NativePRNG", "SHA1PRNG"
|
||||
# and "DRBG" SecureRandom implementations in the "Sun" provider.
|
||||
# (Other SecureRandom implementations might also use this property.)
|
||||
#
|
||||
# On Unix-like systems (for example, Solaris/Linux/MacOS), the
|
||||
# "NativePRNG" and "SHA1PRNG" implementations obtains seed data from
|
||||
# "NativePRNG", "SHA1PRNG" and "DRBG" implementations obtains seed data from
|
||||
# special device files such as file:/dev/random.
|
||||
#
|
||||
# On Windows systems, specifying the URLs "file:/dev/random" or
|
||||
# "file:/dev/urandom" will enable the native Microsoft CryptoAPI seeding
|
||||
# mechanism for SHA1PRNG.
|
||||
# mechanism for SHA1PRNG and DRBG.
|
||||
#
|
||||
# By default, an attempt is made to use the entropy gathering device
|
||||
# specified by the "securerandom.source" Security property. If an
|
||||
# exception occurs while accessing the specified URL:
|
||||
#
|
||||
# SHA1PRNG:
|
||||
# the traditional system/thread activity algorithm will be used.
|
||||
#
|
||||
# NativePRNG:
|
||||
# a default value of /dev/random will be used. If neither
|
||||
# are available, the implementation will be disabled.
|
||||
# "file" is the only currently supported protocol type.
|
||||
#
|
||||
# SHA1PRNG and DRBG:
|
||||
# the traditional system/thread activity algorithm will be used.
|
||||
#
|
||||
# The entropy gathering device can also be specified with the System
|
||||
# property "java.security.egd". For example:
|
||||
#
|
||||
@ -154,7 +154,7 @@ jdk.security.provider.preferred=AES:SunJCE, RSA:SunRsaSign
|
||||
#
|
||||
# In addition, if "file:/dev/random" or "file:/dev/urandom" is
|
||||
# specified, the "NativePRNG" implementation will be more preferred than
|
||||
# SHA1PRNG in the Sun provider.
|
||||
# DRBG and SHA1PRNG in the Sun provider.
|
||||
#
|
||||
securerandom.source=file:/dev/random
|
||||
|
||||
@ -169,12 +169,78 @@ securerandom.source=file:/dev/random
|
||||
# entries.
|
||||
#
|
||||
#ifdef windows
|
||||
securerandom.strongAlgorithms=Windows-PRNG:SunMSCAPI,SHA1PRNG:SUN
|
||||
securerandom.strongAlgorithms=Windows-PRNG:SunMSCAPI,DRBG:SUN
|
||||
#endif
|
||||
#ifndef windows
|
||||
securerandom.strongAlgorithms=NativePRNGBlocking:SUN
|
||||
securerandom.strongAlgorithms=NativePRNGBlocking:SUN,DRBG:SUN
|
||||
#endif
|
||||
|
||||
#
|
||||
# Sun provider DRBG configuration and default instantiation request.
|
||||
#
|
||||
# NIST SP 800-90Ar1 lists several DRBG mechanisms. Each can be configured
|
||||
# with a DRBG algorithm name, and can be instantiated with a security strength,
|
||||
# prediction resistance support, etc. This property defines the configuration
|
||||
# and the default instantiation request of "DRBG" SecureRandom implementations
|
||||
# in the SUN provider. (Other DRBG implementations can also use this property.)
|
||||
# Applications can request different instantiation parameters like security
|
||||
# strength, capability, personalization string using one of the
|
||||
# getInstance(...,SecureRandomParameters,...) methods with a
|
||||
# DrbgParameters.Instantiation argument, but other settings such as the
|
||||
# mechanism and DRBG algorithm names are not currently configurable by any API.
|
||||
#
|
||||
# Please note that the SUN implementation of DRBG always supports reseeding.
|
||||
#
|
||||
# The value of this property is a comma-separated list of all configurable
|
||||
# aspects. The aspects can appear in any order but the same aspect can only
|
||||
# appear at most once. Its BNF-style definition is:
|
||||
#
|
||||
# Value:
|
||||
# aspect { "," aspect }
|
||||
#
|
||||
# aspect:
|
||||
# mech_name | algorithm_name | strength | capability | df
|
||||
#
|
||||
# // The DRBG mechanism to use. Default "Hash_DRBG"
|
||||
# mech_name:
|
||||
# "Hash_DRBG" | "HMAC_DRBG" | "CTR_DRBG"
|
||||
#
|
||||
# // The DRBG algorithm name. The "SHA-***" names are for Hash_DRBG and
|
||||
# // HMAC_DRBG, default "SHA-256". "3KeyTDEA" and "AES-***" names are for
|
||||
# // CTR_DRBG, default "AES-128" when using the limited cryptographic
|
||||
# // or "AES-256" when using the unlimited.
|
||||
# algorithm_name:
|
||||
# "SHA-1" | "SHA-224" | "SHA-512/224" | "SHA-256" |
|
||||
# "SHA-512/256" | "SHA-384" | "SHA-512" |
|
||||
# "3KeyTDEA" | "AES-128" | "AES-192" | "AES-256"
|
||||
#
|
||||
# // Security strength requested. Default "128", or "112"
|
||||
# // if mech_name is CTR_DRBG and algorithm_name is "3KeyTDEA"
|
||||
# strength:
|
||||
# "112" | "128" | "192" | "256"
|
||||
#
|
||||
# // Prediction resistance and reseeding request. Default "none"
|
||||
# // "pr_and_reseed" - Both prediction resistance and reseeding
|
||||
# // support requested
|
||||
# // "reseed_only" - Only reseeding support requested
|
||||
# // "none" - Neither prediction resistance not reseeding
|
||||
# // support requested
|
||||
# pr:
|
||||
# "pr_and_reseed" | "reseed_only" | "none"
|
||||
#
|
||||
# // Whether a derivation function should be used. only applicable
|
||||
# // to CTR_DRBG. Default "use_df"
|
||||
# df:
|
||||
# "use_df" | "no_df"
|
||||
#
|
||||
# Examples,
|
||||
# securerandom.drbg.config=Hash_DRBG,SHA-1,112,none
|
||||
# securerandom.drbg.config=CTR_DRBG,AES-256,192,pr_and_reseed,use_df
|
||||
#
|
||||
# The default value is an empty string, which is equivalent to
|
||||
# securerandom.drbg.config=Hash_DRBG,SHA-256,128,none
|
||||
securerandom.drbg.config=
|
||||
|
||||
#
|
||||
# Class to instantiate as the javax.security.auth.login.Configuration
|
||||
# provider.
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -94,6 +94,7 @@ idevpoll(jint wfd, int dpctl, struct dvpoll a)
|
||||
return 0;
|
||||
}
|
||||
start = now;
|
||||
a.dp_timeout = remaining;
|
||||
}
|
||||
} else {
|
||||
return res;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -25,12 +25,15 @@
|
||||
|
||||
package sun.lwawt.macosx;
|
||||
|
||||
import sun.lwawt.LWWindowPeer;
|
||||
|
||||
import java.awt.*;
|
||||
import java.beans.*;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.Callable;
|
||||
import sun.awt.AWTAccessor;
|
||||
|
||||
import javax.accessibility.*;
|
||||
import javax.swing.*;
|
||||
@ -421,6 +424,8 @@ class CAccessibility implements PropertyChangeListener {
|
||||
}
|
||||
|
||||
public static AccessibleAction getAccessibleAction(final Accessible a, final Component c) {
|
||||
if (a == null) return null;
|
||||
|
||||
return invokeAndWait(new Callable<AccessibleAction>() {
|
||||
public AccessibleAction call() throws Exception {
|
||||
final AccessibleContext ac = a.getAccessibleContext();
|
||||
@ -667,4 +672,28 @@ class CAccessibility implements PropertyChangeListener {
|
||||
}
|
||||
}, c);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return AWTView ptr, a peer of the CPlatformView associated with the toplevel container of the Accessible, if any
|
||||
*/
|
||||
private static long getAWTView(Accessible a) {
|
||||
Accessible ax = CAccessible.getSwingAccessible(a);
|
||||
if (!(ax instanceof Component)) return 0;
|
||||
|
||||
return invokeAndWait(new Callable<Long>() {
|
||||
public Long call() throws Exception {
|
||||
Component cont = (Component) ax;
|
||||
while (cont != null && !(cont instanceof Window)) {
|
||||
cont = cont.getParent();
|
||||
}
|
||||
if (cont != null) {
|
||||
LWWindowPeer peer = (LWWindowPeer) AWTAccessor.getComponentAccessor().getPeer(cont);
|
||||
if (peer != null) {
|
||||
return ((CPlatformWindow) peer.getPlatformWindow()).getContentView().getAWTView();
|
||||
}
|
||||
}
|
||||
return 0L;
|
||||
}
|
||||
}, (Component)ax);
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -264,6 +264,8 @@ class CAccessibleText {
|
||||
final double localY = boundsUnion.getY();
|
||||
|
||||
final Point componentLocation = ac.getAccessibleComponent().getLocationOnScreen();
|
||||
if (componentLocation == null) return ret;
|
||||
|
||||
final double screenX = componentLocation.getX() + localX;
|
||||
final double screenY = componentLocation.getY() + localY;
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -62,6 +62,8 @@
|
||||
- (void) deliverJavaMouseEvent: (NSEvent *) event;
|
||||
- (jobject) awtComponent:(JNIEnv *)env;
|
||||
|
||||
+ (AWTView *) awtView:(JNIEnv *)env ofAccessible:(jobject)jaccessible;
|
||||
|
||||
// Input method-related events
|
||||
- (void)setInputMethod:(jobject)inputMethod;
|
||||
- (void)abandonInput;
|
||||
|
@ -29,6 +29,7 @@
|
||||
#import "AWTWindow.h"
|
||||
#import "JavaComponentAccessibility.h"
|
||||
#import "JavaTextAccessibility.h"
|
||||
#import "JavaAccessibilityUtilities.h"
|
||||
#import "GeomUtilities.h"
|
||||
#import "OSVersion.h"
|
||||
#import "ThreadUtilities.h"
|
||||
@ -129,7 +130,7 @@ static BOOL shouldUsePressAndHold() {
|
||||
self.cglLayer = nil;
|
||||
|
||||
JNIEnv *env = [ThreadUtilities getJNIEnvUncached];
|
||||
(*env)->DeleteGlobalRef(env, m_cPlatformView);
|
||||
(*env)->DeleteWeakGlobalRef(env, m_cPlatformView);
|
||||
m_cPlatformView = NULL;
|
||||
|
||||
if (fInputMethodLOCKABLE != NULL)
|
||||
@ -396,7 +397,11 @@ static BOOL shouldUsePressAndHold() {
|
||||
|
||||
static JNF_CLASS_CACHE(jc_PlatformView, "sun/lwawt/macosx/CPlatformView");
|
||||
static JNF_MEMBER_CACHE(jm_deliverMouseEvent, jc_PlatformView, "deliverMouseEvent", "(Lsun/lwawt/macosx/NSEvent;)V");
|
||||
JNFCallVoidMethod(env, m_cPlatformView, jm_deliverMouseEvent, jEvent);
|
||||
jobject jlocal = (*env)->NewLocalRef(env, m_cPlatformView);
|
||||
if (!(*env)->IsSameObject(env, jlocal, NULL)) {
|
||||
JNFCallVoidMethod(env, jlocal, jm_deliverMouseEvent, jEvent);
|
||||
(*env)->DeleteLocalRef(env, jlocal);
|
||||
}
|
||||
(*env)->DeleteLocalRef(env, jEvent);
|
||||
}
|
||||
|
||||
@ -459,8 +464,11 @@ static BOOL shouldUsePressAndHold() {
|
||||
static JNF_CLASS_CACHE(jc_PlatformView, "sun/lwawt/macosx/CPlatformView");
|
||||
static JNF_MEMBER_CACHE(jm_deliverKeyEvent, jc_PlatformView,
|
||||
"deliverKeyEvent", "(Lsun/lwawt/macosx/NSEvent;)V");
|
||||
JNFCallVoidMethod(env, m_cPlatformView, jm_deliverKeyEvent, jEvent);
|
||||
|
||||
jobject jlocal = (*env)->NewLocalRef(env, m_cPlatformView);
|
||||
if (!(*env)->IsSameObject(env, jlocal, NULL)) {
|
||||
JNFCallVoidMethod(env, jlocal, jm_deliverKeyEvent, jEvent);
|
||||
(*env)->DeleteLocalRef(env, jlocal);
|
||||
}
|
||||
if (characters != NULL) {
|
||||
(*env)->DeleteLocalRef(env, characters);
|
||||
}
|
||||
@ -475,7 +483,12 @@ static BOOL shouldUsePressAndHold() {
|
||||
JNIEnv *env = [ThreadUtilities getJNIEnv];
|
||||
static JNF_CLASS_CACHE(jc_PlatformView, "sun/lwawt/macosx/CPlatformView");
|
||||
static JNF_MEMBER_CACHE(jm_deliverResize, jc_PlatformView, "deliverResize", "(IIII)V");
|
||||
JNFCallVoidMethod(env, m_cPlatformView, jm_deliverResize, x,y,w,h);
|
||||
|
||||
jobject jlocal = (*env)->NewLocalRef(env, m_cPlatformView);
|
||||
if (!(*env)->IsSameObject(env, jlocal, NULL)) {
|
||||
JNFCallVoidMethod(env, jlocal, jm_deliverResize, x,y,w,h);
|
||||
(*env)->DeleteLocalRef(env, jlocal);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -504,7 +517,11 @@ static BOOL shouldUsePressAndHold() {
|
||||
*/
|
||||
static JNF_CLASS_CACHE(jc_CPlatformView, "sun/lwawt/macosx/CPlatformView");
|
||||
static JNF_MEMBER_CACHE(jm_deliverWindowDidExposeEvent, jc_CPlatformView, "deliverWindowDidExposeEvent", "()V");
|
||||
JNFCallVoidMethod(env, m_cPlatformView, jm_deliverWindowDidExposeEvent);
|
||||
jobject jlocal = (*env)->NewLocalRef(env, m_cPlatformView);
|
||||
if (!(*env)->IsSameObject(env, jlocal, NULL)) {
|
||||
JNFCallVoidMethod(env, jlocal, jm_deliverWindowDidExposeEvent);
|
||||
(*env)->DeleteLocalRef(env, jlocal);
|
||||
}
|
||||
/*
|
||||
}
|
||||
*/
|
||||
@ -541,7 +558,13 @@ static BOOL shouldUsePressAndHold() {
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
jobject peer = JNFGetObjectField(env, m_cPlatformView, jf_Peer);
|
||||
|
||||
jobject peer = NULL;
|
||||
jobject jlocal = (*env)->NewLocalRef(env, m_cPlatformView);
|
||||
if (!(*env)->IsSameObject(env, jlocal, NULL)) {
|
||||
peer = JNFGetObjectField(env, jlocal, jf_Peer);
|
||||
(*env)->DeleteLocalRef(env, jlocal);
|
||||
}
|
||||
static JNF_CLASS_CACHE(jc_LWWindowPeer, "sun/lwawt/LWWindowPeer");
|
||||
static JNF_MEMBER_CACHE(jf_Target, jc_LWWindowPeer, "target", "Ljava/awt/Component;");
|
||||
if (peer == NULL) {
|
||||
@ -549,12 +572,27 @@ static BOOL shouldUsePressAndHold() {
|
||||
JNFDumpJavaStack(env);
|
||||
return NULL;
|
||||
}
|
||||
return JNFGetObjectField(env, peer, jf_Target);
|
||||
jobject comp = JNFGetObjectField(env, peer, jf_Target);
|
||||
(*env)->DeleteLocalRef(env, peer);
|
||||
return comp;
|
||||
}
|
||||
|
||||
+ (AWTView *) awtView:(JNIEnv*)env ofAccessible:(jobject)jaccessible
|
||||
{
|
||||
static JNF_STATIC_MEMBER_CACHE(jm_getAWTView, sjc_CAccessibility, "getAWTView", "(Ljavax/accessibility/Accessible;)J");
|
||||
|
||||
jlong jptr = JNFCallStaticLongMethod(env, jm_getAWTView, jaccessible);
|
||||
if (jptr == 0) return nil;
|
||||
|
||||
return (AWTView *)jlong_to_ptr(jptr);
|
||||
}
|
||||
|
||||
- (id)getAxData:(JNIEnv*)env
|
||||
{
|
||||
return [[[JavaComponentAccessibility alloc] initWithParent:self withEnv:env withAccessible:[self awtComponent:env] withIndex:-1 withView:self withJavaRole:nil] autorelease];
|
||||
jobject jcomponent = [self awtComponent:env];
|
||||
id ax = [[[JavaComponentAccessibility alloc] initWithParent:self withEnv:env withAccessible:jcomponent withIndex:-1 withView:self withJavaRole:nil] autorelease];
|
||||
(*env)->DeleteLocalRef(env, jcomponent);
|
||||
return ax;
|
||||
}
|
||||
|
||||
- (NSArray *)accessibilityAttributeNames
|
||||
@ -1299,7 +1337,7 @@ Java_sun_lwawt_macosx_CPlatformView_nativeCreateView
|
||||
JNF_COCOA_ENTER(env);
|
||||
|
||||
NSRect rect = NSMakeRect(originX, originY, width, height);
|
||||
jobject cPlatformView = (*env)->NewGlobalRef(env, obj);
|
||||
jobject cPlatformView = (*env)->NewWeakGlobalRef(env, obj);
|
||||
|
||||
[ThreadUtilities performOnMainThreadWaiting:YES block:^(){
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -35,9 +35,9 @@
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
fAccessibleAction = JNFNewGlobalRef(env, accessibleAction);
|
||||
fAccessibleAction = JNFNewWeakGlobalRef(env, accessibleAction);
|
||||
fIndex = index;
|
||||
fComponent = JNFNewGlobalRef(env, component);
|
||||
fComponent = JNFNewWeakGlobalRef(env, component);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@ -46,10 +46,10 @@
|
||||
{
|
||||
JNIEnv *env = [ThreadUtilities getJNIEnvUncached];
|
||||
|
||||
JNFDeleteGlobalRef(env, fAccessibleAction);
|
||||
JNFDeleteWeakGlobalRef(env, fAccessibleAction);
|
||||
fAccessibleAction = NULL;
|
||||
|
||||
JNFDeleteGlobalRef(env, fComponent);
|
||||
JNFDeleteWeakGlobalRef(env, fComponent);
|
||||
fComponent = NULL;
|
||||
|
||||
[super dealloc];
|
||||
@ -61,7 +61,18 @@
|
||||
|
||||
JNIEnv* env = [ThreadUtilities getJNIEnv];
|
||||
|
||||
return JNFJavaToNSString(env, JNFCallStaticObjectMethod(env, jm_getAccessibleActionDescription, fAccessibleAction, fIndex, fComponent)); // AWT_THREADING Safe (AWTRunLoopMode)
|
||||
jobject fCompLocal = (*env)->NewLocalRef(env, fComponent);
|
||||
if ((*env)->IsSameObject(env, fCompLocal, NULL)) {
|
||||
return @"unknown";
|
||||
}
|
||||
NSString *str = nil;
|
||||
jobject jstr = JNFCallStaticObjectMethod(env, jm_getAccessibleActionDescription, fAccessibleAction, fIndex, fCompLocal);
|
||||
if (jstr != NULL) {
|
||||
NSString *str = JNFJavaToNSString(env, jstr); // AWT_THREADING Safe (AWTRunLoopMode)
|
||||
(*env)->DeleteLocalRef(env, jstr);
|
||||
}
|
||||
(*env)->DeleteLocalRef(env, fCompLocal);
|
||||
return str == nil ? @"unknown" : str;
|
||||
}
|
||||
|
||||
- (void)perform
|
||||
@ -82,9 +93,9 @@
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
fTabGroup = JNFNewGlobalRef(env, tabGroup);
|
||||
fTabGroup = JNFNewWeakGlobalRef(env, tabGroup);
|
||||
fIndex = index;
|
||||
fComponent = JNFNewGlobalRef(env, component);
|
||||
fComponent = JNFNewWeakGlobalRef(env, component);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@ -93,10 +104,10 @@
|
||||
{
|
||||
JNIEnv *env = [ThreadUtilities getJNIEnvUncached];
|
||||
|
||||
JNFDeleteGlobalRef(env, fTabGroup);
|
||||
JNFDeleteWeakGlobalRef(env, fTabGroup);
|
||||
fTabGroup = NULL;
|
||||
|
||||
JNFDeleteGlobalRef(env, fComponent);
|
||||
JNFDeleteWeakGlobalRef(env, fComponent);
|
||||
fComponent = NULL;
|
||||
|
||||
[super dealloc];
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -77,7 +77,9 @@ NSString *getJavaRole(JNIEnv *env, jobject axComponent, jobject component)
|
||||
jobject axRole = JNFCallStaticObjectMethod(env, sjm_getAccessibleRole, axComponent, component); // AWT_THREADING Safe (AWTRunLoopMode)
|
||||
if (axRole == NULL) return @"unknown";
|
||||
|
||||
return JNFJavaToNSString(env, axRole);
|
||||
NSString* str = JNFJavaToNSString(env, axRole);
|
||||
(*env)->DeleteLocalRef(env, axRole);
|
||||
return str;
|
||||
}
|
||||
|
||||
jobject getAxSelection(JNIEnv *env, jobject axContext, jobject component)
|
||||
@ -126,21 +128,27 @@ BOOL isVertical(JNIEnv *env, jobject axContext, jobject component)
|
||||
{
|
||||
static JNF_STATIC_MEMBER_CACHE(jm_VERTICAL, sjc_AccessibleState, "VERTICAL", "Ljavax/accessibility/AccessibleState;");
|
||||
jobject axVertState = JNFGetStaticObjectField(env, jm_VERTICAL);
|
||||
return containsAxState(env, axContext, axVertState, component);
|
||||
BOOL vertical = containsAxState(env, axContext, axVertState, component);
|
||||
(*env)->DeleteLocalRef(env, axVertState);
|
||||
return vertical;
|
||||
}
|
||||
|
||||
BOOL isHorizontal(JNIEnv *env, jobject axContext, jobject component)
|
||||
{
|
||||
static JNF_STATIC_MEMBER_CACHE(jm_HORIZONTAL, sjc_AccessibleState, "HORIZONTAL", "Ljavax/accessibility/AccessibleState;");
|
||||
jobject axHorizState = JNFGetStaticObjectField(env, jm_HORIZONTAL);
|
||||
return containsAxState(env, axContext, axHorizState, component);
|
||||
BOOL horizontal = containsAxState(env, axContext, axHorizState, component);
|
||||
(*env)->DeleteLocalRef(env, axHorizState);
|
||||
return horizontal;
|
||||
}
|
||||
|
||||
BOOL isShowing(JNIEnv *env, jobject axContext, jobject component)
|
||||
{
|
||||
static JNF_STATIC_MEMBER_CACHE(jm_SHOWING, sjc_AccessibleState, "SHOWING", "Ljavax/accessibility/AccessibleState;");
|
||||
jobject axVisibleState = JNFGetStaticObjectField(env, jm_SHOWING);
|
||||
return containsAxState(env, axContext, axVisibleState, component);
|
||||
BOOL showing = containsAxState(env, axContext, axVisibleState, component);
|
||||
(*env)->DeleteLocalRef(env, axVisibleState);
|
||||
return showing;
|
||||
}
|
||||
|
||||
NSPoint getAxComponentLocationOnScreen(JNIEnv *env, jobject axComponent, jobject component)
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -75,7 +75,6 @@ static jobject sAccessibilityClass = NULL;
|
||||
static NSMutableDictionary *sAttributeNamesForRoleCache = nil;
|
||||
static NSObject *sAttributeNamesLOCK = nil;
|
||||
|
||||
|
||||
@interface TabGroupAccessibility : JavaComponentAccessibility {
|
||||
NSInteger _numTabs;
|
||||
}
|
||||
@ -137,8 +136,11 @@ static NSObject *sAttributeNamesLOCK = nil;
|
||||
fView = [view retain];
|
||||
fJavaRole = [javaRole retain];
|
||||
|
||||
fAccessible = JNFNewGlobalRef(env, accessible);
|
||||
fComponent = JNFNewGlobalRef(env, [(AWTView *)fView awtComponent:env]);
|
||||
fAccessible = (*env)->NewWeakGlobalRef(env, accessible);
|
||||
|
||||
jobject jcomponent = [(AWTView *)fView awtComponent:env];
|
||||
fComponent = (*env)->NewWeakGlobalRef(env, jcomponent);
|
||||
(*env)->DeleteLocalRef(env, jcomponent);
|
||||
|
||||
fIndex = index;
|
||||
|
||||
@ -166,10 +168,10 @@ static NSObject *sAttributeNamesLOCK = nil;
|
||||
|
||||
JNIEnv *env = [ThreadUtilities getJNIEnvUncached];
|
||||
|
||||
JNFDeleteGlobalRef(env, fAccessible);
|
||||
(*env)->DeleteWeakGlobalRef(env, fAccessible);
|
||||
fAccessible = NULL;
|
||||
|
||||
JNFDeleteGlobalRef(env, fComponent);
|
||||
(*env)->DeleteWeakGlobalRef(env, fComponent);
|
||||
fComponent = NULL;
|
||||
|
||||
[fParent release];
|
||||
@ -279,7 +281,7 @@ static NSObject *sAttributeNamesLOCK = nil;
|
||||
|
||||
+ (NSArray *)childrenOfParent:(JavaComponentAccessibility *)parent withEnv:(JNIEnv *)env withChildrenCode:(NSInteger)whichChildren allowIgnored:(BOOL)allowIgnored
|
||||
{
|
||||
jobjectArray jchildrenAndRoles = JNFCallStaticObjectMethod(env, jm_getChildrenAndRoles, parent->fAccessible, parent->fComponent, whichChildren, allowIgnored); // AWT_THREADING Safe (AWTRunLoop)
|
||||
jobjectArray jchildrenAndRoles = (jobjectArray)JNFCallStaticObjectMethod(env, jm_getChildrenAndRoles, parent->fAccessible, parent->fComponent, whichChildren, allowIgnored); // AWT_THREADING Safe (AWTRunLoop)
|
||||
if (jchildrenAndRoles == NULL) return nil;
|
||||
|
||||
jsize arrayLen = (*env)->GetArrayLength(env, jchildrenAndRoles);
|
||||
@ -294,14 +296,21 @@ static NSObject *sAttributeNamesLOCK = nil;
|
||||
|
||||
NSString *childJavaRole = nil;
|
||||
if (jchildJavaRole != NULL) {
|
||||
childJavaRole = JNFJavaToNSString(env, JNFGetObjectField(env, jchildJavaRole, sjf_key));
|
||||
jobject jkey = JNFGetObjectField(env, jchildJavaRole, sjf_key);
|
||||
childJavaRole = JNFJavaToNSString(env, jkey);
|
||||
(*env)->DeleteLocalRef(env, jkey);
|
||||
}
|
||||
|
||||
JavaComponentAccessibility *child = [self createWithParent:parent accessible:jchild role:childJavaRole index:childIndex withEnv:env withView:parent->fView];
|
||||
|
||||
(*env)->DeleteLocalRef(env, jchild);
|
||||
(*env)->DeleteLocalRef(env, jchildJavaRole);
|
||||
|
||||
[children addObject:child];
|
||||
childIndex++;
|
||||
}
|
||||
|
||||
(*env)->DeleteLocalRef(env, jchildrenAndRoles);
|
||||
|
||||
return children;
|
||||
}
|
||||
|
||||
@ -310,7 +319,7 @@ static NSObject *sAttributeNamesLOCK = nil;
|
||||
jobject jcomponent = [(AWTView *)view awtComponent:env];
|
||||
jint index = JNFCallStaticIntMethod(env, sjm_getAccessibleIndexInParent, jaccessible, jcomponent);
|
||||
NSString *javaRole = getJavaRole(env, jaccessible, jcomponent);
|
||||
|
||||
(*env)->DeleteLocalRef(env, jcomponent);
|
||||
return [self createWithAccessible:jaccessible role:javaRole index:index withEnv:env withView:view];
|
||||
}
|
||||
|
||||
@ -325,7 +334,10 @@ static NSObject *sAttributeNamesLOCK = nil;
|
||||
jobject jCAX = [JavaComponentAccessibility getCAccessible:jaccessible withEnv:env];
|
||||
if (jCAX == NULL) return nil;
|
||||
JavaComponentAccessibility *value = (JavaComponentAccessibility *) jlong_to_ptr(JNFGetLongField(env, jCAX, jf_ptr));
|
||||
if (value != nil) return [[value retain] autorelease];
|
||||
if (value != nil) {
|
||||
(*env)->DeleteLocalRef(env, jCAX);
|
||||
return [[value retain] autorelease];
|
||||
}
|
||||
|
||||
// otherwise, create a new instance
|
||||
JavaComponentAccessibility *newChild = nil;
|
||||
@ -348,6 +360,7 @@ static NSObject *sAttributeNamesLOCK = nil;
|
||||
// must hard retain pointer poked into Java object
|
||||
[newChild retain];
|
||||
JNFSetLongField(env, jCAX, jf_ptr, ptr_to_jlong(newChild));
|
||||
(*env)->DeleteLocalRef(env, jCAX);
|
||||
|
||||
// return autoreleased instance
|
||||
return [newChild autorelease];
|
||||
@ -380,7 +393,7 @@ static NSObject *sAttributeNamesLOCK = nil;
|
||||
|
||||
// Get all the other accessibility attributes states we need in one swell foop.
|
||||
// javaRole isn't pulled in because we need protected access to AccessibleRole.key
|
||||
jbooleanArray attributeStates = JNFCallStaticObjectMethod(env, jm_getInitialAttributeStates, fAccessible, fComponent); // AWT_THREADING Safe (AWTRunLoop)
|
||||
jbooleanArray attributeStates = (jbooleanArray)JNFCallStaticObjectMethod(env, jm_getInitialAttributeStates, fAccessible, fComponent); // AWT_THREADING Safe (AWTRunLoop)
|
||||
if (attributeStates == NULL) return nil;
|
||||
jboolean *attributeStatesArray = (*env)->GetBooleanArrayElements(env, attributeStates, 0);
|
||||
if (attributeStatesArray == NULL) {
|
||||
@ -475,6 +488,7 @@ static NSObject *sAttributeNamesLOCK = nil;
|
||||
JavaAxAction *action = [[JavaAxAction alloc] initWithEnv:env withAccessibleAction:axAction withIndex:0 withComponent:fComponent];
|
||||
[fActions setObject:action forKey:[self isMenu] ? NSAccessibilityPickAction : NSAccessibilityPressAction];
|
||||
[action release];
|
||||
(*env)->DeleteLocalRef(env, axAction);
|
||||
}
|
||||
}
|
||||
|
||||
@ -485,7 +499,9 @@ static NSObject *sAttributeNamesLOCK = nil;
|
||||
|
||||
- (id)parent
|
||||
{
|
||||
static JNF_CLASS_CACHE(sjc_Window, "java/awt/Window");
|
||||
static JNF_STATIC_MEMBER_CACHE(sjm_getAccessibleParent, sjc_CAccessibility, "getAccessibleParent", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Ljavax/accessibility/Accessible;");
|
||||
static JNF_STATIC_MEMBER_CACHE(sjm_getSwingAccessible, sjc_CAccessible, "getSwingAccessible", "(Ljavax/accessibility/Accessible;)Ljavax/accessibility/Accessible;");
|
||||
|
||||
if(fParent == nil) {
|
||||
JNIEnv* env = [ThreadUtilities getJNIEnv];
|
||||
@ -495,10 +511,21 @@ static NSObject *sAttributeNamesLOCK = nil;
|
||||
if (jparent == NULL) {
|
||||
fParent = fView;
|
||||
} else {
|
||||
fParent = [JavaComponentAccessibility createWithAccessible:jparent withEnv:env withView:fView];
|
||||
AWTView *view = fView;
|
||||
jobject jax = JNFCallStaticObjectMethod(env, sjm_getSwingAccessible, fAccessible);
|
||||
|
||||
if (JNFIsInstanceOf(env, jax, &sjc_Window)) {
|
||||
// In this case jparent is an owner toplevel and we should retrieve its own view
|
||||
view = [AWTView awtView:env ofAccessible:jparent];
|
||||
}
|
||||
if (view != nil) {
|
||||
fParent = [JavaComponentAccessibility createWithAccessible:jparent withEnv:env withView:view];
|
||||
}
|
||||
if (fParent == nil) {
|
||||
fParent = fView;
|
||||
}
|
||||
(*env)->DeleteLocalRef(env, jparent);
|
||||
(*env)->DeleteLocalRef(env, jax );
|
||||
}
|
||||
[fParent retain];
|
||||
}
|
||||
@ -546,7 +573,10 @@ static NSObject *sAttributeNamesLOCK = nil;
|
||||
return NO;
|
||||
}
|
||||
|
||||
return isShowing(env, [self axContextWithEnv:env], fComponent);
|
||||
jobject axContext = [self axContextWithEnv:env];
|
||||
BOOL showing = isShowing(env, axContext, fComponent);
|
||||
(*env)->DeleteLocalRef(env, axContext);
|
||||
return showing;
|
||||
}
|
||||
|
||||
// the array of names for each role is cached in the sAttributeNamesForRoleCache
|
||||
@ -723,7 +753,12 @@ static NSObject *sAttributeNamesLOCK = nil;
|
||||
JNIEnv* env = [ThreadUtilities getJNIEnv];
|
||||
|
||||
jobject val = JNFCallStaticObjectMethod(env, sjm_getAccessibleDescription, fAccessible, fComponent); // AWT_THREADING Safe (AWTRunLoop)
|
||||
return JNFJavaToNSString(env, val);
|
||||
if (val == NULL) {
|
||||
return @"unknown";
|
||||
}
|
||||
NSString* str = JNFJavaToNSString(env, val);
|
||||
(*env)->DeleteLocalRef(env, val);
|
||||
return str;
|
||||
}
|
||||
|
||||
- (BOOL)accessibilityIsHelpAttributeSettable
|
||||
@ -739,7 +774,12 @@ static NSObject *sAttributeNamesLOCK = nil;
|
||||
JNIEnv* env = [ThreadUtilities getJNIEnv];
|
||||
|
||||
jobject axValue = JNFCallStaticObjectMethod(env, jm_getMaximumAccessibleValue, fAccessible, fComponent); // AWT_THREADING Safe (AWTRunLoop)
|
||||
return JNFJavaToNSNumber(env, axValue);
|
||||
if (axValue == NULL) {
|
||||
return [NSNumber numberWithInt:0];
|
||||
}
|
||||
NSNumber* num = JNFJavaToNSNumber(env, axValue);
|
||||
(*env)->DeleteLocalRef(env, axValue);
|
||||
return num;
|
||||
}
|
||||
|
||||
- (BOOL)accessibilityIsMaxValueAttributeSettable
|
||||
@ -755,7 +795,12 @@ static NSObject *sAttributeNamesLOCK = nil;
|
||||
JNIEnv* env = [ThreadUtilities getJNIEnv];
|
||||
|
||||
jobject axValue = JNFCallStaticObjectMethod(env, jm_getMinimumAccessibleValue, fAccessible, fComponent); // AWT_THREADING Safe (AWTRunLoop)
|
||||
return JNFJavaToNSNumber(env, axValue);
|
||||
if (axValue == NULL) {
|
||||
return [NSNumber numberWithInt:0];
|
||||
}
|
||||
NSNumber* num = JNFJavaToNSNumber(env, axValue);
|
||||
(*env)->DeleteLocalRef(env, axValue);
|
||||
return num;
|
||||
}
|
||||
|
||||
- (BOOL)accessibilityIsMinValueAttributeSettable
|
||||
@ -770,13 +815,16 @@ static NSObject *sAttributeNamesLOCK = nil;
|
||||
|
||||
// cmcnote - should batch these two calls into one that returns an array of two bools, one for vertical and one for horiz
|
||||
if (isVertical(env, axContext, fComponent)) {
|
||||
(*env)->DeleteLocalRef(env, axContext);
|
||||
return NSAccessibilityVerticalOrientationValue;
|
||||
}
|
||||
|
||||
if (isHorizontal(env, axContext, fComponent)) {
|
||||
(*env)->DeleteLocalRef(env, axContext);
|
||||
return NSAccessibilityHorizontalOrientationValue;
|
||||
}
|
||||
|
||||
(*env)->DeleteLocalRef(env, axContext);
|
||||
return nil;
|
||||
}
|
||||
|
||||
@ -808,6 +856,7 @@ static NSObject *sAttributeNamesLOCK = nil;
|
||||
// Get the java screen coords, and make a NSPoint of the bottom left of the AxComponent.
|
||||
NSSize size = getAxComponentSize(env, axComponent, fComponent);
|
||||
NSPoint point = getAxComponentLocationOnScreen(env, axComponent, fComponent);
|
||||
(*env)->DeleteLocalRef(env, axComponent);
|
||||
|
||||
point.y += size.height;
|
||||
|
||||
@ -857,8 +906,9 @@ static NSObject *sAttributeNamesLOCK = nil;
|
||||
JNIEnv* env = [ThreadUtilities getJNIEnv];
|
||||
|
||||
jobject axRole = JNFCallStaticObjectMethod(env, jm_getAccessibleRoleDisplayString, fAccessible, fComponent);
|
||||
if(axRole != NULL) {
|
||||
if (axRole != NULL) {
|
||||
value = JNFJavaToNSString(env, axRole);
|
||||
(*env)->DeleteLocalRef(env, axRole);
|
||||
} else {
|
||||
value = @"unknown";
|
||||
}
|
||||
@ -893,7 +943,9 @@ static NSObject *sAttributeNamesLOCK = nil;
|
||||
- (NSValue *)accessibilitySizeAttribute {
|
||||
JNIEnv* env = [ThreadUtilities getJNIEnv];
|
||||
jobject axComponent = JNFCallStaticObjectMethod(env, sjm_getAccessibleComponent, fAccessible, fComponent); // AWT_THREADING Safe (AWTRunLoop)
|
||||
return [NSValue valueWithSize:getAxComponentSize(env, axComponent, fComponent)];
|
||||
NSValue* size = [NSValue valueWithSize:getAxComponentSize(env, axComponent, fComponent)];
|
||||
(*env)->DeleteLocalRef(env, axComponent);
|
||||
return size;
|
||||
}
|
||||
|
||||
- (BOOL)accessibilityIsSizeAttributeSettable
|
||||
@ -952,7 +1004,12 @@ static NSObject *sAttributeNamesLOCK = nil;
|
||||
JNIEnv* env = [ThreadUtilities getJNIEnv];
|
||||
|
||||
jobject val = JNFCallStaticObjectMethod(env, sjm_getAccessibleName, fAccessible, fComponent); // AWT_THREADING Safe (AWTRunLoop)
|
||||
return JNFJavaToNSString(env, val);
|
||||
if (val == NULL) {
|
||||
return @"unknown";
|
||||
}
|
||||
NSString* str = JNFJavaToNSString(env, val);
|
||||
(*env)->DeleteLocalRef(env, val);
|
||||
return str;
|
||||
}
|
||||
|
||||
- (BOOL)accessibilityIsTitleAttributeSettable
|
||||
@ -984,8 +1041,20 @@ static NSObject *sAttributeNamesLOCK = nil;
|
||||
// a text value is taken care of in JavaTextAccessibility
|
||||
|
||||
// cmcnote should coalesce these calls into one java call
|
||||
NSNumber *num = nil;
|
||||
jobject axValue = JNFCallStaticObjectMethod(env, sjm_getAccessibleValue, fAccessible, fComponent); // AWT_THREADING Safe (AWTRunLoop)
|
||||
return JNFJavaToNSNumber(env, JNFCallStaticObjectMethod(env, jm_getCurrentAccessibleValue, axValue, fComponent)); // AWT_THREADING Safe (AWTRunLoop)
|
||||
if (axValue != NULL) {
|
||||
jobject str = JNFCallStaticObjectMethod(env, jm_getCurrentAccessibleValue, axValue, fComponent);
|
||||
if (str != NULL) {
|
||||
num = JNFJavaToNSNumber(env, str); // AWT_THREADING Safe (AWTRunLoop)
|
||||
(*env)->DeleteLocalRef(env, str);
|
||||
}
|
||||
(*env)->DeleteLocalRef(env, axValue);
|
||||
}
|
||||
if (num == nil) {
|
||||
num = [NSNumber numberWithInt:0];
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
- (BOOL)accessibilityIsValueAttributeSettable
|
||||
@ -1084,7 +1153,10 @@ static NSObject *sAttributeNamesLOCK = nil;
|
||||
id value = nil;
|
||||
if (JNFIsInstanceOf(env, jparent, &jc_Container)) {
|
||||
jobject jaccessible = JNFCallStaticObjectMethod(env, jm_accessibilityHitTest, jparent, (jfloat)point.x, (jfloat)point.y); // AWT_THREADING Safe (AWTRunLoop)
|
||||
value = [JavaComponentAccessibility createWithAccessible:jaccessible withEnv:env withView:fView];
|
||||
if (jaccessible != NULL) {
|
||||
value = [JavaComponentAccessibility createWithAccessible:jaccessible withEnv:env withView:fView];
|
||||
(*env)->DeleteLocalRef(env, jaccessible);
|
||||
}
|
||||
}
|
||||
|
||||
if (value == nil) {
|
||||
@ -1116,6 +1188,7 @@ static NSObject *sAttributeNamesLOCK = nil;
|
||||
if (JNFIsInstanceOf(env, focused, &sjc_Accessible)) {
|
||||
value = [JavaComponentAccessibility createWithAccessible:focused withEnv:env withView:fView];
|
||||
}
|
||||
(*env)->DeleteLocalRef(env, focused);
|
||||
}
|
||||
|
||||
if (value == nil) {
|
||||
@ -1222,38 +1295,46 @@ JNF_COCOA_EXIT(env);
|
||||
for (i = 0; i < _numTabs; i++) {
|
||||
aTab = (JavaComponentAccessibility *)[tabs objectAtIndex:i];
|
||||
if ([aTab isAccessibleWithEnv:env forAccessible:selAccessible]) {
|
||||
(*env)->DeleteLocalRef(env, selAccessible);
|
||||
return aTab;
|
||||
}
|
||||
}
|
||||
|
||||
(*env)->DeleteLocalRef(env, selAccessible);
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSArray *)tabControlsWithEnv:(JNIEnv *)env withTabGroupAxContext:(jobject)axContext withTabCode:(NSInteger)whichTabs allowIgnored:(BOOL)allowIgnored
|
||||
{
|
||||
jobjectArray jtabsAndRoles = JNFCallStaticObjectMethod(env, jm_getChildrenAndRoles, fAccessible, fComponent, whichTabs, allowIgnored); // AWT_THREADING Safe (AWTRunLoop)
|
||||
jobjectArray jtabsAndRoles = (jobjectArray)JNFCallStaticObjectMethod(env, jm_getChildrenAndRoles, fAccessible, fComponent, whichTabs, allowIgnored); // AWT_THREADING Safe (AWTRunLoop)
|
||||
if(jtabsAndRoles == NULL) return nil;
|
||||
|
||||
jsize arrayLen = (*env)->GetArrayLength(env, jtabsAndRoles);
|
||||
if (arrayLen == 0) return nil;
|
||||
|
||||
if (arrayLen == 0) {
|
||||
(*env)->DeleteLocalRef(env, jtabsAndRoles);
|
||||
return nil;
|
||||
}
|
||||
NSMutableArray *tabs = [NSMutableArray arrayWithCapacity:(arrayLen/2)];
|
||||
|
||||
// all of the tabs have the same role, so we can just find out what that is here and use it for all the tabs
|
||||
jobject jtabJavaRole = (*env)->GetObjectArrayElement(env, jtabsAndRoles, 1); // the array entries alternate between tab/role, starting with tab. so the first role is entry 1.
|
||||
if (jtabJavaRole == NULL) return nil;
|
||||
|
||||
NSString *tabJavaRole = JNFJavaToNSString(env, JNFGetObjectField(env, jtabJavaRole, sjf_key));
|
||||
if (jtabJavaRole == NULL) {
|
||||
(*env)->DeleteLocalRef(env, jtabsAndRoles);
|
||||
return nil;
|
||||
}
|
||||
jobject jkey = JNFGetObjectField(env, jtabJavaRole, sjf_key);
|
||||
NSString *tabJavaRole = JNFJavaToNSString(env, jkey);
|
||||
(*env)->DeleteLocalRef(env, jkey);
|
||||
|
||||
NSInteger i;
|
||||
NSUInteger tabIndex = (whichTabs >= 0) ? whichTabs : 0; // if we're getting one particular child, make sure to set its index correctly
|
||||
for(i = 0; i < arrayLen; i+=2) {
|
||||
jobject jtab = (*env)->GetObjectArrayElement(env, jtabsAndRoles, i);
|
||||
JavaComponentAccessibility *tab = [[[TabGroupControlAccessibility alloc] initWithParent:self withEnv:env withAccessible:jtab withIndex:tabIndex withTabGroup:axContext withView:[self view] withJavaRole:tabJavaRole] autorelease];
|
||||
(*env)->DeleteLocalRef(env, jtab);
|
||||
[tabs addObject:tab];
|
||||
tabIndex++;
|
||||
}
|
||||
|
||||
(*env)->DeleteLocalRef(env, jtabsAndRoles);
|
||||
return tabs;
|
||||
}
|
||||
|
||||
@ -1272,7 +1353,9 @@ JNF_COCOA_EXIT(env);
|
||||
{
|
||||
JNIEnv *env = [ThreadUtilities getJNIEnv];
|
||||
jobject axContext = [self axContextWithEnv:env];
|
||||
return [self tabControlsWithEnv:env withTabGroupAxContext:axContext withTabCode:JAVA_AX_ALL_CHILDREN allowIgnored:NO];
|
||||
id tabs = [self tabControlsWithEnv:env withTabGroupAxContext:axContext withTabCode:JAVA_AX_ALL_CHILDREN allowIgnored:NO];
|
||||
(*env)->DeleteLocalRef(env, axContext);
|
||||
return tabs;
|
||||
}
|
||||
|
||||
- (BOOL)accessibilityIsTabsAttributeSettable
|
||||
@ -1292,7 +1375,9 @@ JNF_COCOA_EXIT(env);
|
||||
{
|
||||
JNIEnv *env = [ThreadUtilities getJNIEnv];
|
||||
jobject axContext = [self axContextWithEnv:env];
|
||||
return [self contentsWithEnv:env withTabGroupAxContext:axContext withTabCode:JAVA_AX_ALL_CHILDREN allowIgnored:NO];
|
||||
NSArray* cont = [self contentsWithEnv:env withTabGroupAxContext:axContext withTabCode:JAVA_AX_ALL_CHILDREN allowIgnored:NO];
|
||||
(*env)->DeleteLocalRef(env, axContext);
|
||||
return cont;
|
||||
}
|
||||
|
||||
- (BOOL)accessibilityIsContentsAttributeSettable
|
||||
@ -1305,7 +1390,9 @@ JNF_COCOA_EXIT(env);
|
||||
{
|
||||
JNIEnv *env = [ThreadUtilities getJNIEnv];
|
||||
jobject axContext = [self axContextWithEnv:env];
|
||||
return [self currentTabWithEnv:env withAxContext:axContext];
|
||||
id val = [self currentTabWithEnv:env withAxContext:axContext];
|
||||
(*env)->DeleteLocalRef(env, axContext);
|
||||
return val;
|
||||
}
|
||||
|
||||
- (BOOL)accessibilityIsValueAttributeSettable
|
||||
@ -1322,6 +1409,7 @@ JNF_COCOA_EXIT(env);
|
||||
JNIEnv *env = [ThreadUtilities getJNIEnv];
|
||||
jobject axContext = [self axContextWithEnv:env];
|
||||
setAxContextSelection(env, axContext, fIndex, fComponent);
|
||||
(*env)->DeleteLocalRef(env, axContext);
|
||||
}
|
||||
|
||||
- (NSArray *)accessibilityChildrenAttribute
|
||||
@ -1357,6 +1445,7 @@ JNF_COCOA_EXIT(env);
|
||||
result = children;
|
||||
}
|
||||
}
|
||||
(*env)->DeleteLocalRef(env, axContext);
|
||||
} else {
|
||||
result = [super accessibilityArrayAttributeValues:attribute index:index maxCount:maxCount];
|
||||
}
|
||||
@ -1375,7 +1464,7 @@ static BOOL ObjectEquals(JNIEnv *env, jobject a, jobject b, jobject component);
|
||||
self = [super initWithParent:parent withEnv:env withAccessible:accessible withIndex:index withView:view withJavaRole:javaRole];
|
||||
if (self) {
|
||||
if (tabGroup != NULL) {
|
||||
fTabGroupAxContext = JNFNewGlobalRef(env, tabGroup);
|
||||
fTabGroupAxContext = JNFNewWeakGlobalRef(env, tabGroup);
|
||||
} else {
|
||||
fTabGroupAxContext = NULL;
|
||||
}
|
||||
@ -1388,7 +1477,7 @@ static BOOL ObjectEquals(JNIEnv *env, jobject a, jobject b, jobject component);
|
||||
JNIEnv *env = [ThreadUtilities getJNIEnvUncached];
|
||||
|
||||
if (fTabGroupAxContext != NULL) {
|
||||
JNFDeleteGlobalRef(env, fTabGroupAxContext);
|
||||
JNFDeleteWeakGlobalRef(env, fTabGroupAxContext);
|
||||
fTabGroupAxContext = NULL;
|
||||
}
|
||||
|
||||
@ -1399,9 +1488,14 @@ static BOOL ObjectEquals(JNIEnv *env, jobject a, jobject b, jobject component);
|
||||
{
|
||||
JNIEnv *env = [ThreadUtilities getJNIEnv];
|
||||
jobject axContext = [self axContextWithEnv:env];
|
||||
jobject selAccessible = getAxContextSelection(env, [self tabGroup], fIndex, fComponent);
|
||||
|
||||
// Returns the current selection of the page tab list
|
||||
return [NSNumber numberWithBool:ObjectEquals(env, axContext, getAxContextSelection(env, [self tabGroup], fIndex, fComponent), fComponent)];
|
||||
id val = [NSNumber numberWithBool:ObjectEquals(env, axContext, selAccessible, fComponent)];
|
||||
|
||||
(*env)->DeleteLocalRef(env, selAccessible);
|
||||
(*env)->DeleteLocalRef(env, axContext);
|
||||
return val;
|
||||
}
|
||||
|
||||
- (void)getActionsWithEnv:(JNIEnv *)env
|
||||
@ -1416,7 +1510,8 @@ static BOOL ObjectEquals(JNIEnv *env, jobject a, jobject b, jobject component);
|
||||
if (fTabGroupAxContext == NULL) {
|
||||
JNIEnv* env = [ThreadUtilities getJNIEnv];
|
||||
jobject tabGroupAxContext = [(JavaComponentAccessibility *)[self parent] axContextWithEnv:env];
|
||||
fTabGroupAxContext = JNFNewGlobalRef(env, tabGroupAxContext);
|
||||
fTabGroupAxContext = JNFNewWeakGlobalRef(env, tabGroupAxContext);
|
||||
(*env)->DeleteLocalRef(env, tabGroupAxContext);
|
||||
}
|
||||
return fTabGroupAxContext;
|
||||
}
|
||||
@ -1451,8 +1546,10 @@ static BOOL ObjectEquals(JNIEnv *env, jobject a, jobject b, jobject component);
|
||||
if ([[aElement accessibilityRoleAttribute] isEqualToString:NSAccessibilityScrollBarRole]) {
|
||||
jobject elementAxContext = [aElement axContextWithEnv:env];
|
||||
if (isHorizontal(env, elementAxContext, fComponent)) {
|
||||
(*env)->DeleteLocalRef(env, elementAxContext);
|
||||
return aElement;
|
||||
}
|
||||
(*env)->DeleteLocalRef(env, elementAxContext);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1478,8 +1575,10 @@ static BOOL ObjectEquals(JNIEnv *env, jobject a, jobject b, jobject component);
|
||||
if ([[aElement accessibilityRoleAttribute] isEqualToString:NSAccessibilityScrollBarRole]) {
|
||||
jobject elementAxContext = [aElement axContextWithEnv:env];
|
||||
if (isVertical(env, elementAxContext, fComponent)) {
|
||||
(*env)->DeleteLocalRef(env, elementAxContext);
|
||||
return aElement;
|
||||
}
|
||||
(*env)->DeleteLocalRef(env, elementAxContext);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -112,7 +112,9 @@ NSValue *javaIntArrayToNSRangeValue(JNIEnv* env, jintArray array) {
|
||||
// if it's static text, the AppKit AXValue is the java accessibleName
|
||||
jobject axName = JNFCallStaticObjectMethod(env, sjm_getAccessibleName, fAccessible, fComponent); // AWT_THREADING Safe (AWTRunLoop)
|
||||
if (axName != NULL) {
|
||||
return JNFJavaToNSString(env, axName);
|
||||
NSString* str = JNFJavaToNSString(env, axName);
|
||||
(*env)->DeleteLocalRef(env, axName);
|
||||
return str;
|
||||
}
|
||||
// value is still nil if no accessibleName for static text. Below, try to get the accessibleText.
|
||||
}
|
||||
@ -120,12 +122,18 @@ NSValue *javaIntArrayToNSRangeValue(JNIEnv* env, jintArray array) {
|
||||
// cmcnote: inefficient to make three distinct JNI calls. Coalesce. radr://3951923
|
||||
jobject axText = JNFCallStaticObjectMethod(env, sjm_getAccessibleText, fAccessible, fComponent); // AWT_THREADING Safe (AWTRunLoop)
|
||||
if (axText == NULL) return nil;
|
||||
|
||||
(*env)->DeleteLocalRef(env, axText);
|
||||
|
||||
jobject axEditableText = JNFCallStaticObjectMethod(env, sjm_getAccessibleEditableText, fAccessible, fComponent); // AWT_THREADING Safe (AWTRunLoop)
|
||||
if (axEditableText == NULL) return nil;
|
||||
|
||||
static JNF_STATIC_MEMBER_CACHE(jm_getTextRange, sjc_CAccessibleText, "getTextRange", "(Ljavax/accessibility/AccessibleEditableText;IILjava/awt/Component;)Ljava/lang/String;");
|
||||
NSString *string = JNFJavaToNSString(env, JNFCallStaticObjectMethod(env, jm_getTextRange, axEditableText, 0, getAxTextCharCount(env, axEditableText, fComponent), fComponent)); // AWT_THREADING Safe (AWTRunLoop)
|
||||
jobject jrange = JNFCallStaticObjectMethod(env, jm_getTextRange, axEditableText, 0, getAxTextCharCount(env, axEditableText, fComponent), fComponent);
|
||||
NSString *string = JNFJavaToNSString(env, jrange); // AWT_THREADING Safe (AWTRunLoop)
|
||||
|
||||
(*env)->DeleteLocalRef(env, jrange);
|
||||
(*env)->DeleteLocalRef(env, axEditableText);
|
||||
|
||||
if (string == nil) string = @"";
|
||||
return string;
|
||||
}
|
||||
@ -139,6 +147,7 @@ NSValue *javaIntArrayToNSRangeValue(JNIEnv* env, jintArray array) {
|
||||
JNIEnv* env = [ThreadUtilities getJNIEnv];
|
||||
jobject axEditableText = JNFCallStaticObjectMethod(env, sjm_getAccessibleEditableText, fAccessible, fComponent); // AWT_THREADING Safe (AWTRunLoop)
|
||||
if (axEditableText == NULL) return NO;
|
||||
(*env)->DeleteLocalRef(env, axEditableText);
|
||||
return YES;
|
||||
}
|
||||
|
||||
@ -157,7 +166,9 @@ NSValue *javaIntArrayToNSRangeValue(JNIEnv* env, jintArray array) {
|
||||
static JNF_STATIC_MEMBER_CACHE(jm_getSelectedText, sjc_CAccessibleText, "getSelectedText", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Ljava/lang/String;");
|
||||
jobject axText = JNFCallStaticObjectMethod(env, jm_getSelectedText, fAccessible, fComponent); // AWT_THREADING Safe (AWTRunLoop)
|
||||
if (axText == NULL) return @"";
|
||||
return JNFJavaToNSString(env, axText);
|
||||
NSString* str = JNFJavaToNSString(env, axText);
|
||||
(*env)->DeleteLocalRef(env, axText);
|
||||
return str;
|
||||
}
|
||||
|
||||
- (BOOL)accessibilityIsSelectedTextAttributeSettable
|
||||
@ -220,7 +231,9 @@ NSValue *javaIntArrayToNSRangeValue(JNIEnv* env, jintArray array) {
|
||||
// also, static text doesn't always have accessibleText. if axText is null, should get the charcount of the accessibleName instead
|
||||
JNIEnv *env = [ThreadUtilities getJNIEnv];
|
||||
jobject axText = JNFCallStaticObjectMethod(env, sjm_getAccessibleText, fAccessible, fComponent); // AWT_THREADING Safe (AWTRunLoop)
|
||||
return [NSNumber numberWithInt:getAxTextCharCount(env, axText, fComponent)];
|
||||
NSNumber* num = [NSNumber numberWithInt:getAxTextCharCount(env, axText, fComponent)];
|
||||
(*env)->DeleteLocalRef(env, axText);
|
||||
return num;
|
||||
}
|
||||
|
||||
- (BOOL)accessibilityIsNumberOfCharactersAttributeSettable
|
||||
@ -285,7 +298,7 @@ NSValue *javaIntArrayToNSRangeValue(JNIEnv* env, jintArray array) {
|
||||
|
||||
JNIEnv *env = [ThreadUtilities getJNIEnv];
|
||||
static JNF_STATIC_MEMBER_CACHE(jm_getBoundsForRange, sjc_CAccessibleText, "getBoundsForRange", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;II)[D");
|
||||
jdoubleArray axBounds = JNFCallStaticObjectMethod(env, jm_getBoundsForRange, fAccessible, fComponent, range.location, range.length); // AWT_THREADING Safe (AWTRunLoop)
|
||||
jdoubleArray axBounds = (jdoubleArray)JNFCallStaticObjectMethod(env, jm_getBoundsForRange, fAccessible, fComponent, range.location, range.length); // AWT_THREADING Safe (AWTRunLoop)
|
||||
if (axBounds == NULL) return nil;
|
||||
|
||||
// We cheat because we know that the array is 4 elements long (x, y, width, height)
|
||||
@ -324,7 +337,7 @@ NSValue *javaIntArrayToNSRangeValue(JNIEnv* env, jintArray array) {
|
||||
|
||||
JNIEnv *env = [ThreadUtilities getJNIEnv];
|
||||
static JNF_STATIC_MEMBER_CACHE(jm_getRangeForLine, sjc_CAccessibleText, "getRangeForLine", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;I)[I");
|
||||
jintArray axTextRange = JNFCallStaticObjectMethod(env, jm_getRangeForLine, fAccessible, fComponent, [line intValue]); // AWT_THREADING Safe (AWTRunLoop)
|
||||
jintArray axTextRange = (jintArray)JNFCallStaticObjectMethod(env, jm_getRangeForLine, fAccessible, fComponent, [line intValue]); // AWT_THREADING Safe (AWTRunLoop)
|
||||
if (axTextRange == NULL) return nil;
|
||||
|
||||
return javaIntArrayToNSRangeValue(env,axTextRange);
|
||||
@ -350,10 +363,12 @@ NSValue *javaIntArrayToNSRangeValue(JNIEnv* env, jintArray array) {
|
||||
|
||||
JNIEnv *env = [ThreadUtilities getJNIEnv];
|
||||
static JNF_STATIC_MEMBER_CACHE(jm_getStringForRange, sjc_CAccessibleText, "getStringForRange", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;II)Ljava/lang/String;");
|
||||
jstring jstringForRange = JNFCallStaticObjectMethod(env, jm_getStringForRange, fAccessible, fComponent, range.location, range.length); // AWT_THREADING Safe (AWTRunLoop)
|
||||
jstring jstringForRange = (jstring)JNFCallStaticObjectMethod(env, jm_getStringForRange, fAccessible, fComponent, range.location, range.length); // AWT_THREADING Safe (AWTRunLoop)
|
||||
|
||||
if (jstringForRange == NULL) return @"";
|
||||
return JNFJavaToNSString(env, jstringForRange);
|
||||
NSString* str = JNFJavaToNSString(env, jstringForRange);
|
||||
(*env)->DeleteLocalRef(env, jstringForRange);
|
||||
return str;
|
||||
}
|
||||
|
||||
//
|
||||
@ -406,7 +421,7 @@ NSValue *javaIntArrayToNSRangeValue(JNIEnv* env, jintArray array) {
|
||||
|
||||
JNIEnv *env = [ThreadUtilities getJNIEnv];
|
||||
static JNF_STATIC_MEMBER_CACHE(jm_getRangeForIndex, sjc_CAccessibleText, "getRangeForIndex", "(Ljavax/accessibility/Accessible;Ljava/awt/Component;I)[I");
|
||||
jintArray axTextRange = JNFCallStaticObjectMethod(env, jm_getRangeForIndex, fAccessible, fComponent, index); // AWT_THREADING Safe (AWTRunLoop)
|
||||
jintArray axTextRange = (jintArray)JNFCallStaticObjectMethod(env, jm_getRangeForIndex, fAccessible, fComponent, index); // AWT_THREADING Safe (AWTRunLoop)
|
||||
if (axTextRange == NULL) return nil;
|
||||
|
||||
return javaIntArrayToNSRangeValue(env, axTextRange);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -31,7 +31,7 @@
|
||||
@interface CGLLayer : CAOpenGLLayer
|
||||
{
|
||||
@private
|
||||
JNFJObjectWrapper *javaLayer;
|
||||
JNFWeakJObjectWrapper *javaLayer;
|
||||
|
||||
// intermediate buffer, used the RQ lock to synchronize
|
||||
GLuint textureID;
|
||||
@ -45,7 +45,7 @@
|
||||
#endif /* REMOTELAYER */
|
||||
}
|
||||
|
||||
@property (nonatomic, retain) JNFJObjectWrapper *javaLayer;
|
||||
@property (nonatomic, retain) JNFWeakJObjectWrapper *javaLayer;
|
||||
@property (readwrite, assign) GLuint textureID;
|
||||
@property (readwrite, assign) GLenum target;
|
||||
@property (readwrite, assign) float textureWidth;
|
||||
@ -57,7 +57,7 @@
|
||||
@property (nonatomic, retain) NSObject<JRSRemoteLayer> *jrsRemoteLayer;
|
||||
#endif
|
||||
|
||||
- (id) initWithJavaLayer:(JNFJObjectWrapper *)javaLayer;
|
||||
- (id) initWithJavaLayer:(JNFWeakJObjectWrapper *)javaLayer;
|
||||
- (void) blitTexture;
|
||||
@end
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -46,7 +46,7 @@ extern NSOpenGLContext *sharedContext;
|
||||
@synthesize jrsRemoteLayer;
|
||||
#endif
|
||||
|
||||
- (id) initWithJavaLayer:(JNFJObjectWrapper *)layer;
|
||||
- (id) initWithJavaLayer:(JNFWeakJObjectWrapper *)layer;
|
||||
{
|
||||
AWT_ASSERT_APPKIT_THREAD;
|
||||
// Initialize ourselves
|
||||
@ -133,6 +133,15 @@ AWT_ASSERT_APPKIT_THREAD;
|
||||
{
|
||||
AWT_ASSERT_APPKIT_THREAD;
|
||||
|
||||
JNIEnv *env = [ThreadUtilities getJNIEnv];
|
||||
static JNF_CLASS_CACHE(jc_JavaLayer, "sun/java2d/opengl/CGLLayer");
|
||||
static JNF_MEMBER_CACHE(jm_drawInCGLContext, jc_JavaLayer, "drawInCGLContext", "()V");
|
||||
|
||||
jobject javaLayerLocalRef = [self.javaLayer jObjectWithEnv:env];
|
||||
if ((*env)->IsSameObject(env, javaLayerLocalRef, NULL)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Set the current context to the one given to us.
|
||||
CGLSetCurrentContext(glContext);
|
||||
|
||||
@ -141,12 +150,7 @@ AWT_ASSERT_APPKIT_THREAD;
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
glViewport(0, 0, textureWidth, textureHeight);
|
||||
|
||||
JNIEnv *env = [ThreadUtilities getJNIEnv];
|
||||
static JNF_CLASS_CACHE(jc_JavaLayer, "sun/java2d/opengl/CGLLayer");
|
||||
static JNF_MEMBER_CACHE(jm_drawInCGLContext, jc_JavaLayer, "drawInCGLContext", "()V");
|
||||
|
||||
jobject javaLayerLocalRef = [self.javaLayer jObjectWithEnv:env];
|
||||
JNFCallVoidMethod(env, javaLayerLocalRef, jm_drawInCGLContext);
|
||||
(*env)->DeleteLocalRef(env, javaLayerLocalRef);
|
||||
|
||||
@ -171,7 +175,7 @@ Java_sun_java2d_opengl_CGLLayer_nativeCreateLayer
|
||||
|
||||
JNF_COCOA_ENTER(env);
|
||||
|
||||
JNFJObjectWrapper *javaLayer = [JNFJObjectWrapper wrapperWithJObject:obj withEnv:env];
|
||||
JNFWeakJObjectWrapper *javaLayer = [JNFWeakJObjectWrapper wrapperWithJObject:obj withEnv:env];
|
||||
|
||||
[ThreadUtilities performOnMainThreadWaiting:YES block:^(){
|
||||
AWT_ASSERT_APPKIT_THREAD;
|
||||
|
@ -231,12 +231,14 @@ static void BufImg_GetRasInfo(JNIEnv *env,
|
||||
pRasInfo->redErrTable = NULL;
|
||||
pRasInfo->grnErrTable = NULL;
|
||||
pRasInfo->bluErrTable = NULL;
|
||||
pRasInfo->representsPrimaries = 0;
|
||||
} else {
|
||||
pRasInfo->invColorTable = bipriv->cData->img_clr_tbl;
|
||||
pRasInfo->redErrTable = bipriv->cData->img_oda_red;
|
||||
pRasInfo->grnErrTable = bipriv->cData->img_oda_green;
|
||||
pRasInfo->bluErrTable = bipriv->cData->img_oda_blue;
|
||||
pRasInfo->invGrayTable = bipriv->cData->pGrayInverseLutData;
|
||||
pRasInfo->representsPrimaries = bipriv->cData->representsPrimaries;
|
||||
}
|
||||
}
|
||||
|
||||
@ -259,6 +261,59 @@ static void BufImg_Release(JNIEnv *env,
|
||||
}
|
||||
}
|
||||
|
||||
static int calculatePrimaryColorsApproximation(int* cmap, unsigned char* cube, int cube_size) {
|
||||
int i, j, k;
|
||||
int index, value, color;
|
||||
// values calculated from cmap
|
||||
int r, g, b;
|
||||
// maximum positive/negative variation allowed for r, g, b values for primary colors
|
||||
int delta = 5;
|
||||
// get the primary color cmap indices from corner of inverse color table
|
||||
for (i = 0; i < cube_size; i += (cube_size - 1)) {
|
||||
for (j = 0; j < cube_size; j += (cube_size - 1)) {
|
||||
for (k = 0; k < cube_size; k += (cube_size - 1)) {
|
||||
// calculate inverse color table index
|
||||
index = i + cube_size * (j + cube_size * k);
|
||||
// get value present in corners of inverse color table
|
||||
value = cube[index];
|
||||
// use the corner values as index for cmap
|
||||
color = cmap[value];
|
||||
// extract r,g,b values from cmap value
|
||||
r = ((color) >> 16) & 0xff;
|
||||
g = ((color) >> 8) & 0xff;
|
||||
b = color & 0xff;
|
||||
/*
|
||||
* If i/j/k value is 0 optimum value of b/g/r should be 0 but we allow
|
||||
* maximum positive variation of 5. If i/j/k value is 31 optimum value
|
||||
* of b/g/r should be 255 but we allow maximum negative variation of 5.
|
||||
*/
|
||||
if (i == 0) {
|
||||
if (b > delta)
|
||||
return 0;
|
||||
} else {
|
||||
if (b < (255 - delta))
|
||||
return 0;
|
||||
}
|
||||
if (j == 0) {
|
||||
if (g > delta)
|
||||
return 0;
|
||||
} else {
|
||||
if (g < (255 - delta))
|
||||
return 0;
|
||||
}
|
||||
if (k == 0) {
|
||||
if (r > delta)
|
||||
return 0;
|
||||
} else {
|
||||
if (r < (255 - delta))
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static ColorData *BufImg_SetupICM(JNIEnv *env,
|
||||
BufImgSDOps *bisdo)
|
||||
{
|
||||
@ -298,6 +353,7 @@ static ColorData *BufImg_SetupICM(JNIEnv *env,
|
||||
}
|
||||
|
||||
cData->img_clr_tbl = initCubemap(pRgb, bisdo->lutsize, 32);
|
||||
cData->representsPrimaries = calculatePrimaryColorsApproximation(pRgb, cData->img_clr_tbl, 32);
|
||||
if (allGray == JNI_TRUE) {
|
||||
initInverseGrayLut(pRgb, bisdo->lutsize, cData);
|
||||
}
|
||||
|
@ -163,6 +163,7 @@ typedef struct {
|
||||
char *grnErrTable; /* Green ordered dither table */
|
||||
char *bluErrTable; /* Blue ordered dither table */
|
||||
int *invGrayTable; /* Inverse gray table */
|
||||
int representsPrimaries; /* whether cmap represents primary colors */
|
||||
union {
|
||||
void *align; /* ensures strict alignment */
|
||||
char data[SD_RASINFO_PRIVATE_SIZE];
|
||||
|
@ -43,7 +43,7 @@ typedef jubyte ByteIndexedDataType;
|
||||
jint *PREFIX ## Lut;
|
||||
|
||||
#define DeclareByteIndexedStoreVars(PREFIX) \
|
||||
int PREFIX ## XDither, PREFIX ## YDither; \
|
||||
int PREFIX ## XDither, PREFIX ## YDither, PREFIX ## RepPrims; \
|
||||
char *PREFIX ## rerr, *PREFIX ## gerr, *PREFIX ## berr; \
|
||||
unsigned char *PREFIX ## InvLut;
|
||||
|
||||
@ -70,6 +70,7 @@ typedef jubyte ByteIndexedDataType;
|
||||
do { \
|
||||
SetByteIndexedStoreVarsYPos(PREFIX, pRasInfo, (pRasInfo)->bounds.y1); \
|
||||
PREFIX ## InvLut = (pRasInfo)->invColorTable; \
|
||||
PREFIX ## RepPrims = (pRasInfo)->representsPrimaries; \
|
||||
} while (0)
|
||||
|
||||
#define InitByteIndexedStoreVarsX(PREFIX, pRasInfo) \
|
||||
@ -168,9 +169,14 @@ typedef jubyte ByteIndexedBmDataType;
|
||||
|
||||
#define StoreByteIndexedFrom3ByteRgb(pRas, PREFIX, x, r, g, b) \
|
||||
do { \
|
||||
r += PREFIX ## rerr[PREFIX ## XDither]; \
|
||||
g += PREFIX ## gerr[PREFIX ## XDither]; \
|
||||
b += PREFIX ## berr[PREFIX ## XDither]; \
|
||||
if (!(((r == 0) || (r == 255)) && \
|
||||
((g == 0) || (g == 255)) && \
|
||||
((b == 0) || (b == 255)) && \
|
||||
PREFIX ## RepPrims)) { \
|
||||
r += PREFIX ## rerr[PREFIX ## XDither]; \
|
||||
g += PREFIX ## gerr[PREFIX ## XDither]; \
|
||||
b += PREFIX ## berr[PREFIX ## XDither]; \
|
||||
} \
|
||||
ByteClamp3Components(r, g, b); \
|
||||
(pRas)[x] = SurfaceData_InvColorMap(PREFIX ## InvLut, r, g, b); \
|
||||
} while (0)
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -191,4 +191,11 @@ typedef jubyte FourByteAbgrDataType;
|
||||
COMP_PREFIX ## A, COMP_PREFIX ## R, \
|
||||
COMP_PREFIX ## G, COMP_PREFIX ## B)
|
||||
|
||||
/*
|
||||
* SrcOver ## TYPE ## BlendFactor
|
||||
* Returns appropriate blend value for use in blending calculations.
|
||||
*/
|
||||
#define SrcOverFourByteAbgrBlendFactor(dF, dA) \
|
||||
(dA)
|
||||
|
||||
#endif /* FourByteAbgr_h_Included */
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -217,4 +217,11 @@ typedef jubyte FourByteAbgrPreDataType;
|
||||
(pRas)[4*(x)+3] = (jubyte) COMP_PREFIX ## R; \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* SrcOver ## TYPE ## BlendFactor
|
||||
* Returns appropriate blend value for use in blending calculations.
|
||||
*/
|
||||
#define SrcOverFourByteAbgrPreBlendFactor(dF, dA) \
|
||||
(dF)
|
||||
|
||||
#endif /* FourByteAbgrPre_h_Included */
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -208,4 +208,11 @@ typedef jint IntArgbDataType;
|
||||
COMP_PREFIX ## A = (COMP_PREFIX ## A << 8) + COMP_PREFIX ## A; \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* SrcOver ## TYPE ## BlendFactor
|
||||
* Returns appropriate blend value for use in blending calculations.
|
||||
*/
|
||||
#define SrcOverIntArgbBlendFactor(dF, dA) \
|
||||
(dA)
|
||||
|
||||
#endif /* IntArgb_h_Included */
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -206,4 +206,11 @@ typedef jint IntArgbBmDataType;
|
||||
COMP_PREFIX ## A = (COMP_PREFIX ## A << 8) + COMP_PREFIX ## A; \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* SrcOver ## TYPE ## BlendFactor
|
||||
* Returns appropriate blend value for use in blending calculations.
|
||||
*/
|
||||
#define SrcOverIntArgbBmBlendFactor(dF, dA) \
|
||||
(dA)
|
||||
|
||||
#endif /* IntArgbBm_h_Included */
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -216,4 +216,11 @@ typedef jint IntArgbPreDataType;
|
||||
COMP_PREFIX ## G, \
|
||||
COMP_PREFIX ## B)
|
||||
|
||||
/*
|
||||
* SrcOver ## TYPE ## BlendFactor
|
||||
* Returns appropriate blend value for use in blending calculations.
|
||||
*/
|
||||
#define SrcOverIntArgbPreBlendFactor(dF, dA) \
|
||||
(dF)
|
||||
|
||||
#endif /* IntArgbPre_h_Included */
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -1668,31 +1668,83 @@ void NAME_SOLID_DRAWGLYPHLIST(DST)(SurfaceDataRasInfo *pRasInfo, \
|
||||
} \
|
||||
} while (0);
|
||||
|
||||
/*
|
||||
* Antialiased glyph drawing results in artifacts around the character edges
|
||||
* when text is drawn ontop of translucent background color. The standard
|
||||
* blending equation for two colors:
|
||||
* destColor = srcColor * glyphAlpha + destColor * (1 - glyphAlpha)
|
||||
* works only when srcColor and destColor are opaque. For translucent srcColor
|
||||
* and destColor, the respective alpha components in each color will influence
|
||||
* the visibility of the color and the visibility of the color below it. Hence
|
||||
* the equation for blending is given as:
|
||||
* resA = srcAlpha + dstAlpha * (1 - srcAlpha)
|
||||
* resCol = (srcColor * srcAlpha + destColor * destAlpha * (1- srcAlpha))/resA
|
||||
* In addition, srcAlpha is multiplied with the glyphAlpha- that indicates the
|
||||
* grayscale mask value of the glyph being drawn. The combined result provides
|
||||
* smooth antialiased text on the buffer without any artifacts. Since the
|
||||
* logic is executed for every pixel in a glyph, the implementation is further
|
||||
* optimized to reduce computation and improve execution time.
|
||||
*/
|
||||
#define GlyphListAABlend4ByteArgb(DST, GLYPH_PIXELS, PIXEL_INDEX, DST_PTR, \
|
||||
FG_PIXEL, PREFIX, SRC_PREFIX) \
|
||||
do { \
|
||||
DeclareAlphaVarFor4ByteArgb(dstA) \
|
||||
DeclareCompVarsFor4ByteArgb(dst) \
|
||||
do { \
|
||||
DeclareAlphaVarFor4ByteArgb(resA) \
|
||||
DeclareCompVarsFor4ByteArgb(res) \
|
||||
jint mixValSrc = GLYPH_PIXELS[PIXEL_INDEX]; \
|
||||
if (mixValSrc) { \
|
||||
if (mixValSrc < 255) { \
|
||||
jint mixValDst = 255 - mixValSrc; \
|
||||
Load ## DST ## To4ByteArgb(DST_PTR, pix, PIXEL_INDEX, \
|
||||
dstA, dstR, dstG, dstB); \
|
||||
dstA = MUL8(dstA, mixValDst) + \
|
||||
MUL8(SRC_PREFIX ## A, mixValSrc); \
|
||||
MultMultAddAndStore4ByteArgbComps(dst, mixValDst, dst, \
|
||||
mixValSrc, SRC_PREFIX); \
|
||||
if (!(DST ## IsOpaque) && \
|
||||
!(DST ## IsPremultiplied) && dstA && dstA < 255) { \
|
||||
DivideAndStore4ByteArgbComps(dst, dst, dstA); \
|
||||
if (mixValSrc != 0xff) { \
|
||||
PromoteByteAlphaFor4ByteArgb(mixValSrc); \
|
||||
resA = MultiplyAlphaFor4ByteArgb(mixValSrc, SRC_PREFIX ## A); \
|
||||
} else { \
|
||||
resA = SRC_PREFIX ## A; \
|
||||
} \
|
||||
if (resA != MaxValFor4ByteArgb) { \
|
||||
DeclareAndInvertAlphaVarFor4ByteArgb(dstF, resA) \
|
||||
DeclareAndClearAlphaVarFor4ByteArgb(dstA) \
|
||||
DeclareCompVarsFor4ByteArgb(dst) \
|
||||
DeclareCompVarsFor4ByteArgb(tmp) \
|
||||
MultiplyAndStore4ByteArgbComps(res, resA, SRC_PREFIX); \
|
||||
if (!(DST ## IsPremultiplied)) { \
|
||||
Load ## DST ## To4ByteArgb(DST_PTR, pix, PIXEL_INDEX, \
|
||||
dstA, dstR, dstG, dstB); \
|
||||
Store4ByteArgbCompsUsingOp(tmp, =, dst); \
|
||||
} else { \
|
||||
Declare ## DST ## AlphaLoadData(DstPix) \
|
||||
jint pixelOffset = PIXEL_INDEX * (DST ## PixelStride); \
|
||||
DST ## DataType *pixelAddress = PtrAddBytes(DST_PTR, \
|
||||
pixelOffset); \
|
||||
LoadAlphaFrom ## DST ## For4ByteArgb(pixelAddress, \
|
||||
DstPix, \
|
||||
dst); \
|
||||
Postload4ByteArgbFrom ## DST(pixelAddress, \
|
||||
DstPix, \
|
||||
tmp); \
|
||||
} \
|
||||
if (dstA) { \
|
||||
DeclareAlphaVarFor4ByteArgb(blendF) \
|
||||
dstA = MultiplyAlphaFor4ByteArgb(dstF, dstA); \
|
||||
resA += dstA; \
|
||||
blendF = SrcOver ## DST ## BlendFactor(dstF, dstA); \
|
||||
if (blendF != MaxValFor4ByteArgb) { \
|
||||
MultiplyAndStore4ByteArgbComps(tmp, \
|
||||
blendF, \
|
||||
tmp); \
|
||||
} \
|
||||
Store4ByteArgbCompsUsingOp(res, +=, tmp); \
|
||||
} \
|
||||
Store ## DST ## From4ByteArgbComps(DST_PTR, pix, \
|
||||
PIXEL_INDEX, dst); \
|
||||
} else { \
|
||||
Store ## DST ## PixelData(DST_PTR, PIXEL_INDEX, \
|
||||
FG_PIXEL, PREFIX); \
|
||||
break; \
|
||||
} \
|
||||
if (!(DST ## IsOpaque) && \
|
||||
!(DST ## IsPremultiplied) && resA && \
|
||||
resA < MaxValFor4ByteArgb) \
|
||||
{ \
|
||||
DivideAndStore4ByteArgbComps(res, res, resA); \
|
||||
} \
|
||||
Store ## DST ## From4ByteArgbComps(DST_PTR, pix, \
|
||||
PIXEL_INDEX, res); \
|
||||
} \
|
||||
} while (0);
|
||||
|
||||
|
@ -44,6 +44,7 @@ typedef struct _ColorData {
|
||||
char* img_oda_blue;
|
||||
int *pGrayInverseLutData;
|
||||
int screendata;
|
||||
int representsPrimaries;
|
||||
} ColorData;
|
||||
|
||||
|
||||
|
@ -312,7 +312,7 @@ static void* dl_symbol_gthread(const char* name)
|
||||
return result;
|
||||
}
|
||||
|
||||
gboolean gtk2_check(const char* lib_name, int flags)
|
||||
gboolean gtk2_check(const char* lib_name, gboolean load)
|
||||
{
|
||||
if (gtk2_libhandle != NULL) {
|
||||
/* We've already successfully opened the GTK libs, so return true. */
|
||||
@ -320,16 +320,25 @@ gboolean gtk2_check(const char* lib_name, int flags)
|
||||
} else {
|
||||
void *lib = NULL;
|
||||
|
||||
lib = dlopen(lib_name, flags);
|
||||
#ifdef RTLD_NOLOAD
|
||||
/* Just check if gtk libs are already in the process space */
|
||||
lib = dlopen(lib_name, RTLD_LAZY | RTLD_NOLOAD);
|
||||
if (!load || lib != NULL) {
|
||||
return lib != NULL;
|
||||
}
|
||||
#else
|
||||
#ifdef _AIX
|
||||
/* On AIX we could implement this with the help of loadquery(L_GETINFO, ..) */
|
||||
/* (see reload_table() in hotspot/src/os/aix/vm/loadlib_aix.cpp) but it is */
|
||||
/* probably not worth it because most AIX servers don't have GTK libs anyway */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
lib = dlopen(lib_name, RTLD_LAZY | RTLD_LOCAL);
|
||||
if (lib == NULL) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (flags & RTLD_NOLOAD) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
fp_gtk_check_version = dlsym(lib, "gtk_check_version");
|
||||
/* Check for GTK 2.2+ */
|
||||
if (!fp_gtk_check_version(2, 2, 0)) {
|
||||
|
@ -87,13 +87,25 @@ static void* dl_symbol(const char* name)
|
||||
return result;
|
||||
}
|
||||
|
||||
gboolean gtk3_check(const char* lib_name, int flags)
|
||||
gboolean gtk3_check(const char* lib_name, gboolean load)
|
||||
{
|
||||
if (gtk3_libhandle != NULL) {
|
||||
/* We've already successfully opened the GTK libs, so return true. */
|
||||
return TRUE;
|
||||
} else {
|
||||
return dlopen(lib_name, flags) != NULL;
|
||||
#ifdef RTLD_NOLOAD
|
||||
void *lib = dlopen(lib_name, RTLD_LAZY | RTLD_NOLOAD);
|
||||
if (!load || lib != NULL) {
|
||||
return lib != NULL;
|
||||
}
|
||||
#else
|
||||
#ifdef _AIX
|
||||
/* On AIX we could implement this with the help of loadquery(L_GETINFO, ..) */
|
||||
/* (see reload_table() in hotspot/src/os/aix/vm/loadlib_aix.cpp) but it is */
|
||||
/* probably not worth it because most AIX servers don't have GTK libs anyway */
|
||||
#endif
|
||||
#endif
|
||||
return dlopen(lib_name, RTLD_LAZY | RTLD_LOCAL) != NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -30,8 +30,8 @@
|
||||
GtkApi* gtk2_load(JNIEnv *env, const char* lib_name);
|
||||
GtkApi* gtk3_load(JNIEnv *env, const char* lib_name);
|
||||
|
||||
gboolean gtk2_check(const char* lib_name, int flags);
|
||||
gboolean gtk3_check(const char* lib_name, int flags);
|
||||
gboolean gtk2_check(const char* lib_name, gboolean load);
|
||||
gboolean gtk3_check(const char* lib_name, gboolean load);
|
||||
|
||||
GtkApi *gtk;
|
||||
|
||||
@ -40,7 +40,7 @@ typedef struct {
|
||||
const char* name;
|
||||
const char* vname;
|
||||
GtkApi* (*load)(JNIEnv *env, const char* lib_name);
|
||||
gboolean (*check)(const char* lib_name, int flags);
|
||||
gboolean (*check)(const char* lib_name, gboolean load);
|
||||
} GtkLib;
|
||||
|
||||
static GtkLib libs[] = {
|
||||
@ -70,10 +70,10 @@ static GtkLib libs[] = {
|
||||
static GtkLib* get_loaded() {
|
||||
GtkLib* lib = libs;
|
||||
while(!gtk && lib->version) {
|
||||
if (lib->check(lib->vname, RTLD_NOLOAD)) {
|
||||
if (lib->check(lib->vname, /* load = */FALSE)) {
|
||||
return lib;
|
||||
}
|
||||
if (lib->check(lib->name, RTLD_NOLOAD)) {
|
||||
if (lib->check(lib->name, /* load = */FALSE)) {
|
||||
return lib;
|
||||
}
|
||||
lib++;
|
||||
@ -130,14 +130,14 @@ gboolean gtk_load(JNIEnv *env, GtkVersion version, gboolean verbose) {
|
||||
return gtk != NULL;
|
||||
}
|
||||
|
||||
static gboolean check_version(GtkVersion version, int flags) {
|
||||
static gboolean check_version(GtkVersion version) {
|
||||
GtkLib* lib = libs;
|
||||
while (lib->version) {
|
||||
if (version == GTK_ANY || lib->version == version) {
|
||||
if (lib->check(lib->vname, flags)) {
|
||||
if (lib->check(lib->vname, /* load = */TRUE)) {
|
||||
return TRUE;
|
||||
}
|
||||
if (lib->check(lib->name, flags)) {
|
||||
if (lib->check(lib->name, /* load = */TRUE)) {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
@ -150,9 +150,6 @@ gboolean gtk_check_version(GtkVersion version) {
|
||||
if (gtk) {
|
||||
return TRUE;
|
||||
}
|
||||
if (check_version(version, RTLD_NOLOAD)) {
|
||||
return TRUE;
|
||||
}
|
||||
return check_version(version, RTLD_LAZY | RTLD_LOCAL);
|
||||
return check_version(version);
|
||||
}
|
||||
|
||||
|
@ -33,6 +33,7 @@ typedef struct _ColorData {
|
||||
char* img_oda_blue;
|
||||
unsigned char* img_clr_tbl;
|
||||
int *pGrayInverseLutData;
|
||||
int representsPrimaries;
|
||||
} ColorData;
|
||||
|
||||
#define CANFREE(pData) (pData)
|
||||
|
@ -144,13 +144,9 @@ public class AsyncSSLDelegate implements Closeable, AsyncConnection {
|
||||
sslParameters = Utils.copySSLParameters(sslp);
|
||||
if (alpn != null) {
|
||||
sslParameters.setApplicationProtocols(alpn);
|
||||
Log.logSSL("Setting application protocols: " + Arrays.toString(alpn));
|
||||
} else {
|
||||
Log.logSSL("No application protocols proposed");
|
||||
}
|
||||
logParams(sslParameters);
|
||||
engine.setSSLParameters(sslParameters);
|
||||
engine.setEnabledCipherSuites(sslp.getCipherSuites());
|
||||
engine.setEnabledProtocols(sslp.getProtocols());
|
||||
this.lowerOutput = lowerOutput;
|
||||
this.client = client;
|
||||
this.channelInputQ = new Queue<>();
|
||||
@ -560,24 +556,26 @@ public class AsyncSSLDelegate implements Closeable, AsyncConnection {
|
||||
return sslParameters;
|
||||
}
|
||||
|
||||
static void printParams(SSLParameters p) {
|
||||
System.out.println("SSLParameters:");
|
||||
static void logParams(SSLParameters p) {
|
||||
if (!Log.ssl())
|
||||
return;
|
||||
Log.logSSL("SSLParameters:");
|
||||
if (p == null) {
|
||||
System.out.println("Null params");
|
||||
Log.logSSL("Null params");
|
||||
return;
|
||||
}
|
||||
for (String cipher : p.getCipherSuites()) {
|
||||
System.out.printf("cipher: %s\n", cipher);
|
||||
Log.logSSL("cipher: {0}\n", cipher);
|
||||
}
|
||||
for (String approto : p.getApplicationProtocols()) {
|
||||
System.out.printf("application protocol: %s\n", approto);
|
||||
Log.logSSL("application protocol: {0}\n", approto);
|
||||
}
|
||||
for (String protocol : p.getProtocols()) {
|
||||
System.out.printf("protocol: %s\n", protocol);
|
||||
Log.logSSL("protocol: {0}\n", protocol);
|
||||
}
|
||||
if (p.getServerNames() != null)
|
||||
for (SNIServerName sname : p.getServerNames()) {
|
||||
System.out.printf("server name: %s\n", sname.toString());
|
||||
for (SNIServerName sname : p.getServerNames()) {
|
||||
Log.logSSL("server name: {0}\n", sname.toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -110,7 +110,10 @@ class HttpClientImpl extends HttpClient implements BufferHandler {
|
||||
this.proxySelector = builder.proxy;
|
||||
authenticator = builder.authenticator;
|
||||
version = builder.version;
|
||||
sslParams = builder.sslParams;
|
||||
if (builder.sslParams == null)
|
||||
sslParams = getDefaultParams(sslContext);
|
||||
else
|
||||
sslParams = builder.sslParams;
|
||||
connections = new ConnectionPool();
|
||||
connections.start();
|
||||
timeouts = new LinkedList<>();
|
||||
@ -129,6 +132,12 @@ class HttpClientImpl extends HttpClient implements BufferHandler {
|
||||
selmgr.start();
|
||||
}
|
||||
|
||||
private static SSLParameters getDefaultParams(SSLContext ctx) {
|
||||
SSLParameters params = ctx.getSupportedSSLParameters();
|
||||
params.setProtocols(new String[]{"TLSv1.2"});
|
||||
return params;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for activity on given exchange (assuming blocking = false).
|
||||
* It's a no-op if blocking = true. In particular, the following occurs
|
||||
|
@ -66,8 +66,6 @@ class SSLDelegate {
|
||||
Log.logSSL("No application protocols proposed");
|
||||
}
|
||||
engine.setSSLParameters(sslParameters);
|
||||
engine.setEnabledCipherSuites(sslp.getCipherSuites());
|
||||
engine.setEnabledProtocols(sslp.getProtocols());
|
||||
wrapper = new EngineWrapper(chan, engine);
|
||||
this.chan = chan;
|
||||
this.client = client;
|
||||
|
@ -146,7 +146,7 @@ final class Utils {
|
||||
} else {
|
||||
sb.append(uri.getScheme())
|
||||
.append("://")
|
||||
.append(uri.getHost())
|
||||
.append(uri.getAuthority())
|
||||
.append(uri.getPath());
|
||||
urlstring = sb.toString();
|
||||
|
||||
|
@ -436,7 +436,8 @@ public class InstrumentationImpl implements Instrumentation {
|
||||
if (classBeingRedefined != null) {
|
||||
module = classBeingRedefined.getModule();
|
||||
} else {
|
||||
module = loader.getUnnamedModule();
|
||||
module = (loader == null) ? jdk.internal.loader.BootLoader.getUnnamedModule()
|
||||
: loader.getUnnamedModule();
|
||||
}
|
||||
}
|
||||
if (mgr == null) {
|
||||
|
@ -650,6 +650,7 @@ JNIEXPORT jint JNICALL Java_com_oracle_security_ucrypto_NativeCipher_nativeFinal
|
||||
unsigned char *bufIn;
|
||||
unsigned char *bufOut;
|
||||
int outLen, rv = 0;
|
||||
jint rc;
|
||||
|
||||
context = (crypto_ctx_t *) contextID;
|
||||
|
||||
@ -668,22 +669,20 @@ JNIEXPORT jint JNICALL Java_com_oracle_security_ucrypto_NativeCipher_nativeFinal
|
||||
}
|
||||
rv = CipherFinal(context, encrypt, bufOut, 0, &outLen);
|
||||
if (rv) {
|
||||
free(context);
|
||||
if (outLen != 0) {
|
||||
free(bufOut);
|
||||
}
|
||||
return -rv;
|
||||
rc = -rv;
|
||||
} else {
|
||||
if (bufOut != NULL && outLen != 0) {
|
||||
if (outLen > 0) {
|
||||
(*env)->SetByteArrayRegion(env, out, outOfs, outLen, (jbyte *)bufOut);
|
||||
free(bufOut);
|
||||
}
|
||||
free(context);
|
||||
return outLen;
|
||||
rc = outLen;
|
||||
}
|
||||
free(context);
|
||||
if (bufOut != (unsigned char *)(&outLen)) {
|
||||
free(bufOut);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Class: com_oracle_security_ucrypto_NativeKey
|
||||
* Method: nativeFree
|
||||
|
@ -370,7 +370,10 @@ public class WindowsTerminal
|
||||
}
|
||||
} else {
|
||||
// virtual keycodes: http://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx
|
||||
// just add support for basic editing keys (no control state, no numpad keys)
|
||||
// xterm escape codes: E. Moy, S. Gildea and T. Dickey, "XTerm Control Sequences":
|
||||
// http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
|
||||
// http://xorg.freedesktop.org/releases/X11R6.8.1/PDF/ctlseqs.pdf
|
||||
// just add support for basic editing keys and function keys
|
||||
String escapeSequence = null;
|
||||
switch (keyEvent.keyCode) {
|
||||
case 0x21: // VK_PRIOR PageUp
|
||||
@ -403,6 +406,42 @@ public class WindowsTerminal
|
||||
case 0x2E: // VK_DELETE
|
||||
escapeSequence = escapeSequence(keyEvent.controlKeyState, "\u001B[3~", "\u001B[3;%d~");
|
||||
break;
|
||||
case 0x70: // VK_F1
|
||||
escapeSequence = escapeSequence(keyEvent.controlKeyState, "\u001BOP", "\u001BO%dP");
|
||||
break;
|
||||
case 0x71: // VK_F2
|
||||
escapeSequence = escapeSequence(keyEvent.controlKeyState, "\u001BOQ", "\u001BO%dQ");
|
||||
break;
|
||||
case 0x72: // VK_F3
|
||||
escapeSequence = escapeSequence(keyEvent.controlKeyState, "\u001BOR", "\u001BO%dR");
|
||||
break;
|
||||
case 0x73: // VK_F4
|
||||
escapeSequence = escapeSequence(keyEvent.controlKeyState, "\u001BOS", "\u001BO%dS");
|
||||
break;
|
||||
case 0x74: // VK_F5
|
||||
escapeSequence = escapeSequence(keyEvent.controlKeyState, "\u001B[15~", "\u001B[15;%d~");
|
||||
break;
|
||||
case 0x75: // VK_F6
|
||||
escapeSequence = escapeSequence(keyEvent.controlKeyState, "\u001B[17~", "\u001B[17;%d~");
|
||||
break;
|
||||
case 0x76: // VK_F7
|
||||
escapeSequence = escapeSequence(keyEvent.controlKeyState, "\u001B[18~", "\u001B[18;%d~");
|
||||
break;
|
||||
case 0x77: // VK_F8
|
||||
escapeSequence = escapeSequence(keyEvent.controlKeyState, "\u001B[19~", "\u001B[19;%d~");
|
||||
break;
|
||||
case 0x78: // VK_F9
|
||||
escapeSequence = escapeSequence(keyEvent.controlKeyState, "\u001B[20~", "\u001B[20;%d~");
|
||||
break;
|
||||
case 0x79: // VK_F10
|
||||
escapeSequence = escapeSequence(keyEvent.controlKeyState, "\u001B[21~", "\u001B[21;%d~");
|
||||
break;
|
||||
case 0x7A: // VK_F11
|
||||
escapeSequence = escapeSequence(keyEvent.controlKeyState, "\u001B[23~", "\u001B[23;%d~");
|
||||
break;
|
||||
case 0x7B: // VK_F12
|
||||
escapeSequence = escapeSequence(keyEvent.controlKeyState, "\u001B[24~", "\u001B[24;%d~");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -177,24 +177,28 @@ public final class IncludeLocalesPlugin implements TransformerPlugin, ResourcePr
|
||||
Pool.Module module = resources.getModule(MODULENAME);
|
||||
|
||||
// jdk.localedata module validation
|
||||
Set<String> packages = module.getAllPackages();
|
||||
if (!packages.containsAll(LOCALEDATA_PACKAGES)) {
|
||||
throw new PluginException(PluginsResourceBundle.getMessage(NAME + ".missingpackages") +
|
||||
LOCALEDATA_PACKAGES.stream()
|
||||
.filter(pn -> !packages.contains(pn))
|
||||
.collect(Collectors.joining(",\n\t")));
|
||||
if (module != null) {
|
||||
Set<String> packages = module.getAllPackages();
|
||||
if (!packages.containsAll(LOCALEDATA_PACKAGES)) {
|
||||
throw new PluginException(PluginsResourceBundle.getMessage(NAME + ".missingpackages") +
|
||||
LOCALEDATA_PACKAGES.stream()
|
||||
.filter(pn -> !packages.contains(pn))
|
||||
.collect(Collectors.joining(",\n\t")));
|
||||
}
|
||||
|
||||
available = Stream.concat(module.getContent().stream()
|
||||
.map(md -> p.matcher(md.getPath()))
|
||||
.filter(m -> m.matches())
|
||||
.map(m -> m.group("tag").replaceAll("_", "-")),
|
||||
Stream.concat(Stream.of(jaJPJPTag), Stream.of(thTHTHTag)))
|
||||
.distinct()
|
||||
.sorted()
|
||||
.map(IncludeLocalesPlugin::tagToLocale)
|
||||
.collect(Collectors.toList());
|
||||
} else {
|
||||
// jdk.localedata is not added.
|
||||
throw new PluginException(PluginsResourceBundle.getMessage(NAME + ".localedatanotfound"));
|
||||
}
|
||||
|
||||
available = Stream.concat(module.getContent().stream()
|
||||
.map(md -> p.matcher(md.getPath()))
|
||||
.filter(m -> m.matches())
|
||||
.map(m -> m.group("tag").replaceAll("_", "-")),
|
||||
Stream.concat(Stream.of(jaJPJPTag), Stream.of(thTHTHTag)))
|
||||
.distinct()
|
||||
.sorted()
|
||||
.map(IncludeLocalesPlugin::tagToLocale)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
filtered = filterLocales(available);
|
||||
|
||||
if (filtered.isEmpty()) {
|
||||
|
@ -89,6 +89,9 @@ No matching locales found for \"%s\". Check the specified pattern.
|
||||
include-locales.invalidtag=\
|
||||
Invalid language tag: %s
|
||||
|
||||
include-locales.localedatanotfound=\
|
||||
jdk.localedata module was not specified with --addmods option
|
||||
|
||||
main.status.ok=Functional.
|
||||
|
||||
main.status.not.ok= Not functional.
|
||||
|
@ -52,10 +52,10 @@ class JarFileSystem extends ZipFileSystem {
|
||||
private Function<byte[],byte[]> lookup;
|
||||
|
||||
@Override
|
||||
Entry getEntry(byte[] path) throws IOException {
|
||||
IndexNode getInode(byte[] path) {
|
||||
// check for an alias to a versioned entry
|
||||
byte[] versionedPath = lookup.apply(path);
|
||||
return versionedPath == null ? super.getEntry(path) : super.getEntry(versionedPath);
|
||||
return versionedPath == null ? super.getInode(path) : super.getInode(versionedPath);
|
||||
}
|
||||
|
||||
JarFileSystem(ZipFileSystemProvider provider, Path zfpath, Map<String,?> env)
|
||||
@ -87,7 +87,7 @@ class JarFileSystem extends ZipFileSystem {
|
||||
}
|
||||
|
||||
private boolean isMultiReleaseJar() {
|
||||
try (InputStream is = newInputStream(getBytes("META-INF/MANIFEST.MF"))) {
|
||||
try (InputStream is = newInputStream(getBytes("/META-INF/MANIFEST.MF"))) {
|
||||
return (new Manifest(is)).getMainAttributes()
|
||||
.containsKey(new Attributes.Name("Multi-Release"));
|
||||
// fixme change line above after JarFile integration to contain Attributes.Name.MULTI_RELEASE
|
||||
@ -108,7 +108,7 @@ class JarFileSystem extends ZipFileSystem {
|
||||
*/
|
||||
private Function<byte[],byte[]> createVersionedLinks(int version) {
|
||||
HashMap<IndexNode,byte[]> aliasMap = new HashMap<>();
|
||||
getVersionMap(version, getInode(getBytes("META-INF/versions"))).values()
|
||||
getVersionMap(version, getInode(getBytes("/META-INF/versions"))).values()
|
||||
.forEach(versionNode -> { // for each META-INF/versions/{n} directory
|
||||
// put all the leaf inodes, i.e. entries, into the alias map
|
||||
// possibly shadowing lower versioned entries
|
||||
@ -176,7 +176,7 @@ class JarFileSystem extends ZipFileSystem {
|
||||
* returns foo/bar.class
|
||||
*/
|
||||
private byte[] getRootName(IndexNode prefix, IndexNode inode) {
|
||||
int offset = prefix.name.length;
|
||||
int offset = prefix.name.length - 1;
|
||||
byte[] fullName = inode.name;
|
||||
return Arrays.copyOfRange(fullName, offset, fullName.length);
|
||||
}
|
||||
|
@ -26,122 +26,17 @@
|
||||
package jdk.nio.zipfs;
|
||||
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.nio.file.attribute.FileTime;
|
||||
import java.util.Arrays;
|
||||
import java.util.Formatter;
|
||||
import static jdk.nio.zipfs.ZipUtils.*;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Xueming Shen, Rajendra Gutupalli,Jaya Hangal
|
||||
*/
|
||||
|
||||
class ZipFileAttributes implements BasicFileAttributes
|
||||
{
|
||||
private final ZipFileSystem.Entry e;
|
||||
|
||||
ZipFileAttributes(ZipFileSystem.Entry e) {
|
||||
this.e = e;
|
||||
}
|
||||
|
||||
///////// basic attributes ///////////
|
||||
@Override
|
||||
public FileTime creationTime() {
|
||||
if (e.ctime != -1)
|
||||
return FileTime.fromMillis(e.ctime);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDirectory() {
|
||||
return e.isDir();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOther() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRegularFile() {
|
||||
return !e.isDir();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileTime lastAccessTime() {
|
||||
if (e.atime != -1)
|
||||
return FileTime.fromMillis(e.atime);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileTime lastModifiedTime() {
|
||||
return FileTime.fromMillis(e.mtime);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long size() {
|
||||
return e.size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSymbolicLink() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object fileKey() {
|
||||
return null;
|
||||
}
|
||||
|
||||
///////// zip entry attributes ///////////
|
||||
public long compressedSize() {
|
||||
return e.csize;
|
||||
}
|
||||
|
||||
public long crc() {
|
||||
return e.crc;
|
||||
}
|
||||
|
||||
public int method() {
|
||||
return e.method;
|
||||
}
|
||||
|
||||
public byte[] extra() {
|
||||
if (e.extra != null)
|
||||
return Arrays.copyOf(e.extra, e.extra.length);
|
||||
return null;
|
||||
}
|
||||
|
||||
public byte[] comment() {
|
||||
if (e.comment != null)
|
||||
return Arrays.copyOf(e.comment, e.comment.length);
|
||||
return null;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder(1024);
|
||||
Formatter fm = new Formatter(sb);
|
||||
if (creationTime() != null)
|
||||
fm.format(" creationTime : %tc%n", creationTime().toMillis());
|
||||
else
|
||||
fm.format(" creationTime : null%n");
|
||||
|
||||
if (lastAccessTime() != null)
|
||||
fm.format(" lastAccessTime : %tc%n", lastAccessTime().toMillis());
|
||||
else
|
||||
fm.format(" lastAccessTime : null%n");
|
||||
fm.format(" lastModifiedTime: %tc%n", lastModifiedTime().toMillis());
|
||||
fm.format(" isRegularFile : %b%n", isRegularFile());
|
||||
fm.format(" isDirectory : %b%n", isDirectory());
|
||||
fm.format(" isSymbolicLink : %b%n", isSymbolicLink());
|
||||
fm.format(" isOther : %b%n", isOther());
|
||||
fm.format(" fileKey : %s%n", fileKey());
|
||||
fm.format(" size : %d%n", size());
|
||||
fm.format(" compressedSize : %d%n", compressedSize());
|
||||
fm.format(" crc : %x%n", crc());
|
||||
fm.format(" method : %d%n", method());
|
||||
fm.close();
|
||||
return sb.toString();
|
||||
}
|
||||
interface ZipFileAttributes extends BasicFileAttributes {
|
||||
public long compressedSize();
|
||||
public long crc();
|
||||
public int method();
|
||||
public byte[] extra();
|
||||
public byte[] comment();
|
||||
public String toString();
|
||||
}
|
||||
|
@ -68,36 +68,29 @@ import static java.nio.file.StandardCopyOption.*;
|
||||
class ZipFileSystem extends FileSystem {
|
||||
|
||||
private final ZipFileSystemProvider provider;
|
||||
private final ZipPath defaultdir;
|
||||
private boolean readOnly = false;
|
||||
private final Path zfpath;
|
||||
private final ZipCoder zc;
|
||||
|
||||
private final boolean noExtt; // see readExtra()
|
||||
private final ZipPath rootdir;
|
||||
// configurable by env map
|
||||
private final String defaultDir; // default dir for the file system
|
||||
private final String nameEncoding; // default encoding for name/comment
|
||||
private final boolean useTempFile; // use a temp file for newOS, default
|
||||
// is to use BAOS for better performance
|
||||
private final boolean createNew; // create a new zip if not exists
|
||||
private boolean readOnly = false; // readonly file system
|
||||
private static final boolean isWindows = AccessController.doPrivileged(
|
||||
(PrivilegedAction<Boolean>) () -> System.getProperty("os.name")
|
||||
.startsWith("Windows"));
|
||||
|
||||
ZipFileSystem(ZipFileSystemProvider provider,
|
||||
Path zfpath,
|
||||
Map<String, ?> env)
|
||||
throws IOException
|
||||
Map<String, ?> env) throws IOException
|
||||
{
|
||||
// configurable env setup
|
||||
this.createNew = "true".equals(env.get("create"));
|
||||
this.nameEncoding = env.containsKey("encoding") ?
|
||||
(String)env.get("encoding") : "UTF-8";
|
||||
// create a new zip if not exists
|
||||
boolean createNew = "true".equals(env.get("create"));
|
||||
// default encoding for name/comment
|
||||
String nameEncoding = env.containsKey("encoding") ?
|
||||
(String)env.get("encoding") : "UTF-8";
|
||||
this.noExtt = "false".equals(env.get("zipinfo-time"));
|
||||
this.useTempFile = TRUE.equals(env.get("useTempFile"));
|
||||
this.defaultDir = env.containsKey("default.dir") ?
|
||||
(String)env.get("default.dir") : "/";
|
||||
if (this.defaultDir.charAt(0) != '/')
|
||||
throw new IllegalArgumentException("default dir should be absolute");
|
||||
|
||||
this.provider = provider;
|
||||
this.zfpath = zfpath;
|
||||
if (Files.notExists(zfpath)) {
|
||||
@ -113,10 +106,9 @@ class ZipFileSystem extends FileSystem {
|
||||
zfpath.getFileSystem().provider().checkAccess(zfpath, AccessMode.READ);
|
||||
boolean writeable = AccessController.doPrivileged(
|
||||
(PrivilegedAction<Boolean>) () -> Files.isWritable(zfpath));
|
||||
if (!writeable)
|
||||
this.readOnly = true;
|
||||
this.readOnly = !writeable;
|
||||
this.zc = ZipCoder.get(nameEncoding);
|
||||
this.defaultdir = new ZipPath(this, getBytes(defaultDir));
|
||||
this.rootdir = new ZipPath(this, new byte[]{'/'});
|
||||
this.ch = Files.newByteChannel(zfpath, READ);
|
||||
try {
|
||||
this.cen = initCEN();
|
||||
@ -161,33 +153,29 @@ class ZipFileSystem extends FileSystem {
|
||||
|
||||
@Override
|
||||
public Iterable<Path> getRootDirectories() {
|
||||
ArrayList<Path> pathArr = new ArrayList<>();
|
||||
pathArr.add(new ZipPath(this, new byte[]{'/'}));
|
||||
return pathArr;
|
||||
return List.of(rootdir);
|
||||
}
|
||||
|
||||
ZipPath getDefaultDir() { // package private
|
||||
return defaultdir;
|
||||
ZipPath getRootDir() {
|
||||
return rootdir;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ZipPath getPath(String first, String... more) {
|
||||
String path;
|
||||
if (more.length == 0) {
|
||||
path = first;
|
||||
} else {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(first);
|
||||
for (String segment: more) {
|
||||
if (segment.length() > 0) {
|
||||
if (sb.length() > 0)
|
||||
sb.append('/');
|
||||
sb.append(segment);
|
||||
}
|
||||
}
|
||||
path = sb.toString();
|
||||
return new ZipPath(this, getBytes(first));
|
||||
}
|
||||
return new ZipPath(this, getBytes(path));
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(first);
|
||||
for (String path : more) {
|
||||
if (path.length() > 0) {
|
||||
if (sb.length() > 0) {
|
||||
sb.append('/');
|
||||
}
|
||||
sb.append(path);
|
||||
}
|
||||
}
|
||||
return new ZipPath(this, getBytes(sb.toString()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -206,14 +194,11 @@ class ZipFileSystem extends FileSystem {
|
||||
|
||||
@Override
|
||||
public Iterable<FileStore> getFileStores() {
|
||||
ArrayList<FileStore> list = new ArrayList<>(1);
|
||||
list.add(new ZipFileStore(new ZipPath(this, new byte[]{'/'})));
|
||||
return list;
|
||||
return List.of(new ZipFileStore(rootdir));
|
||||
}
|
||||
|
||||
private static final Set<String> supportedFileAttributeViews =
|
||||
Collections.unmodifiableSet(
|
||||
new HashSet<String>(Arrays.asList("basic", "zip")));
|
||||
Set.of("basic", "zip");
|
||||
|
||||
@Override
|
||||
public Set<String> supportedFileAttributeViews() {
|
||||
@ -331,12 +316,26 @@ class ZipFileSystem extends FileSystem {
|
||||
return null;
|
||||
e = new Entry(inode.name); // pseudo directory
|
||||
e.method = METHOD_STORED; // STORED for dir
|
||||
e.mtime = e.atime = e.ctime = -1;// -1 for all times
|
||||
e.mtime = e.atime = e.ctime = zfsDefaultTimeStamp;
|
||||
}
|
||||
} finally {
|
||||
endRead();
|
||||
}
|
||||
return new ZipFileAttributes(e);
|
||||
return e;
|
||||
}
|
||||
|
||||
void checkAccess(byte[] path) throws IOException {
|
||||
beginRead();
|
||||
try {
|
||||
ensureOpen();
|
||||
// is it necessary to readCEN as a sanity check?
|
||||
if (getInode(path) == null) {
|
||||
throw new NoSuchFileException(toString());
|
||||
}
|
||||
|
||||
} finally {
|
||||
endRead();
|
||||
}
|
||||
}
|
||||
|
||||
void setTimes(byte[] path, FileTime mtime, FileTime atime, FileTime ctime)
|
||||
@ -387,14 +386,6 @@ class ZipFileSystem extends FileSystem {
|
||||
}
|
||||
}
|
||||
|
||||
private ZipPath toZipPath(byte[] path) {
|
||||
// make it absolute
|
||||
byte[] p = new byte[path.length + 1];
|
||||
p[0] = '/';
|
||||
System.arraycopy(path, 0, p, 1, path.length);
|
||||
return new ZipPath(this, p);
|
||||
}
|
||||
|
||||
// returns the list of child paths of "path"
|
||||
Iterator<Path> iteratorOf(byte[] path,
|
||||
DirectoryStream.Filter<? super Path> filter)
|
||||
@ -409,7 +400,7 @@ class ZipFileSystem extends FileSystem {
|
||||
List<Path> list = new ArrayList<>();
|
||||
IndexNode child = inode.child;
|
||||
while (child != null) {
|
||||
ZipPath zp = toZipPath(child.name);
|
||||
ZipPath zp = new ZipPath(this, child.name);
|
||||
if (filter == null || filter.accept(zp))
|
||||
list.add(zp);
|
||||
child = child.sibling;
|
||||
@ -450,6 +441,7 @@ class ZipFileSystem extends FileSystem {
|
||||
try {
|
||||
ensureOpen();
|
||||
Entry eSrc = getEntry(src); // ensureOpen checked
|
||||
|
||||
if (eSrc == null)
|
||||
throw new NoSuchFileException(getString(src));
|
||||
if (eSrc.isDir()) { // spec says to create dst dir
|
||||
@ -679,7 +671,7 @@ class ZipFileSystem extends FileSystem {
|
||||
}
|
||||
|
||||
public SeekableByteChannel truncate(long size)
|
||||
throws IOException
|
||||
throws IOException
|
||||
{
|
||||
throw new NonWritableChannelException();
|
||||
}
|
||||
@ -879,7 +871,8 @@ class ZipFileSystem extends FileSystem {
|
||||
private void checkParents(byte[] path) throws IOException {
|
||||
beginRead();
|
||||
try {
|
||||
while ((path = getParent(path)) != null && path.length != 0) {
|
||||
while ((path = getParent(path)) != null &&
|
||||
path != ROOTPATH) {
|
||||
if (!inodes.containsKey(IndexNode.keyOf(path))) {
|
||||
throw new NoSuchFileException(getString(path));
|
||||
}
|
||||
@ -889,15 +882,20 @@ class ZipFileSystem extends FileSystem {
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] ROOTPATH = new byte[0];
|
||||
private static byte[] ROOTPATH = new byte[] { '/' };
|
||||
private static byte[] getParent(byte[] path) {
|
||||
int off = getParentOff(path);
|
||||
if (off <= 1)
|
||||
return ROOTPATH;
|
||||
return Arrays.copyOf(path, off + 1);
|
||||
}
|
||||
|
||||
private static int getParentOff(byte[] path) {
|
||||
int off = path.length - 1;
|
||||
if (off > 0 && path[off] == '/') // isDirectory
|
||||
off--;
|
||||
while (off > 0 && path[off] != '/') { off--; }
|
||||
if (off <= 0)
|
||||
return ROOTPATH;
|
||||
return Arrays.copyOf(path, off + 1);
|
||||
return off;
|
||||
}
|
||||
|
||||
private final void beginWrite() {
|
||||
@ -941,19 +939,6 @@ class ZipFileSystem extends FileSystem {
|
||||
close();
|
||||
}
|
||||
|
||||
private long getDataPos(Entry e) throws IOException {
|
||||
if (e.locoff == -1) {
|
||||
Entry e2 = getEntry(e.name);
|
||||
if (e2 == null)
|
||||
throw new ZipException("invalid loc for entry <" + e.name + ">");
|
||||
e.locoff = e2.locoff;
|
||||
}
|
||||
byte[] buf = new byte[LOCHDR];
|
||||
if (readFullyAt(buf, 0, buf.length, e.locoff) != buf.length)
|
||||
throw new ZipException("invalid loc for entry <" + e.name + ">");
|
||||
return locpos + e.locoff + LOCHDR + LOCNAM(buf) + LOCEXT(buf);
|
||||
}
|
||||
|
||||
// Reads len bytes of data from the specified offset into buf.
|
||||
// Returns the total number of bytes read.
|
||||
// Each/every byte read from here (except the cen, which is mapped).
|
||||
@ -1090,7 +1075,9 @@ class ZipFileSystem extends FileSystem {
|
||||
if (pos + CENHDR + nlen > limit) {
|
||||
zerror("invalid CEN header (bad header size)");
|
||||
}
|
||||
byte[] name = Arrays.copyOfRange(cen, pos + CENHDR, pos + CENHDR + nlen);
|
||||
byte[] name = new byte[nlen + 1];
|
||||
System.arraycopy(cen, pos + CENHDR, name, 1, nlen);
|
||||
name[0] = '/';
|
||||
IndexNode inode = new IndexNode(name, pos);
|
||||
inodes.put(inode, inode);
|
||||
// skip ext and comment
|
||||
@ -1278,7 +1265,7 @@ class ZipFileSystem extends FileSystem {
|
||||
if (inode.pos == -1) {
|
||||
continue; // pseudo directory node
|
||||
}
|
||||
e = Entry.readCEN(this, inode.pos);
|
||||
e = Entry.readCEN(this, inode);
|
||||
try {
|
||||
written += copyLOCEntry(e, false, os, written, buf);
|
||||
elist.add(e);
|
||||
@ -1320,13 +1307,6 @@ class ZipFileSystem extends FileSystem {
|
||||
|
||||
Files.move(tmpFile, zfpath, REPLACE_EXISTING);
|
||||
hasUpdate = false; // clear
|
||||
/*
|
||||
if (isOpen) {
|
||||
ch = zfpath.newByteChannel(READ); // re-fresh "ch" and "cen"
|
||||
cen = initCEN();
|
||||
}
|
||||
*/
|
||||
//System.out.printf("->sync(%s) done!%n", toString());
|
||||
}
|
||||
|
||||
IndexNode getInode(byte[] path) {
|
||||
@ -1350,7 +1330,7 @@ class ZipFileSystem extends FileSystem {
|
||||
return (Entry)inode;
|
||||
if (inode == null || inode.pos == -1)
|
||||
return null;
|
||||
return Entry.readCEN(this, inode.pos);
|
||||
return Entry.readCEN(this, inode);
|
||||
}
|
||||
|
||||
public void deleteFile(byte[] path, boolean failIfNotExists)
|
||||
@ -1432,7 +1412,6 @@ class ZipFileSystem extends FileSystem {
|
||||
bufSize = 8192;
|
||||
final long size = e.size;
|
||||
eis = new InflaterInputStream(eis, getInflater(), (int)bufSize) {
|
||||
|
||||
private boolean isClosed = false;
|
||||
public void close() throws IOException {
|
||||
if (!isClosed) {
|
||||
@ -1493,10 +1472,20 @@ class ZipFileSystem extends FileSystem {
|
||||
this.zfch = zfch;
|
||||
rem = e.csize;
|
||||
size = e.size;
|
||||
pos = getDataPos(e);
|
||||
pos = e.locoff;
|
||||
if (pos == -1) {
|
||||
Entry e2 = getEntry(e.name);
|
||||
if (e2 == null) {
|
||||
throw new ZipException("invalid loc for entry <" + e.name + ">");
|
||||
}
|
||||
pos = e2.locoff;
|
||||
}
|
||||
pos = -pos; // lazy initialize the real data offset
|
||||
}
|
||||
|
||||
public int read(byte b[], int off, int len) throws IOException {
|
||||
ensureOpen();
|
||||
initDataPos();
|
||||
if (rem == 0) {
|
||||
return -1;
|
||||
}
|
||||
@ -1523,6 +1512,7 @@ class ZipFileSystem extends FileSystem {
|
||||
}
|
||||
return (int)n;
|
||||
}
|
||||
|
||||
public int read() throws IOException {
|
||||
byte[] b = new byte[1];
|
||||
if (read(b, 0, 1) == 1) {
|
||||
@ -1531,6 +1521,7 @@ class ZipFileSystem extends FileSystem {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
public long skip(long n) throws IOException {
|
||||
ensureOpen();
|
||||
if (n > rem)
|
||||
@ -1542,16 +1533,30 @@ class ZipFileSystem extends FileSystem {
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
public int available() {
|
||||
return rem > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) rem;
|
||||
}
|
||||
|
||||
public long size() {
|
||||
return size;
|
||||
}
|
||||
|
||||
public void close() {
|
||||
rem = 0;
|
||||
streams.remove(this);
|
||||
}
|
||||
|
||||
private void initDataPos() throws IOException {
|
||||
if (pos <= 0) {
|
||||
pos = -pos + locpos;
|
||||
byte[] buf = new byte[LOCHDR];
|
||||
if (readFullyAt(buf, 0, buf.length, pos) != LOCHDR) {
|
||||
throw new ZipException("invalid loc " + pos + " for entry reading");
|
||||
}
|
||||
pos += LOCHDR + LOCNAM(buf) + LOCEXT(buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class EntryOutputStream extends DeflaterOutputStream
|
||||
@ -1701,8 +1706,9 @@ class ZipFileSystem extends FileSystem {
|
||||
|
||||
// End of central directory record
|
||||
static class END {
|
||||
int disknum;
|
||||
int sdisknum;
|
||||
// these 2 fields are not used by anyone and write() uses "0"
|
||||
// int disknum;
|
||||
// int sdisknum;
|
||||
int endsub; // endsub
|
||||
int centot; // 4 bytes
|
||||
long cenlen; // 4 bytes
|
||||
@ -1711,9 +1717,9 @@ class ZipFileSystem extends FileSystem {
|
||||
byte[] comment;
|
||||
|
||||
/* members of Zip64 end of central directory locator */
|
||||
int diskNum;
|
||||
// int diskNum;
|
||||
long endpos;
|
||||
int disktot;
|
||||
// int disktot;
|
||||
|
||||
void write(OutputStream os, long offset) throws IOException {
|
||||
boolean hasZip64 = false;
|
||||
@ -1776,6 +1782,11 @@ class ZipFileSystem extends FileSystem {
|
||||
int hashcode; // node is hashable/hashed by its name
|
||||
int pos = -1; // position in cen table, -1 menas the
|
||||
// entry does not exists in zip file
|
||||
IndexNode(byte[] name) {
|
||||
name(name);
|
||||
this.pos = -1;
|
||||
}
|
||||
|
||||
IndexNode(byte[] name, int pos) {
|
||||
name(name);
|
||||
this.pos = pos;
|
||||
@ -1804,6 +1815,9 @@ class ZipFileSystem extends FileSystem {
|
||||
if (!(other instanceof IndexNode)) {
|
||||
return false;
|
||||
}
|
||||
if (other instanceof ParentLookup) {
|
||||
return ((ParentLookup)other).equals(this);
|
||||
}
|
||||
return Arrays.equals(name, ((IndexNode)other).name);
|
||||
}
|
||||
|
||||
@ -1816,17 +1830,16 @@ class ZipFileSystem extends FileSystem {
|
||||
IndexNode child; // 1st child
|
||||
}
|
||||
|
||||
static class Entry extends IndexNode {
|
||||
static class Entry extends IndexNode implements ZipFileAttributes {
|
||||
|
||||
static final int CEN = 1; // entry read from cen
|
||||
static final int NEW = 2; // updated contents in bytes or file
|
||||
static final int FILECH = 3; // fch update in "file"
|
||||
static final int COPY = 4; // copy of a CEN entry
|
||||
static final int CEN = 1; // entry read from cen
|
||||
static final int NEW = 2; // updated contents in bytes or file
|
||||
static final int FILECH = 3; // fch update in "file"
|
||||
static final int COPY = 4; // copy of a CEN entry
|
||||
|
||||
|
||||
byte[] bytes; // updated content bytes
|
||||
Path file; // use tmp file to store bytes;
|
||||
int type = CEN; // default is the entry read from cen
|
||||
byte[] bytes; // updated content bytes
|
||||
Path file; // use tmp file to store bytes;
|
||||
int type = CEN; // default is the entry read from cen
|
||||
|
||||
// entry attributes
|
||||
int version;
|
||||
@ -1841,10 +1854,12 @@ class ZipFileSystem extends FileSystem {
|
||||
byte[] extra;
|
||||
|
||||
// cen
|
||||
int versionMade;
|
||||
int disk;
|
||||
int attrs;
|
||||
long attrsEx;
|
||||
|
||||
// these fields are not used by anyone and writeCEN uses "0"
|
||||
// int versionMade;
|
||||
// int disk;
|
||||
// int attrs;
|
||||
// long attrsEx;
|
||||
long locoff;
|
||||
byte[] comment;
|
||||
|
||||
@ -1875,10 +1890,12 @@ class ZipFileSystem extends FileSystem {
|
||||
this.csize = e.csize;
|
||||
this.method = e.method;
|
||||
this.extra = e.extra;
|
||||
/*
|
||||
this.versionMade = e.versionMade;
|
||||
this.disk = e.disk;
|
||||
this.attrs = e.attrs;
|
||||
this.attrsEx = e.attrsEx;
|
||||
*/
|
||||
this.locoff = e.locoff;
|
||||
this.comment = e.comment;
|
||||
this.type = type;
|
||||
@ -1899,19 +1916,19 @@ class ZipFileSystem extends FileSystem {
|
||||
}
|
||||
|
||||
///////////////////// CEN //////////////////////
|
||||
static Entry readCEN(ZipFileSystem zipfs, int pos)
|
||||
static Entry readCEN(ZipFileSystem zipfs, IndexNode inode)
|
||||
throws IOException
|
||||
{
|
||||
return new Entry().cen(zipfs, pos);
|
||||
return new Entry().cen(zipfs, inode);
|
||||
}
|
||||
|
||||
private Entry cen(ZipFileSystem zipfs, int pos)
|
||||
private Entry cen(ZipFileSystem zipfs, IndexNode inode)
|
||||
throws IOException
|
||||
{
|
||||
byte[] cen = zipfs.cen;
|
||||
int pos = inode.pos;
|
||||
if (!cenSigAt(cen, pos))
|
||||
zerror("invalid CEN header (bad signature)");
|
||||
versionMade = CENVEM(cen, pos);
|
||||
version = CENVER(cen, pos);
|
||||
flag = CENFLG(cen, pos);
|
||||
method = CENHOW(cen, pos);
|
||||
@ -1922,13 +1939,16 @@ class ZipFileSystem extends FileSystem {
|
||||
int nlen = CENNAM(cen, pos);
|
||||
int elen = CENEXT(cen, pos);
|
||||
int clen = CENCOM(cen, pos);
|
||||
/*
|
||||
versionMade = CENVEM(cen, pos);
|
||||
disk = CENDSK(cen, pos);
|
||||
attrs = CENATT(cen, pos);
|
||||
attrsEx = CENATX(cen, pos);
|
||||
*/
|
||||
locoff = CENOFF(cen, pos);
|
||||
|
||||
pos += CENHDR;
|
||||
name(Arrays.copyOfRange(cen, pos, pos + nlen));
|
||||
this.name = inode.name;
|
||||
this.hashcode = inode.hashcode;
|
||||
|
||||
pos += nlen;
|
||||
if (elen > 0) {
|
||||
@ -1955,7 +1975,8 @@ class ZipFileSystem extends FileSystem {
|
||||
boolean foundExtraTime = false; // if time stamp NTFS, EXTT present
|
||||
|
||||
// confirm size/length
|
||||
int nlen = (name != null) ? name.length : 0;
|
||||
|
||||
int nlen = (name != null) ? name.length - 1 : 0; // name has [0] as "slash"
|
||||
int elen = (extra != null) ? extra.length : 0;
|
||||
int eoff = 0;
|
||||
int clen = (comment != null) ? comment.length : 0;
|
||||
@ -2004,7 +2025,7 @@ class ZipFileSystem extends FileSystem {
|
||||
writeInt(os, crc); // crc-32
|
||||
writeInt(os, csize0); // compressed size
|
||||
writeInt(os, size0); // uncompressed size
|
||||
writeShort(os, name.length);
|
||||
writeShort(os, nlen);
|
||||
writeShort(os, elen + elen64 + elenNTFS + elenEXTT);
|
||||
|
||||
if (comment != null) {
|
||||
@ -2016,7 +2037,7 @@ class ZipFileSystem extends FileSystem {
|
||||
writeShort(os, 0); // internal file attributes (unused)
|
||||
writeInt(os, 0); // external file attributes (unused)
|
||||
writeInt(os, locoff0); // relative offset of local header
|
||||
writeBytes(os, name);
|
||||
writeBytes(os, name, 1, nlen);
|
||||
if (elen64 != 0) {
|
||||
writeShort(os, EXTID_ZIP64);// Zip64 extra
|
||||
writeShort(os, elen64 - 4); // size of "this" extra block
|
||||
@ -2086,8 +2107,9 @@ class ZipFileSystem extends FileSystem {
|
||||
int nlen = LOCNAM(buf);
|
||||
int elen = LOCEXT(buf);
|
||||
|
||||
name = new byte[nlen];
|
||||
if (zipfs.readFullyAt(name, 0, nlen, pos + LOCHDR) != nlen) {
|
||||
name = new byte[nlen + 1];
|
||||
name[0] = '/';
|
||||
if (zipfs.readFullyAt(name, 1, nlen, pos + LOCHDR) != nlen) {
|
||||
throw new ZipException("loc: name reading failed");
|
||||
}
|
||||
if (elen > 0) {
|
||||
@ -2130,12 +2152,10 @@ class ZipFileSystem extends FileSystem {
|
||||
return this;
|
||||
}
|
||||
|
||||
int writeLOC(OutputStream os)
|
||||
throws IOException
|
||||
{
|
||||
int writeLOC(OutputStream os) throws IOException {
|
||||
writeInt(os, LOCSIG); // LOC header signature
|
||||
int version = version();
|
||||
int nlen = (name != null) ? name.length : 0;
|
||||
int nlen = (name != null) ? name.length - 1 : 0; // [0] is slash
|
||||
int elen = (extra != null) ? extra.length : 0;
|
||||
boolean foundExtraTime = false; // if extra timestamp present
|
||||
int eoff = 0;
|
||||
@ -2192,9 +2212,9 @@ class ZipFileSystem extends FileSystem {
|
||||
elenEXTT += 4;
|
||||
}
|
||||
}
|
||||
writeShort(os, name.length);
|
||||
writeShort(os, nlen);
|
||||
writeShort(os, elen + elen64 + elenNTFS + elenEXTT);
|
||||
writeBytes(os, name);
|
||||
writeBytes(os, name, 1, nlen);
|
||||
if (elen64 != 0) {
|
||||
writeShort(os, EXTID_ZIP64);
|
||||
writeShort(os, 16);
|
||||
@ -2229,13 +2249,11 @@ class ZipFileSystem extends FileSystem {
|
||||
if (extra != null) {
|
||||
writeBytes(os, extra);
|
||||
}
|
||||
return LOCHDR + name.length + elen + elen64 + elenNTFS + elenEXTT;
|
||||
return LOCHDR + nlen + elen + elen64 + elenNTFS + elenEXTT;
|
||||
}
|
||||
|
||||
// Data Descriptior
|
||||
int writeEXT(OutputStream os)
|
||||
throws IOException
|
||||
{
|
||||
int writeEXT(OutputStream os) throws IOException {
|
||||
writeInt(os, EXTSIG); // EXT header signature
|
||||
writeInt(os, crc); // crc-32
|
||||
if (csize >= ZIP64_MINVAL || size >= ZIP64_MINVAL) {
|
||||
@ -2301,7 +2319,15 @@ class ZipFileSystem extends FileSystem {
|
||||
break;
|
||||
case EXTID_EXTT:
|
||||
// spec says the Extened timestamp in cen only has mtime
|
||||
// need to read the loc to get the extra a/ctime
|
||||
// need to read the loc to get the extra a/ctime, if flag
|
||||
// "zipinfo-time" is not specified to false;
|
||||
// there is performance cost (move up to loc and read) to
|
||||
// access the loc table foreach entry;
|
||||
if (zipfs.noExtt) {
|
||||
if (sz == 5)
|
||||
mtime = unixToJavaTime(LG(extra, pos + 1));
|
||||
break;
|
||||
}
|
||||
byte[] buf = new byte[LOCHDR];
|
||||
if (zipfs.readFullyAt(buf, 0, buf.length , locoff)
|
||||
!= buf.length)
|
||||
@ -2309,7 +2335,6 @@ class ZipFileSystem extends FileSystem {
|
||||
if (!locSigAt(buf, 0))
|
||||
throw new ZipException("loc: wrong sig ->"
|
||||
+ Long.toString(getSig(buf, 0), 16));
|
||||
|
||||
int locElen = LOCEXT(buf);
|
||||
if (locElen < 9) // EXTT is at lease 9 bytes
|
||||
break;
|
||||
@ -2354,6 +2379,96 @@ class ZipFileSystem extends FileSystem {
|
||||
else
|
||||
extra = null;
|
||||
}
|
||||
|
||||
///////// basic file attributes ///////////
|
||||
@Override
|
||||
public FileTime creationTime() {
|
||||
return FileTime.fromMillis(ctime == -1 ? mtime : ctime);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDirectory() {
|
||||
return isDir();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOther() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isRegularFile() {
|
||||
return !isDir();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileTime lastAccessTime() {
|
||||
return FileTime.fromMillis(atime == -1 ? mtime : atime);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileTime lastModifiedTime() {
|
||||
return FileTime.fromMillis(mtime);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long size() {
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSymbolicLink() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object fileKey() {
|
||||
return null;
|
||||
}
|
||||
|
||||
///////// zip entry attributes ///////////
|
||||
public long compressedSize() {
|
||||
return csize;
|
||||
}
|
||||
|
||||
public long crc() {
|
||||
return crc;
|
||||
}
|
||||
|
||||
public int method() {
|
||||
return method;
|
||||
}
|
||||
|
||||
public byte[] extra() {
|
||||
if (extra != null)
|
||||
return Arrays.copyOf(extra, extra.length);
|
||||
return null;
|
||||
}
|
||||
|
||||
public byte[] comment() {
|
||||
if (comment != null)
|
||||
return Arrays.copyOf(comment, comment.length);
|
||||
return null;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder(1024);
|
||||
Formatter fm = new Formatter(sb);
|
||||
fm.format(" creationTime : %tc%n", creationTime().toMillis());
|
||||
fm.format(" lastAccessTime : %tc%n", lastAccessTime().toMillis());
|
||||
fm.format(" lastModifiedTime: %tc%n", lastModifiedTime().toMillis());
|
||||
fm.format(" isRegularFile : %b%n", isRegularFile());
|
||||
fm.format(" isDirectory : %b%n", isDirectory());
|
||||
fm.format(" isSymbolicLink : %b%n", isSymbolicLink());
|
||||
fm.format(" isOther : %b%n", isOther());
|
||||
fm.format(" fileKey : %s%n", fileKey());
|
||||
fm.format(" size : %d%n", size());
|
||||
fm.format(" compressedSize : %d%n", compressedSize());
|
||||
fm.format(" crc : %x%n", crc());
|
||||
fm.format(" method : %d%n", method());
|
||||
fm.close();
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
private static class ExChannelCloser {
|
||||
@ -2379,25 +2494,8 @@ class ZipFileSystem extends FileSystem {
|
||||
// implemented below.
|
||||
private IndexNode root;
|
||||
|
||||
private void addToTree(IndexNode inode, HashSet<IndexNode> dirs) {
|
||||
if (dirs.contains(inode)) {
|
||||
return;
|
||||
}
|
||||
IndexNode parent;
|
||||
byte[] name = inode.name;
|
||||
byte[] pname = getParent(name);
|
||||
if (inodes.containsKey(LOOKUPKEY.as(pname))) {
|
||||
parent = inodes.get(LOOKUPKEY);
|
||||
} else { // pseudo directory entry
|
||||
parent = new IndexNode(pname, -1);
|
||||
inodes.put(parent, parent);
|
||||
}
|
||||
addToTree(parent, dirs);
|
||||
inode.sibling = parent.child;
|
||||
parent.child = inode;
|
||||
if (name[name.length -1] == '/')
|
||||
dirs.add(inode);
|
||||
}
|
||||
// default time stamp for pseudo entries
|
||||
private long zfsDefaultTimeStamp = System.currentTimeMillis();
|
||||
|
||||
private void removeFromTree(IndexNode inode) {
|
||||
IndexNode parent = inodes.get(LOOKUPKEY.as(getParent(inode.name)));
|
||||
@ -2417,15 +2515,69 @@ class ZipFileSystem extends FileSystem {
|
||||
}
|
||||
}
|
||||
|
||||
// purely for parent lookup, so we don't have to copy the parent
|
||||
// name every time
|
||||
static class ParentLookup extends IndexNode {
|
||||
int len;
|
||||
ParentLookup() {}
|
||||
|
||||
final ParentLookup as(byte[] name, int len) { // as a lookup "key"
|
||||
name(name, len);
|
||||
return this;
|
||||
}
|
||||
|
||||
void name(byte[] name, int len) {
|
||||
this.name = name;
|
||||
this.len = len;
|
||||
// calculate the hashcode the same way as Arrays.hashCode() does
|
||||
int result = 1;
|
||||
for (int i = 0; i < len; i++)
|
||||
result = 31 * result + name[i];
|
||||
this.hashcode = result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
if (!(other instanceof IndexNode)) {
|
||||
return false;
|
||||
}
|
||||
byte[] oname = ((IndexNode)other).name;
|
||||
return Arrays.equals(name, 0, len,
|
||||
oname, 0, oname.length);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void buildNodeTree() throws IOException {
|
||||
beginWrite();
|
||||
try {
|
||||
HashSet<IndexNode> dirs = new HashSet<>();
|
||||
IndexNode root = new IndexNode(ROOTPATH, -1);
|
||||
IndexNode root = new IndexNode(ROOTPATH);
|
||||
IndexNode[] nodes = inodes.keySet().toArray(new IndexNode[0]);
|
||||
inodes.put(root, root);
|
||||
dirs.add(root);
|
||||
for (IndexNode node : inodes.keySet().toArray(new IndexNode[0])) {
|
||||
addToTree(node, dirs);
|
||||
ParentLookup lookup = new ParentLookup();
|
||||
for (IndexNode node : nodes) {
|
||||
IndexNode parent;
|
||||
while (true) {
|
||||
int off = getParentOff(node.name);
|
||||
if (off <= 1) { // parent is root
|
||||
node.sibling = root.child;
|
||||
root.child = node;
|
||||
break;
|
||||
}
|
||||
lookup = lookup.as(node.name, off + 1);
|
||||
if (inodes.containsKey(lookup)) {
|
||||
parent = inodes.get(lookup);
|
||||
node.sibling = parent.child;
|
||||
parent.child = node;
|
||||
break;
|
||||
}
|
||||
// add new pseudo directory entry
|
||||
parent = new IndexNode(Arrays.copyOf(node.name, off + 1));
|
||||
inodes.put(parent, parent);
|
||||
node.sibling = parent.child;
|
||||
parent.child = node;
|
||||
node = parent;
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
endWrite();
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user