nsmClass)
throws IllegalAccessException, NoSuchMemberException {
- MemberName result = resolve(refKind, m, lookupClass);
+ MemberName result = resolve(refKind, m, lookupClass, false);
if (result.isResolved())
return result;
ReflectiveOperationException ex = result.makeAccessException();
@@ -1106,8 +1110,8 @@ MemberName resolveOrFail(byte refKind, MemberName m, Class> lookupClass,
*/
public
MemberName resolveOrNull(byte refKind, MemberName m, Class> lookupClass) {
- MemberName result = resolve(refKind, m, lookupClass);
- if (result.isResolved())
+ MemberName result = resolve(refKind, m, lookupClass, true);
+ if (result != null && result.isResolved())
return result;
return null;
}
diff --git a/src/java.base/share/classes/java/lang/invoke/MethodHandleNatives.java b/src/java.base/share/classes/java/lang/invoke/MethodHandleNatives.java
index c288f6d7a57..3e872414b6c 100644
--- a/src/java.base/share/classes/java/lang/invoke/MethodHandleNatives.java
+++ b/src/java.base/share/classes/java/lang/invoke/MethodHandleNatives.java
@@ -49,7 +49,8 @@ private MethodHandleNatives() { } // static only
static native void init(MemberName self, Object ref);
static native void expand(MemberName self);
- static native MemberName resolve(MemberName self, Class> caller) throws LinkageError, ClassNotFoundException;
+ static native MemberName resolve(MemberName self, Class> caller,
+ boolean speculativeResolve) throws LinkageError, ClassNotFoundException;
static native int getMembers(Class> defc, String matchName, String matchSig,
int matchFlags, Class> caller, int skip, MemberName[] results);
diff --git a/src/java.base/share/classes/java/lang/invoke/MethodHandles.java b/src/java.base/share/classes/java/lang/invoke/MethodHandles.java
index e0d078dcc1f..0277a8e24e2 100644
--- a/src/java.base/share/classes/java/lang/invoke/MethodHandles.java
+++ b/src/java.base/share/classes/java/lang/invoke/MethodHandles.java
@@ -5893,6 +5893,19 @@ private static Class> iteratedLoopChecks(MethodHandle iterator, MethodHandle i
* In rare cases where exceptions must be converted in that way, first wrap
* the target with {@link #catchException(MethodHandle, Class, MethodHandle)}
* to capture an outgoing exception, and then wrap with {@code tryFinally}.
+ *
+ * It is recommended that the first parameter type of {@code cleanup} be
+ * declared {@code Throwable} rather than a narrower subtype. This ensures
+ * {@code cleanup} will always be invoked with whatever exception that
+ * {@code target} throws. Declaring a narrower type may result in a
+ * {@code ClassCastException} being thrown by the {@code try-finally}
+ * handle if the type of the exception thrown by {@code target} is not
+ * assignable to the first parameter type of {@code cleanup}. Note that
+ * various exception types of {@code VirtualMachineError},
+ * {@code LinkageError}, and {@code RuntimeException} can in principle be
+ * thrown by almost any kind of Java code, and a finally clause that
+ * catches (say) only {@code IOException} would mask any of the others
+ * behind a {@code ClassCastException}.
*
* @param target the handle whose execution is to be wrapped in a {@code try} block.
* @param cleanup the handle that is invoked in the finally block.
@@ -5909,7 +5922,6 @@ private static Class> iteratedLoopChecks(MethodHandle iterator, MethodHandle i
*/
public static MethodHandle tryFinally(MethodHandle target, MethodHandle cleanup) {
List> targetParamTypes = target.type().parameterList();
- List> cleanupParamTypes = cleanup.type().parameterList();
Class> rtype = target.type().returnType();
tryFinallyChecks(target, cleanup);
@@ -5919,6 +5931,10 @@ public static MethodHandle tryFinally(MethodHandle target, MethodHandle cleanup)
// target parameter list.
cleanup = dropArgumentsToMatch(cleanup, (rtype == void.class ? 1 : 2), targetParamTypes, 0);
+ // Ensure that the intrinsic type checks the instance thrown by the
+ // target against the first parameter of cleanup
+ cleanup = cleanup.asType(cleanup.type().changeParameterType(0, Throwable.class));
+
// Use asFixedArity() to avoid unnecessary boxing of last argument for VarargsCollector case.
return MethodHandleImpl.makeTryFinally(target.asFixedArity(), cleanup.asFixedArity(), rtype, targetParamTypes);
}
diff --git a/src/java.base/share/classes/java/lang/invoke/MethodType.java b/src/java.base/share/classes/java/lang/invoke/MethodType.java
index f3346bc21c6..620404c8782 100644
--- a/src/java.base/share/classes/java/lang/invoke/MethodType.java
+++ b/src/java.base/share/classes/java/lang/invoke/MethodType.java
@@ -1206,33 +1206,24 @@ private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOExceptio
* @param s the stream to read the object from
* @throws java.io.IOException if there is a problem reading the object
* @throws ClassNotFoundException if one of the component classes cannot be resolved
- * @see #MethodType()
* @see #readResolve
* @see #writeObject
*/
private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException {
+ // Assign temporary defaults in case this object escapes
+ MethodType_init(void.class, NO_PTYPES);
+
s.defaultReadObject(); // requires serialPersistentFields to be an empty array
Class> returnType = (Class>) s.readObject();
Class>[] parameterArray = (Class>[]) s.readObject();
-
- // Probably this object will never escape, but let's check
- // the field values now, just to be sure.
- checkRtype(returnType);
- checkPtypes(parameterArray);
-
parameterArray = parameterArray.clone(); // make sure it is unshared
+
+ // Assign deserialized values
MethodType_init(returnType, parameterArray);
}
- /**
- * For serialization only.
- * Sets the final fields to null, pending {@code Unsafe.putObject}.
- */
- private MethodType() {
- this.rtype = null;
- this.ptypes = null;
- }
+ // Initialization of state for deserialization only
private void MethodType_init(Class> rtype, Class>[] ptypes) {
// In order to communicate these values to readResolve, we must
// store them into the implementation-specific final fields.
@@ -1259,9 +1250,14 @@ private static class OffsetHolder {
*/
private Object readResolve() {
// Do not use a trusted path for deserialization:
- //return makeImpl(rtype, ptypes, true);
+ // return makeImpl(rtype, ptypes, true);
// Verify all operands, and make sure ptypes is unshared:
- return methodType(rtype, ptypes);
+ try {
+ return methodType(rtype, ptypes);
+ } finally {
+ // Re-assign defaults in case this object escapes
+ MethodType_init(void.class, NO_PTYPES);
+ }
}
/**
diff --git a/src/java.base/share/classes/java/lang/invoke/VarHandle.java b/src/java.base/share/classes/java/lang/invoke/VarHandle.java
index 1b4e1a975ff..d6eca54cc0d 100644
--- a/src/java.base/share/classes/java/lang/invoke/VarHandle.java
+++ b/src/java.base/share/classes/java/lang/invoke/VarHandle.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -1788,10 +1788,12 @@ public enum AccessMode {
static final Map methodNameToAccessMode;
static {
- // Initial capacity of # values is sufficient to avoid resizes
- // for the smallest table size (32)
- methodNameToAccessMode = new HashMap<>(AccessMode.values().length);
- for (AccessMode am : AccessMode.values()) {
+ AccessMode[] values = AccessMode.values();
+ // Initial capacity of # values divided by the load factor is sufficient
+ // to avoid resizes for the smallest table size (64)
+ int initialCapacity = (int)(values.length / 0.75f) + 1;
+ methodNameToAccessMode = new HashMap<>(initialCapacity);
+ for (AccessMode am : values) {
methodNameToAccessMode.put(am.methodName, am);
}
}
diff --git a/src/java.base/share/classes/java/lang/invoke/X-VarHandle.java.template b/src/java.base/share/classes/java/lang/invoke/X-VarHandle.java.template
index 71419c36548..505a8dad470 100644
--- a/src/java.base/share/classes/java/lang/invoke/X-VarHandle.java.template
+++ b/src/java.base/share/classes/java/lang/invoke/X-VarHandle.java.template
@@ -592,6 +592,28 @@ final class VarHandle$Type$s {
return accessMode.at.accessModeType({#if[Object]?arrayType:$type$[].class}, {#if[Object]?arrayType.getComponentType():$type$.class}, int.class);
}
+#if[Object]
+ @ForceInline
+ static Object runtimeTypeCheck(Array handle, Object[] oarray, Object value) {
+ if (handle.arrayType == oarray.getClass()) {
+ // Fast path: static array type same as argument array type
+ return handle.componentType.cast(value);
+ } else {
+ // Slow path: check value against argument array component type
+ return reflectiveTypeCheck(oarray, value);
+ }
+ }
+
+ @ForceInline
+ static Object reflectiveTypeCheck(Object[] oarray, Object value) {
+ try {
+ return oarray.getClass().getComponentType().cast(value);
+ } catch (ClassCastException e) {
+ throw new ArrayStoreException();
+ }
+ }
+#end[Object]
+
@ForceInline
static $type$ get(Array handle, Object oarray, int index) {
#if[Object]
@@ -632,7 +654,7 @@ final class VarHandle$Type$s {
#end[Object]
UNSAFE.put$Type$Volatile(array,
(((long) Preconditions.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase,
- {#if[Object]?handle.componentType.cast(value):value});
+ {#if[Object]?runtimeTypeCheck(handle, array, value):value});
}
@ForceInline
@@ -655,7 +677,7 @@ final class VarHandle$Type$s {
#end[Object]
UNSAFE.put$Type$Opaque(array,
(((long) Preconditions.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase,
- {#if[Object]?handle.componentType.cast(value):value});
+ {#if[Object]?runtimeTypeCheck(handle, array, value):value});
}
@ForceInline
@@ -678,7 +700,7 @@ final class VarHandle$Type$s {
#end[Object]
UNSAFE.put$Type$Release(array,
(((long) Preconditions.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase,
- {#if[Object]?handle.componentType.cast(value):value});
+ {#if[Object]?runtimeTypeCheck(handle, array, value):value});
}
#if[CAS]
@@ -692,7 +714,7 @@ final class VarHandle$Type$s {
return UNSAFE.compareAndSet$Type$(array,
(((long) Preconditions.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase,
{#if[Object]?handle.componentType.cast(expected):expected},
- {#if[Object]?handle.componentType.cast(value):value});
+ {#if[Object]?runtimeTypeCheck(handle, array, value):value});
}
@ForceInline
@@ -705,7 +727,7 @@ final class VarHandle$Type$s {
return UNSAFE.compareAndExchange$Type$(array,
(((long) Preconditions.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase,
{#if[Object]?handle.componentType.cast(expected):expected},
- {#if[Object]?handle.componentType.cast(value):value});
+ {#if[Object]?runtimeTypeCheck(handle, array, value):value});
}
@ForceInline
@@ -718,7 +740,7 @@ final class VarHandle$Type$s {
return UNSAFE.compareAndExchange$Type$Acquire(array,
(((long) Preconditions.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase,
{#if[Object]?handle.componentType.cast(expected):expected},
- {#if[Object]?handle.componentType.cast(value):value});
+ {#if[Object]?runtimeTypeCheck(handle, array, value):value});
}
@ForceInline
@@ -731,7 +753,7 @@ final class VarHandle$Type$s {
return UNSAFE.compareAndExchange$Type$Release(array,
(((long) Preconditions.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase,
{#if[Object]?handle.componentType.cast(expected):expected},
- {#if[Object]?handle.componentType.cast(value):value});
+ {#if[Object]?runtimeTypeCheck(handle, array, value):value});
}
@ForceInline
@@ -744,7 +766,7 @@ final class VarHandle$Type$s {
return UNSAFE.weakCompareAndSet$Type$Plain(array,
(((long) Preconditions.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase,
{#if[Object]?handle.componentType.cast(expected):expected},
- {#if[Object]?handle.componentType.cast(value):value});
+ {#if[Object]?runtimeTypeCheck(handle, array, value):value});
}
@ForceInline
@@ -757,7 +779,7 @@ final class VarHandle$Type$s {
return UNSAFE.weakCompareAndSet$Type$(array,
(((long) Preconditions.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase,
{#if[Object]?handle.componentType.cast(expected):expected},
- {#if[Object]?handle.componentType.cast(value):value});
+ {#if[Object]?runtimeTypeCheck(handle, array, value):value});
}
@ForceInline
@@ -770,7 +792,7 @@ final class VarHandle$Type$s {
return UNSAFE.weakCompareAndSet$Type$Acquire(array,
(((long) Preconditions.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase,
{#if[Object]?handle.componentType.cast(expected):expected},
- {#if[Object]?handle.componentType.cast(value):value});
+ {#if[Object]?runtimeTypeCheck(handle, array, value):value});
}
@ForceInline
@@ -783,7 +805,7 @@ final class VarHandle$Type$s {
return UNSAFE.weakCompareAndSet$Type$Release(array,
(((long) Preconditions.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase,
{#if[Object]?handle.componentType.cast(expected):expected},
- {#if[Object]?handle.componentType.cast(value):value});
+ {#if[Object]?runtimeTypeCheck(handle, array, value):value});
}
@ForceInline
@@ -795,7 +817,7 @@ final class VarHandle$Type$s {
#end[Object]
return UNSAFE.getAndSet$Type$(array,
(((long) Preconditions.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase,
- {#if[Object]?handle.componentType.cast(value):value});
+ {#if[Object]?runtimeTypeCheck(handle, array, value):value});
}
@ForceInline
@@ -807,7 +829,7 @@ final class VarHandle$Type$s {
#end[Object]
return UNSAFE.getAndSet$Type$Acquire(array,
(((long) Preconditions.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase,
- {#if[Object]?handle.componentType.cast(value):value});
+ {#if[Object]?runtimeTypeCheck(handle, array, value):value});
}
@ForceInline
@@ -819,7 +841,7 @@ final class VarHandle$Type$s {
#end[Object]
return UNSAFE.getAndSet$Type$Release(array,
(((long) Preconditions.checkIndex(index, array.length, AIOOBE_SUPPLIER)) << handle.ashift) + handle.abase,
- {#if[Object]?handle.componentType.cast(value):value});
+ {#if[Object]?runtimeTypeCheck(handle, array, value):value});
}
#end[CAS]
#if[AtomicAdd]
diff --git a/src/java.base/share/classes/java/lang/invoke/package-info.java b/src/java.base/share/classes/java/lang/invoke/package-info.java
index 48c24f8a4cb..0aec94f2aa3 100644
--- a/src/java.base/share/classes/java/lang/invoke/package-info.java
+++ b/src/java.base/share/classes/java/lang/invoke/package-info.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -122,8 +122,11 @@
* On success the call site then becomes permanently linked to the {@code invokedynamic}
* instruction.
*
- * For a dynamically-computed constant, the result of the bootstrap method is cached
- * as the resolved constant value.
+ * For a dynamically-computed constant, the first parameter of the bootstrap
+ * method must be assignable to {@code MethodHandles.Lookup}. If this condition
+ * is not met, a {@code BootstrapMethodError} is thrown.
+ * On success the result of the bootstrap method is cached as the resolved
+ * constant value.
*
* If an exception, {@code E} say, occurs during execution of the bootstrap method, then
* resolution fails and terminates abnormally. {@code E} is rethrown if the type of
@@ -171,16 +174,25 @@
*
Types of bootstrap methods
* For a dynamically-computed call site, the bootstrap method is invoked with parameter
* types {@code MethodHandles.Lookup}, {@code String}, {@code MethodType}, and the types
- * of any static arguments; the return type is {@code CallSite}. For a
- * dynamically-computed constant, the bootstrap method is invoked with parameter types
+ * of any static arguments; the return type is {@code CallSite}.
+ *
+ * For a dynamically-computed constant, the bootstrap method is invoked with parameter types
* {@code MethodHandles.Lookup}, {@code String}, {@code Class}, and the types of any
* static arguments; the return type is the type represented by the {@code Class}.
- *
+ *
* Because {@link java.lang.invoke.MethodHandle#invoke MethodHandle.invoke} allows for
- * adaptations between the invoked method type and the method handle's method type,
+ * adaptations between the invoked method type and the bootstrap method handle's method type,
* there is flexibility in the declaration of the bootstrap method.
- * For example, the first argument could be {@code Object}
- * instead of {@code MethodHandles.Lookup}, and the return type
+ * For a dynamically-computed constant the first parameter type of the bootstrap method handle
+ * must be assignable to {@code MethodHandles.Lookup}, other than that constraint the same degree
+ * of flexibility applies to bootstrap methods of dynamically-computed call sites and
+ * dynamically-computed constants.
+ * Note: this constraint allows for the future possibility where the bootstrap method is
+ * invoked with just the parameter types of static arguments, thereby supporting a wider
+ * range of methods compatible with the static arguments (such as methods that don't declare
+ * or require the lookup, name, and type meta-data parameters).
+ *
For example, for dynamically-computed call site, a the first argument
+ * could be {@code Object} instead of {@code MethodHandles.Lookup}, and the return type
* could also be {@code Object} instead of {@code CallSite}.
* (Note that the types and number of the stacked arguments limit
* the legal kinds of bootstrap methods to appropriately typed
@@ -227,7 +239,10 @@
* {@code String} and {@code Integer} (or {@code int}), respectively.
* The second-to-last example assumes that all extra arguments are of type
* {@code String}.
- * The other examples work with all types of extra arguments.
+ * The other examples work with all types of extra arguments. Note that all
+ * the examples except the second and third also work with dynamically-computed
+ * constants if the return type is changed to be compatible with the
+ * constant's declared type (such as {@code Object}, which is always compatible).
*
* Since dynamically-computed constants can be provided as static arguments to bootstrap
* methods, there are no limitations on the types of bootstrap arguments.
diff --git a/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java b/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java
index 626c5200606..cb578423cba 100644
--- a/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java
+++ b/src/java.base/share/classes/java/lang/module/ModuleDescriptor.java
@@ -1742,7 +1742,7 @@ public Builder exports(Set ms,
throw new IllegalArgumentException("Empty target set");
if (strict) {
requirePackageName(e.source());
- targets.stream().forEach(Checks::requireModuleName);
+ targets.forEach(Checks::requireModuleName);
}
return exports(e);
}
@@ -1878,7 +1878,7 @@ public Builder opens(Set ms,
throw new IllegalArgumentException("Empty target set");
if (strict) {
requirePackageName(opens.source());
- targets.stream().forEach(Checks::requireModuleName);
+ targets.forEach(Checks::requireModuleName);
}
return opens(opens);
}
diff --git a/src/java.base/share/classes/java/lang/reflect/Proxy.java b/src/java.base/share/classes/java/lang/reflect/Proxy.java
index 27d33a83d17..456527dd19b 100644
--- a/src/java.base/share/classes/java/lang/reflect/Proxy.java
+++ b/src/java.base/share/classes/java/lang/reflect/Proxy.java
@@ -593,8 +593,7 @@ static void trace(String cn,
module.getName(), cn, loader);
}
if (isDebug("debug")) {
- interfaces.stream()
- .forEach(c -> System.out.println(toDetails(c)));
+ interfaces.forEach(c -> System.out.println(toDetails(c)));
}
}
diff --git a/src/java.base/share/classes/java/net/CookieHandler.java b/src/java.base/share/classes/java/net/CookieHandler.java
index af4c813926b..922eaf5bd21 100644
--- a/src/java.base/share/classes/java/net/CookieHandler.java
+++ b/src/java.base/share/classes/java/net/CookieHandler.java
@@ -36,9 +36,9 @@
* handler. The HTTP state management mechanism specifies a way to
* create a stateful session with HTTP requests and responses.
*
- * A system-wide CookieHandler that to used by the HTTP protocol
- * handler can be registered by doing a
- * CookieHandler.setDefault(CookieHandler). The currently registered
+ *
A system-wide CookieHandler to be used by the {@linkplain
+ * HttpURLConnection HTTP URL stream protocol handler} can be registered by
+ * doing a CookieHandler.setDefault(CookieHandler). The currently registered
* CookieHandler can be retrieved by calling
* CookieHandler.getDefault().
*
diff --git a/src/java.base/share/classes/java/net/InetAddress.java b/src/java.base/share/classes/java/net/InetAddress.java
index 84a0c578f5f..044f326e6eb 100644
--- a/src/java.base/share/classes/java/net/InetAddress.java
+++ b/src/java.base/share/classes/java/net/InetAddress.java
@@ -290,7 +290,10 @@ InetAddressHolder holder() {
/* Used to store the name service provider */
private static transient NameService nameService = null;
- /* Used to store the best available hostname */
+ /**
+ * Used to store the best available hostname.
+ * Lazily initialized via a data race; safe because Strings are immutable.
+ */
private transient String canonicalHostName = null;
/** use serialVersionUID from JDK 1.0.2 for interoperability */
@@ -622,11 +625,11 @@ String getHostName(boolean check) {
* @since 1.4
*/
public String getCanonicalHostName() {
- if (canonicalHostName == null) {
- canonicalHostName =
+ String value = canonicalHostName;
+ if (value == null)
+ canonicalHostName = value =
InetAddress.getHostFromNameService(this, true);
- }
- return canonicalHostName;
+ return value;
}
/**
diff --git a/src/java.base/share/classes/java/net/URL.java b/src/java.base/share/classes/java/net/URL.java
index 2917be133bd..e8af5b528cb 100644
--- a/src/java.base/share/classes/java/net/URL.java
+++ b/src/java.base/share/classes/java/net/URL.java
@@ -1411,7 +1411,7 @@ static URLStreamHandler getURLStreamHandler(String protocol) {
// Check with factory if another thread set a
// factory since our last check
if (!checkedWithFactory && (fac = factory) != null) {
- handler2 = fac.createURLStreamHandler(protocol);
+ handler2 = fac.createURLStreamHandler(protocol);
}
if (handler2 != null) {
diff --git a/src/java.base/share/classes/java/net/URLClassLoader.java b/src/java.base/share/classes/java/net/URLClassLoader.java
index fb7f6520c67..8d96985ce85 100644
--- a/src/java.base/share/classes/java/net/URLClassLoader.java
+++ b/src/java.base/share/classes/java/net/URLClassLoader.java
@@ -983,7 +983,7 @@ protected PermissionCollection getPermissions(CodeSource codesource)
path = ParseUtil.decode(path);
if (path.endsWith(File.separator))
path += "-";
- p = new FilePermission(path, SecurityConstants.FILE_READ_ACTION);
+ p = new FilePermission(path, SecurityConstants.FILE_READ_ACTION);
} else {
/**
* Not loading from a 'file:' URL so we want to give the class
diff --git a/src/java.base/share/classes/java/net/doc-files/net-properties.html b/src/java.base/share/classes/java/net/doc-files/net-properties.html
index acf653ebaed..19ba9a5f78f 100644
--- a/src/java.base/share/classes/java/net/doc-files/net-properties.html
+++ b/src/java.base/share/classes/java/net/doc-files/net-properties.html
@@ -1,6 +1,6 @@
-
- true/PM
+
+ true/PM
+ PerMonitorV2, PerMonitor, system
diff --git a/src/java.base/windows/native/libjava/Console_md.c b/src/java.base/windows/native/libjava/Console_md.c
index 173b2ffeb4a..d3c74343b0b 100644
--- a/src/java.base/windows/native/libjava/Console_md.c
+++ b/src/java.base/windows/native/libjava/Console_md.c
@@ -82,3 +82,14 @@ Java_java_io_Console_echo(JNIEnv *env, jclass cls, jboolean on)
}
return old;
}
+
+JNIEXPORT jboolean JNICALL
+Java_java_io_Console_echo0(JNIEnv *env, jclass cls)
+{
+ DWORD fdwMode;
+ if (! GetConsoleMode(hStdIn, &fdwMode)) {
+ JNU_ThrowIOExceptionWithLastError(env, "GetConsoleMode failed");
+ return JNI_TRUE;
+ }
+ return (fdwMode & ENABLE_ECHO_INPUT) != 0;
+}
diff --git a/src/java.base/windows/native/libjimage/osSupport_windows.cpp b/src/java.base/windows/native/libjimage/osSupport_windows.cpp
index fff5468c191..97e074bb0f4 100644
--- a/src/java.base/windows/native/libjimage/osSupport_windows.cpp
+++ b/src/java.base/windows/native/libjimage/osSupport_windows.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -38,7 +38,8 @@
* Return the file descriptor.
*/
jint osSupport::openReadOnly(const char *path) {
- return ::open(path, 0, 0);
+ // jimage file descriptors must not be inherited by child processes
+ return ::open(path, O_BINARY | O_NOINHERIT, O_RDONLY);
}
/**
diff --git a/src/java.base/windows/native/libnet/DualStackPlainSocketImpl.c b/src/java.base/windows/native/libnet/DualStackPlainSocketImpl.c
index 0ae73f3f761..73c226efff2 100644
--- a/src/java.base/windows/native/libnet/DualStackPlainSocketImpl.c
+++ b/src/java.base/windows/native/libnet/DualStackPlainSocketImpl.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -27,8 +27,8 @@
#include "java_net_DualStackPlainSocketImpl.h"
#include "java_net_SocketOptions.h"
-#define SET_BLOCKING 0
-#define SET_NONBLOCKING 1
+#define SET_BLOCKING 0
+#define SET_NONBLOCKING 1
static jclass isa_class; /* java.net.InetSocketAddress */
static jmethodID isa_ctorID; /* InetSocketAddress(InetAddress, int) */
@@ -60,22 +60,28 @@ JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_initIDs
* Signature: (ZZ)I
*/
JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_socket0
- (JNIEnv *env, jclass clazz, jboolean stream, jboolean v6Only /*unused*/) {
+ (JNIEnv *env, jclass clazz, jboolean stream) {
int fd, rv, opt=0;
+ int type = (stream ? SOCK_STREAM : SOCK_DGRAM);
+ int domain = ipv6_available() ? AF_INET6 : AF_INET;
+
+ fd = NET_Socket(domain, type, 0);
- fd = NET_Socket(AF_INET6, (stream ? SOCK_STREAM : SOCK_DGRAM), 0);
if (fd == INVALID_SOCKET) {
NET_ThrowNew(env, WSAGetLastError(), "create");
return -1;
}
- rv = setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &opt, sizeof(opt));
- if (rv == SOCKET_ERROR) {
- NET_ThrowNew(env, WSAGetLastError(), "create");
+ if (domain == AF_INET6) {
+ rv = setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &opt,
+ sizeof(opt));
+ if (rv == SOCKET_ERROR) {
+ NET_ThrowNew(env, WSAGetLastError(), "create");
+ closesocket(fd);
+ return -1;
+ }
}
- SetHandleInformation((HANDLE)(UINT_PTR)fd, HANDLE_FLAG_INHERIT, FALSE);
-
return fd;
}
@@ -90,10 +96,11 @@ JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_bind0
{
SOCKETADDRESS sa;
int rv, sa_len = 0;
+ jboolean v4MappedAddress = ipv6_available() ? JNI_TRUE : JNI_FALSE;
if (NET_InetAddressToSockaddr(env, iaObj, port, &sa,
- &sa_len, JNI_TRUE) != 0) {
- return;
+ &sa_len, v4MappedAddress) != 0) {
+ return;
}
rv = NET_WinBind(fd, &sa, sa_len, exclBind);
@@ -111,10 +118,11 @@ JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_connect0
(JNIEnv *env, jclass clazz, jint fd, jobject iaObj, jint port) {
SOCKETADDRESS sa;
int rv, sa_len = 0;
+ jboolean v4MappedAddress = ipv6_available() ? JNI_TRUE : JNI_FALSE;
if (NET_InetAddressToSockaddr(env, iaObj, port, &sa,
- &sa_len, JNI_TRUE) != 0) {
- return -1;
+ &sa_len, v4MappedAddress) != 0) {
+ return -1;
}
rv = connect(fd, &sa.sa, sa_len);
@@ -124,7 +132,8 @@ JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_connect0
return java_net_DualStackPlainSocketImpl_WOULDBLOCK;
} else if (err == WSAEADDRNOTAVAIL) {
JNU_ThrowByName(env, JNU_JAVANETPKG "ConnectException",
- "connect: Address is invalid on local machine, or port is not valid on remote machine");
+ "connect: Address is invalid on local machine,"
+ " or port is not valid on remote machine");
} else {
NET_ThrowNew(env, err, "connect");
}
@@ -200,6 +209,10 @@ JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_waitForConnect
if (rv == 0) {
JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
"Unable to establish connection");
+ } else if (!ipv6_available() && rv == WSAEADDRNOTAVAIL) {
+ JNU_ThrowByName(env, JNU_JAVANETPKG "ConnectException",
+ "connect: Address is invalid on local machine,"
+ " or port is not valid on remote machine");
} else {
NET_ThrowNew(env, rv, "connect");
}
@@ -284,13 +297,7 @@ JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_accept0
newfd = accept(fd, &sa.sa, &len);
if (newfd == INVALID_SOCKET) {
- if (WSAGetLastError() == -2) {
- JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
- "operation interrupted");
- } else {
- JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
- "socket closed");
- }
+ NET_ThrowNew(env, WSAGetLastError(), "accept failed");
return -1;
}
@@ -298,6 +305,10 @@ JNIEXPORT jint JNICALL Java_java_net_DualStackPlainSocketImpl_accept0
ia = NET_SockaddrToInetAddress(env, &sa, &port);
isa = (*env)->NewObject(env, isa_class, isa_ctorID, ia, port);
+ if (isa == NULL) {
+ closesocket(newfd);
+ return -1;
+ }
(*env)->SetObjectArrayElement(env, isaa, 0, isa);
return newfd;
@@ -400,6 +411,51 @@ Java_java_net_DualStackPlainSocketImpl_setIntOption
}
}
+/*
+ * Class: java_net_DualStackPlainSocketImpl
+ * Method: setSoTimeout0
+ * Signature: (II)V
+ */
+JNIEXPORT void JNICALL
+Java_java_net_DualStackPlainSocketImpl_setSoTimeout0
+ (JNIEnv *env, jclass clazz, jint fd, jint timeout)
+{
+ /*
+ * SO_TIMEOUT is the socket option used to specify the timeout
+ * for ServerSocket.accept and Socket.getInputStream().read.
+ * It does not typically map to a native level socket option.
+ * For Windows we special-case this and use the SOL_SOCKET/SO_RCVTIMEO
+ * socket option to specify a receive timeout on the socket. This
+ * receive timeout is applicable to Socket only and the socket
+ * option should not be set on ServerSocket.
+ */
+
+ /*
+ * SO_RCVTIMEO is only supported on Microsoft's implementation
+ * of Windows Sockets so if WSAENOPROTOOPT returned then
+ * reset flag and timeout will be implemented using
+ * select() -- see SocketInputStream.socketRead.
+ */
+ if (isRcvTimeoutSupported) {
+ /*
+ * Disable SO_RCVTIMEO if timeout is <= 5 second.
+ */
+ if (timeout <= 5000) {
+ timeout = 0;
+ }
+
+ if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout,
+ sizeof(timeout)) < 0) {
+ int err = WSAGetLastError();
+ if (err == WSAENOPROTOOPT) {
+ isRcvTimeoutSupported = JNI_FALSE;
+ } else {
+ NET_ThrowNew(env, err, "setsockopt SO_RCVTIMEO");
+ }
+ }
+ }
+}
+
/*
* Class: java_net_DualStackPlainSocketImpl
* Method: getIntOption
@@ -466,7 +522,7 @@ JNIEXPORT void JNICALL Java_java_net_DualStackPlainSocketImpl_configureBlocking
int result;
if (blocking == JNI_TRUE) {
- arg = SET_BLOCKING; // 0
+ arg = SET_BLOCKING; // 0
} else {
arg = SET_NONBLOCKING; // 1
}
diff --git a/src/java.base/windows/native/libnet/TwoStacksPlainSocketImpl.c b/src/java.base/windows/native/libnet/TwoStacksPlainSocketImpl.c
deleted file mode 100644
index 23c424bcda8..00000000000
--- a/src/java.base/windows/native/libnet/TwoStacksPlainSocketImpl.c
+++ /dev/null
@@ -1,550 +0,0 @@
-/*
- * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-#include "net_util.h"
-
-#include "java_net_TwoStacksPlainSocketImpl.h"
-#include "java_net_SocketOptions.h"
-#include "java_net_InetAddress.h"
-
-#define SET_BLOCKING 0
-#define SET_NONBLOCKING 1
-
-static jclass isa_class; /* java.net.InetSocketAddress */
-static jmethodID isa_ctorID; /* InetSocketAddress(InetAddress, int) */
-
-/************************************************************************
- * TwoStacksPlainSocketImpl
- */
-
-/*
- * The initIDs function is called whenever TwoStacksPlainSocketImpl is
- * loaded, to cache fieldIds for efficiency. This is called everytime
- * the Java class is loaded.
- *
- * Class: java_net_TwoStacksPlainSocketImpl
- * Method: initIDs
- * Signature: ()V
- */
-JNIEXPORT void JNICALL Java_java_net_TwoStacksPlainSocketImpl_initIDs
- (JNIEnv *env, jclass clazz) {
-
- jclass cls = (*env)->FindClass(env, "java/net/InetSocketAddress");
- CHECK_NULL(cls);
- isa_class = (*env)->NewGlobalRef(env, cls);
- CHECK_NULL(isa_class);
- isa_ctorID = (*env)->GetMethodID(env, cls, "",
- "(Ljava/net/InetAddress;I)V");
- CHECK_NULL(isa_ctorID);
-}
-
-/*
- * Class: java_net_TwoStacksPlainSocketImpl
- * Method: socket0
- * Signature: (ZZ)I
- */
-JNIEXPORT jint JNICALL Java_java_net_TwoStacksPlainSocketImpl_socket0
- (JNIEnv *env, jclass clazz, jboolean stream, jboolean v6Only /*unused*/) {
- int fd;
-
- fd = socket(AF_INET, (stream ? SOCK_STREAM: SOCK_DGRAM), 0);
- if (fd == INVALID_SOCKET) {
- NET_ThrowNew(env, WSAGetLastError(), "create");
- return -1;
- }
-
- SetHandleInformation((HANDLE)(UINT_PTR)fd, HANDLE_FLAG_INHERIT, FALSE);
-
- return fd;
-}
-
-/*
- * Class: java_net_TwoStacksPlainSocketImpl
- * Method: bind0
- * Signature: (ILjava/net/InetAddress;I)V
- */
-JNIEXPORT void JNICALL Java_java_net_TwoStacksPlainSocketImpl_bind0
- (JNIEnv *env, jclass clazz, jint fd, jobject iaObj, jint port,
- jboolean exclBind)
-{
- SOCKETADDRESS sa;
- int rv, sa_len = 0;
- /* family is an int field of iaObj */
- int family;
-
- family = getInetAddress_family(env, iaObj);
- if (family != java_net_InetAddress_IPv4) {
- JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
- "Protocol family not supported");
- return;
- }
-
- if (NET_InetAddressToSockaddr(env, iaObj, port, &sa,
- &sa_len, JNI_FALSE) != 0) {
- return;
- }
-
- rv = NET_WinBind(fd, &sa, sa_len, exclBind);
-
- if (rv == SOCKET_ERROR)
- NET_ThrowNew(env, WSAGetLastError(), "NET_Bind");
-}
-
-/*
- * Class: java_net_TwoStacksPlainSocketImpl
- * Method: connect0
- * Signature: (ILjava/net/InetAddress;I)I
- */
-JNIEXPORT jint JNICALL Java_java_net_TwoStacksPlainSocketImpl_connect0
- (JNIEnv *env, jclass clazz, jint fd, jobject iaObj, jint port) {
- SOCKETADDRESS sa;
- int rv, sa_len = 0;
- int family;
-
- if (NET_InetAddressToSockaddr(env, iaObj, port, &sa,
- &sa_len, JNI_FALSE) != 0) {
- return -1;
- }
-
- family = sa.sa.sa_family;
- if (family != AF_INET) {
- JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
- "Protocol family not supported");
- return -1;
- }
-
- rv = connect(fd, &sa.sa, sa_len);
- if (rv == SOCKET_ERROR) {
- int err = WSAGetLastError();
- if (err == WSAEWOULDBLOCK) {
- return java_net_TwoStacksPlainSocketImpl_WOULDBLOCK;
- } else if (err == WSAEADDRNOTAVAIL) {
- JNU_ThrowByName(env, JNU_JAVANETPKG "ConnectException",
- "connect: Address is invalid on local machine, or port is not valid on remote machine");
- } else {
- NET_ThrowNew(env, err, "connect");
- }
- return -1; // return value not important.
- }
- return rv;
-}
-
-/*
- * Class: java_net_TwoStacksPlainSocketImpl
- * Method: waitForConnect
- * Signature: (II)V
- */
-JNIEXPORT void JNICALL Java_java_net_TwoStacksPlainSocketImpl_waitForConnect
- (JNIEnv *env, jclass clazz, jint fd, jint timeout) {
- int rv, retry;
- int optlen = sizeof(rv);
- fd_set wr, ex;
- struct timeval t;
-
- FD_ZERO(&wr);
- FD_ZERO(&ex);
- FD_SET(fd, &wr);
- FD_SET(fd, &ex);
- t.tv_sec = timeout / 1000;
- t.tv_usec = (timeout % 1000) * 1000;
-
- /*
- * Wait for timeout, connection established or
- * connection failed.
- */
- rv = select(fd+1, 0, &wr, &ex, &t);
-
- /*
- * Timeout before connection is established/failed so
- * we throw exception and shutdown input/output to prevent
- * socket from being used.
- * The socket should be closed immediately by the caller.
- */
- if (rv == 0) {
- JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
- "connect timed out");
- shutdown( fd, SD_BOTH );
- return;
- }
- /*
- * Socket is writable or error occurred. On some Windows editions
- * the socket will appear writable when the connect fails so we
- * check for error rather than writable.
- */
- if (!FD_ISSET(fd, &ex)) {
- return; /* connection established */
- }
-
- /*
- * Connection failed. The logic here is designed to work around
- * bug on Windows NT whereby using getsockopt to obtain the
- * last error (SO_ERROR) indicates there is no error. The workaround
- * on NT is to allow winsock to be scheduled and this is done by
- * yielding and retrying. As yielding is problematic in heavy
- * load conditions we attempt up to 3 times to get the error reason.
- */
- for (retry=0; retry<3; retry++) {
- NET_GetSockOpt(fd, SOL_SOCKET, SO_ERROR,
- (char*)&rv, &optlen);
- if (rv) {
- break;
- }
- Sleep(0);
- }
-
- if (rv == 0) {
- JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
- "Unable to establish connection");
- } else if (rv == WSAEADDRNOTAVAIL) {
- JNU_ThrowByName(env, JNU_JAVANETPKG "ConnectException",
- "connect: Address is invalid on local machine,"
- " or port is not valid on remote machine");
- } else {
- NET_ThrowNew(env, rv, "connect");
- }
-}
-
-/*
- * Class: java_net_TwoStacksPlainSocketImpl
- * Method: localPort0
- * Signature: (I)I
- */
-JNIEXPORT jint JNICALL Java_java_net_TwoStacksPlainSocketImpl_localPort0
- (JNIEnv *env, jclass clazz, jint fd) {
- SOCKETADDRESS sa;
- int len = sizeof(sa);
-
- if (getsockname(fd, &sa.sa, &len) == SOCKET_ERROR) {
- if (WSAGetLastError() == WSAENOTSOCK) {
- JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
- "Socket closed");
- } else {
- NET_ThrowNew(env, WSAGetLastError(), "getsockname failed");
- }
- return -1;
- }
- return (int) ntohs((u_short)GET_PORT(&sa));
-}
-
-/*
- * Class: java_net_TwoStacksPlainSocketImpl
- * Method: localAddress
- * Signature: (ILjava/net/InetAddressContainer;)V
- */
-JNIEXPORT void JNICALL Java_java_net_TwoStacksPlainSocketImpl_localAddress
- (JNIEnv *env, jclass clazz, jint fd, jobject iaContainerObj) {
- int port;
- SOCKETADDRESS sa;
- int len = sizeof(sa);
- jobject iaObj;
- jclass iaContainerClass;
- jfieldID iaFieldID;
-
- if (getsockname(fd, &sa.sa, &len) == SOCKET_ERROR) {
- NET_ThrowNew(env, WSAGetLastError(), "Error getting socket name");
- return;
- }
- iaObj = NET_SockaddrToInetAddress(env, &sa, &port);
- CHECK_NULL(iaObj);
-
- iaContainerClass = (*env)->GetObjectClass(env, iaContainerObj);
- iaFieldID = (*env)->GetFieldID(env, iaContainerClass, "addr", "Ljava/net/InetAddress;");
- CHECK_NULL(iaFieldID);
- (*env)->SetObjectField(env, iaContainerObj, iaFieldID, iaObj);
-}
-
-
-/*
- * Class: java_net_TwoStacksPlainSocketImpl
- * Method: listen0
- * Signature: (II)V
- */
-JNIEXPORT void JNICALL Java_java_net_TwoStacksPlainSocketImpl_listen0
- (JNIEnv *env, jclass clazz, jint fd, jint backlog) {
- if (listen(fd, backlog) == SOCKET_ERROR) {
- NET_ThrowNew(env, WSAGetLastError(), "listen failed");
- }
-}
-
-/*
- * Class: java_net_TwoStacksPlainSocketImpl
- * Method: accept0
- * Signature: (I[Ljava/net/InetSocketAddress;)I
- */
-JNIEXPORT jint JNICALL Java_java_net_TwoStacksPlainSocketImpl_accept0
- (JNIEnv *env, jclass clazz, jint fd, jobjectArray isaa) {
- int newfd, port=0;
- jobject isa;
- jobject ia;
- SOCKETADDRESS sa;
- int len = sizeof(sa);
-
- memset((char *)&sa, 0, len);
- newfd = accept(fd, &sa.sa, &len);
-
- if (newfd < 0) {
- if (newfd == -2) {
- JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
- "operation interrupted");
- } else {
- JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
- "socket closed");
- }
- return -1;
- }
-
- SetHandleInformation((HANDLE)(UINT_PTR)newfd, HANDLE_FLAG_INHERIT, 0);
-
- if (sa.sa.sa_family != AF_INET) {
- JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
- "Protocol family not supported");
- NET_SocketClose(newfd);
- return -1;
- }
-
- ia = NET_SockaddrToInetAddress(env, &sa, &port);
- isa = (*env)->NewObject(env, isa_class, isa_ctorID, ia, port);
- (*env)->SetObjectArrayElement(env, isaa, 0, isa);
-
- return newfd;
-}
-
-/*
- * Class: java_net_TwoStacksPlainSocketImpl
- * Method: waitForNewConnection
- * Signature: (II)V
- */
-JNIEXPORT void JNICALL Java_java_net_TwoStacksPlainSocketImpl_waitForNewConnection
- (JNIEnv *env, jclass clazz, jint fd, jint timeout) {
- int rv;
-
- rv = NET_Timeout(fd, timeout);
- if (rv == 0) {
- JNU_ThrowByName(env, JNU_JAVANETPKG "SocketTimeoutException",
- "Accept timed out");
- } else if (rv == -1) {
- JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException", "socket closed");
- } else if (rv == -2) {
- JNU_ThrowByName(env, JNU_JAVAIOPKG "InterruptedIOException",
- "operation interrupted");
- }
-}
-
-/*
- * Class: java_net_TwoStacksPlainSocketImpl
- * Method: available0
- * Signature: (I)I
- */
-JNIEXPORT jint JNICALL Java_java_net_TwoStacksPlainSocketImpl_available0
- (JNIEnv *env, jclass clazz, jint fd) {
- jint available = -1;
-
- if ((ioctlsocket(fd, FIONREAD, &available)) == SOCKET_ERROR) {
- NET_ThrowNew(env, WSAGetLastError(), "socket available");
- }
-
- return available;
-}
-
-/*
- * Class: java_net_TwoStacksPlainSocketImpl
- * Method: close0
- * Signature: (I)V
- */
-JNIEXPORT void JNICALL Java_java_net_TwoStacksPlainSocketImpl_close0
- (JNIEnv *env, jclass clazz, jint fd) {
- NET_SocketClose(fd);
-}
-
-/*
- * Class: java_net_TwoStacksPlainSocketImpl
- * Method: shutdown0
- * Signature: (II)V
- */
-JNIEXPORT void JNICALL Java_java_net_TwoStacksPlainSocketImpl_shutdown0
- (JNIEnv *env, jclass clazz, jint fd, jint howto) {
- shutdown(fd, howto);
-}
-
-
-/*
- * Class: java_net_TwoStacksPlainSocketImpl
- * Method: setIntOption
- * Signature: (III)V
- */
-JNIEXPORT void JNICALL
-Java_java_net_TwoStacksPlainSocketImpl_setIntOption
- (JNIEnv *env, jclass clazz, jint fd, jint cmd, jint value)
-{
- int level = 0, opt = 0;
- struct linger linger = {0, 0};
- char *parg;
- int arglen;
-
- if (NET_MapSocketOption(cmd, &level, &opt) < 0) {
- JNU_ThrowByName(env, "java/net/SocketException", "Invalid option");
- return;
- }
-
- if (opt == java_net_SocketOptions_SO_LINGER) {
- parg = (char *)&linger;
- arglen = sizeof(linger);
- if (value >= 0) {
- linger.l_onoff = 1;
- linger.l_linger = (unsigned short)value;
- } else {
- linger.l_onoff = 0;
- linger.l_linger = 0;
- }
- } else {
- parg = (char *)&value;
- arglen = sizeof(value);
- }
-
- if (NET_SetSockOpt(fd, level, opt, parg, arglen) < 0) {
- NET_ThrowNew(env, WSAGetLastError(), "setsockopt");
- }
-}
-
-/*
- * Class: java_net_TwoStacksPlainSocketImpl
- * Method: setSoTimeout0
- * Signature: (II)V
- */
-JNIEXPORT void JNICALL
-Java_java_net_TwoStacksPlainSocketImpl_setSoTimeout0
- (JNIEnv *env, jclass clazz, jint fd, jint timeout)
-{
- /*
- * SO_TIMEOUT is the socket option used to specify the timeout
- * for ServerSocket.accept and Socket.getInputStream().read.
- * It does not typically map to a native level socket option.
- * For Windows we special-case this and use the SOL_SOCKET/SO_RCVTIMEO
- * socket option to specify a receive timeout on the socket. This
- * receive timeout is applicable to Socket only and the socket
- * option should not be set on ServerSocket.
- */
-
- /*
- * SO_RCVTIMEO is only supported on Microsoft's implementation
- * of Windows Sockets so if WSAENOPROTOOPT returned then
- * reset flag and timeout will be implemented using
- * select() -- see SocketInputStream.socketRead.
- */
- if (isRcvTimeoutSupported) {
- /*
- * Disable SO_RCVTIMEO if timeout is <= 5 second.
- */
- if (timeout <= 5000) {
- timeout = 0;
- }
-
- if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout,
- sizeof(timeout)) < 0) {
- int err = WSAGetLastError();
- if (err == WSAENOPROTOOPT) {
- isRcvTimeoutSupported = JNI_FALSE;
- } else {
- NET_ThrowNew(env, err, "setsockopt SO_RCVTIMEO");
- }
- }
- }
-}
-
-/*
- * Class: java_net_TwoStacksPlainSocketImpl
- * Method: getIntOption
- * Signature: (II)I
- */
-JNIEXPORT jint JNICALL Java_java_net_TwoStacksPlainSocketImpl_getIntOption
- (JNIEnv *env, jclass clazz, jint fd, jint cmd)
-{
- int level = 0, opt = 0;
- int result=0;
- struct linger linger = {0, 0};
- char *arg;
- int arglen;
-
- if (NET_MapSocketOption(cmd, &level, &opt) < 0) {
- JNU_ThrowByName(env, "java/net/SocketException", "Invalid option");
- return -1;
- }
-
- if (opt == java_net_SocketOptions_SO_LINGER) {
- arg = (char *)&linger;
- arglen = sizeof(linger);
- } else {
- arg = (char *)&result;
- arglen = sizeof(result);
- }
-
- if (NET_GetSockOpt(fd, level, opt, arg, &arglen) < 0) {
- NET_ThrowNew(env, WSAGetLastError(), "getsockopt");
- return -1;
- }
-
- if (opt == java_net_SocketOptions_SO_LINGER)
- return linger.l_onoff ? linger.l_linger : -1;
- else
- return result;
-}
-
-
-/*
- * Class: java_net_TwoStacksPlainSocketImpl
- * Method: sendOOB
- * Signature: (II)V
- */
-JNIEXPORT void JNICALL Java_java_net_TwoStacksPlainSocketImpl_sendOOB
- (JNIEnv *env, jclass clazz, jint fd, jint data) {
- jint n;
- unsigned char d = (unsigned char) data & 0xff;
-
- n = send(fd, (char *)&data, 1, MSG_OOB);
- if (n == SOCKET_ERROR) {
- NET_ThrowNew(env, WSAGetLastError(), "send");
- }
-}
-
-/*
- * Class: java_net_TwoStacksPlainSocketImpl
- * Method: configureBlocking
- * Signature: (IZ)V
- */
-JNIEXPORT void JNICALL Java_java_net_TwoStacksPlainSocketImpl_configureBlocking
- (JNIEnv *env, jclass clazz, jint fd, jboolean blocking) {
- u_long arg;
- int result;
-
- if (blocking == JNI_TRUE) {
- arg = SET_BLOCKING; // 0
- } else {
- arg = SET_NONBLOCKING; // 1
- }
-
- result = ioctlsocket(fd, FIONBIO, &arg);
- if (result == SOCKET_ERROR) {
- NET_ThrowNew(env, WSAGetLastError(), "configureBlocking");
- }
-}
diff --git a/src/java.base/zos/classes/sun/nio/ch/DefaultSelectorProvider.java b/src/java.base/zos/classes/sun/nio/ch/DefaultSelectorProvider.java
index 94c0187893d..9f57b2106b6 100644
--- a/src/java.base/zos/classes/sun/nio/ch/DefaultSelectorProvider.java
+++ b/src/java.base/zos/classes/sun/nio/ch/DefaultSelectorProvider.java
@@ -64,7 +64,7 @@ private DefaultSelectorProvider() { }
* Returns the default SelectorProvider.
*/
public static SelectorProvider create() {
- return new sun.nio.ch.EPollSelectorProvider();
+ return new EPollSelectorProvider();
}
}
diff --git a/src/java.base/zos/classes/sun/nio/ch/EPoll.java b/src/java.base/zos/classes/sun/nio/ch/EPoll.java
index edaf5ce44ce..f2963339909 100644
--- a/src/java.base/zos/classes/sun/nio/ch/EPoll.java
+++ b/src/java.base/zos/classes/sun/nio/ch/EPoll.java
@@ -47,6 +47,8 @@
package sun.nio.ch;
+import jdk.internal.misc.Unsafe;
+
import java.io.IOException;
import jdk.internal.misc.Unsafe;
@@ -81,6 +83,10 @@ private EPoll() { }
static final int EPOLL_CTL_DEL = 2;
static final int EPOLL_CTL_MOD = 3;
+ // events
+ static final int EPOLLIN = 0x1;
+ static final int EPOLLOUT = 0x4;
+
// flags
static final int EPOLLONESHOT = (1 << 30);
@@ -127,11 +133,11 @@ static int getEvents(long eventAddress) {
private static native int dataOffset();
- static native int epollCreate() throws IOException;
+ static native int create() throws IOException;
- static native int epollCtl(int epfd, int opcode, int fd, int events);
+ static native int ctl(int epfd, int opcode, int fd, int events);
- static native int epollWait(int epfd, long pollAddress, int numfds)
+ static native int wait(int epfd, long pollAddress, int numfds, int timeout)
throws IOException;
static {
diff --git a/src/java.base/zos/classes/sun/nio/ch/EPollArrayWrapper.java b/src/java.base/zos/classes/sun/nio/ch/EPollArrayWrapper.java
deleted file mode 100644
index 9a68acc3216..00000000000
--- a/src/java.base/zos/classes/sun/nio/ch/EPollArrayWrapper.java
+++ /dev/null
@@ -1,367 +0,0 @@
-/*===========================================================================
- * Licensed Materials - Property of IBM
- * "Restricted Materials of IBM"
- *
- * IBM SDK, Java(tm) Technology Edition, v9
- * (C) Copyright IBM Corp. 2005, 2013. All Rights Reserved
- *
- * US Government Users Restricted Rights - Use, duplication or disclosure
- * restricted by GSA ADP Schedule Contract with IBM Corp.
- *===========================================================================
- */
-/*===========================================================================
- * Licensed Materials - Property of IBM
- * "Restricted Materials of IBM"
- *
- * IBM SDK, Java(tm) Technology Edition, v9
- * (C) Copyright IBM Corp. 2005, 2013. All Rights Reserved
- *
- * US Government Users Restricted Rights - Use, duplication or disclosure
- * restricted by GSA ADP Schedule Contract with IBM Corp.
- *===========================================================================
- */
-/*
- * Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.
- * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- *
- */
-
-package sun.nio.ch;
-
-import java.io.IOException;
-import java.security.AccessController;
-import java.util.BitSet;
-import java.util.HashMap;
-import java.util.Map;
-import sun.security.action.GetIntegerAction;
-
-/**
- * Manipulates a native array of epoll_event structs on Linux:
- *
- * typedef union epoll_data {
- * void *ptr;
- * int fd;
- * __uint32_t u32;
- * __uint64_t u64;
- * } epoll_data_t;
- *
- * struct epoll_event {
- * __uint32_t events;
- * epoll_data_t data;
- * };
- *
- * The system call to wait for I/O events is epoll_wait(2). It populates an
- * array of epoll_event structures that are passed to the call. The data
- * member of the epoll_event structure contains the same data as was set
- * when the file descriptor was registered to epoll via epoll_ctl(2). In
- * this implementation we set data.fd to be the file descriptor that we
- * register. That way, we have the file descriptor available when we
- * process the events.
- */
-
-class EPollArrayWrapper {
- // EPOLL_EVENTS
- private static final int EPOLLIN = 0x001;
-
- // opcodes
- private static final int EPOLL_CTL_ADD = 1;
- private static final int EPOLL_CTL_DEL = 2;
- private static final int EPOLL_CTL_MOD = 3;
-
- // Miscellaneous constants
- private static final int SIZE_EPOLLEVENT = sizeofEPollEvent();
- private static final int EVENT_OFFSET = 0;
- private static final int DATA_OFFSET = offsetofData();
- private static final int FD_OFFSET = DATA_OFFSET;
- private static final int OPEN_MAX = IOUtil.fdLimit();
- private static final int NUM_EPOLLEVENTS = Math.min(OPEN_MAX, 8192);
-
- // Special value to indicate that an update should be ignored
- private static final byte KILLED = (byte)-1;
-
- // Initial size of arrays for fd registration changes
- private static final int INITIAL_PENDING_UPDATE_SIZE = 64;
-
- // maximum size of updatesLow
- private static final int MAX_UPDATE_ARRAY_SIZE = AccessController.doPrivileged(
- new GetIntegerAction("sun.nio.ch.maxUpdateArraySize", Math.min(OPEN_MAX, 64*1024)));
-
- // The fd of the epoll driver
- private final int epfd;
-
- // The epoll_event array for results from epoll_wait
- private final AllocatedNativeObject pollArray;
-
- // Base address of the epoll_event array
- private final long pollArrayAddress;
-
- // The fd of the interrupt line going out
- private int outgoingInterruptFD;
-
- // The fd of the interrupt line coming in
- private int incomingInterruptFD;
-
- // The index of the interrupt FD
- private int interruptedIndex;
-
- // Number of updated pollfd entries
- int updated;
-
- // object to synchronize fd registration changes
- private final Object updateLock = new Object();
-
- // number of file descriptors with registration changes pending
- private int updateCount;
-
- // file descriptors with registration changes pending
- private int[] updateDescriptors = new int[INITIAL_PENDING_UPDATE_SIZE];
-
- // events for file descriptors with registration changes pending, indexed
- // by file descriptor and stored as bytes for efficiency reasons. For
- // file descriptors higher than MAX_UPDATE_ARRAY_SIZE (unlimited case at
- // least) then the update is stored in a map.
- private final byte[] eventsLow = new byte[MAX_UPDATE_ARRAY_SIZE];
- private Map eventsHigh;
-
- // Used by release and updateRegistrations to track whether a file
- // descriptor is registered with epoll.
- private final BitSet registered = new BitSet();
-
-
- EPollArrayWrapper() throws IOException {
- // creates the epoll file descriptor
- epfd = epollCreate();
-
- // the epoll_event array passed to epoll_wait
- int allocationSize = NUM_EPOLLEVENTS * SIZE_EPOLLEVENT;
- pollArray = new AllocatedNativeObject(allocationSize, true);
- pollArrayAddress = pollArray.address();
-
- // eventHigh needed when using file descriptors > 64k
- if (OPEN_MAX > MAX_UPDATE_ARRAY_SIZE)
- eventsHigh = new HashMap<>();
- }
-
- void initInterrupt(int fd0, int fd1) {
- outgoingInterruptFD = fd1;
- incomingInterruptFD = fd0;
- epollCtl(epfd, EPOLL_CTL_ADD, fd0, EPOLLIN);
- }
-
- void putEventOps(int i, int event) {
- int offset = SIZE_EPOLLEVENT * i + EVENT_OFFSET;
- pollArray.putInt(offset, event);
- }
-
- void putDescriptor(int i, int fd) {
- int offset = SIZE_EPOLLEVENT * i + FD_OFFSET;
- pollArray.putInt(offset, fd);
- }
-
- int getEventOps(int i) {
- int offset = SIZE_EPOLLEVENT * i + EVENT_OFFSET;
- return pollArray.getInt(offset);
- }
-
- int getDescriptor(int i) {
- int offset = SIZE_EPOLLEVENT * i + FD_OFFSET;
- return pollArray.getInt(offset);
- }
-
- /**
- * Returns {@code true} if updates for the given key (file
- * descriptor) are killed.
- */
- private boolean isEventsHighKilled(Integer key) {
- assert key >= MAX_UPDATE_ARRAY_SIZE;
- Byte value = eventsHigh.get(key);
- return (value != null && value == KILLED);
- }
-
- /**
- * Sets the pending update events for the given file descriptor. This
- * method has no effect if the update events is already set to KILLED,
- * unless {@code force} is {@code true}.
- */
- private void setUpdateEvents(int fd, byte events, boolean force) {
- if (fd < MAX_UPDATE_ARRAY_SIZE) {
- if ((eventsLow[fd] != KILLED) || force) {
- eventsLow[fd] = events;
- }
- } else {
- Integer key = Integer.valueOf(fd);
- if (!isEventsHighKilled(key) || force) {
- eventsHigh.put(key, Byte.valueOf(events));
- }
- }
- }
-
- /**
- * Returns the pending update events for the given file descriptor.
- */
- private byte getUpdateEvents(int fd) {
- if (fd < MAX_UPDATE_ARRAY_SIZE) {
- return eventsLow[fd];
- } else {
- Byte result = eventsHigh.get(Integer.valueOf(fd));
- // result should never be null
- return result.byteValue();
- }
- }
-
- /**
- * Update the events for a given file descriptor
- */
- void setInterest(int fd, int mask) {
- synchronized (updateLock) {
- // record the file descriptor and events
- int oldCapacity = updateDescriptors.length;
- if (updateCount == oldCapacity) {
- int newCapacity = oldCapacity + INITIAL_PENDING_UPDATE_SIZE;
- int[] newDescriptors = new int[newCapacity];
- System.arraycopy(updateDescriptors, 0, newDescriptors, 0, oldCapacity);
- updateDescriptors = newDescriptors;
- }
- updateDescriptors[updateCount++] = fd;
-
- // events are stored as bytes for efficiency reasons
- byte b = (byte)mask;
- assert (b == mask) && (b != KILLED);
- setUpdateEvents(fd, b, false);
- }
- }
-
- /**
- * Add a file descriptor
- */
- void add(int fd) {
- // force the initial update events to 0 as it may be KILLED by a
- // previous registration.
- synchronized (updateLock) {
- assert !registered.get(fd);
- setUpdateEvents(fd, (byte)0, true);
- }
- }
-
- /**
- * Remove a file descriptor
- */
- void remove(int fd) {
- synchronized (updateLock) {
- // kill pending and future update for this file descriptor
- setUpdateEvents(fd, KILLED, false);
-
- // remove from epoll
- if (registered.get(fd)) {
- epollCtl(epfd, EPOLL_CTL_DEL, fd, 0);
- registered.clear(fd);
- }
- }
- }
-
- /**
- * Close epoll file descriptor and free poll array
- */
- void closeEPollFD() throws IOException {
- FileDispatcherImpl.closeIntFD(epfd);
- pollArray.free();
- }
-
- int poll(long timeout) throws IOException {
- updateRegistrations();
- updated = epollWait(pollArrayAddress, NUM_EPOLLEVENTS, timeout, epfd);
- for (int i=0; i>> 32), (int) fds};
+ } catch (IOException ioe) {
+ EPoll.freePollArray(address);
+ FileDispatcherImpl.closeIntFD(epfd);
+ throw ioe;
}
- this.sp = sv;
- // allocate the poll array
- this.address = allocatePollArray(MAX_EPOLL_EVENTS);
+ // register one end with epoll
+ EPoll.ctl(epfd, EPOLL_CTL_ADD, sp[0], EPOLLIN);
// create the queue and offer the special event to ensure that the first
// threads polls
@@ -145,17 +149,17 @@ private void implClose() {
return;
closed = true;
}
- freePollArray(address);
- close0(sp[0]);
- close0(sp[1]);
- close0(epfd);
+ try { FileDispatcherImpl.closeIntFD(epfd); } catch (IOException ioe) { }
+ try { FileDispatcherImpl.closeIntFD(sp[0]); } catch (IOException ioe) { }
+ try { FileDispatcherImpl.closeIntFD(sp[1]); } catch (IOException ioe) { }
+ EPoll.freePollArray(address);
}
private void wakeup() {
if (wakeupCount.incrementAndGet() == 1) {
// write byte to socketpair to force wakeup
try {
- interrupt(sp[1]);
+ IOUtil.write1(sp[1], (byte)0);
} catch (IOException x) {
throw new AssertionError(x);
}
@@ -182,7 +186,7 @@ void shutdownHandlerTasks() {
if (nThreads == 0) {
implClose();
} else {
- // send interrupt to each thread
+ // send wakeup to each thread
while (nThreads-- > 0) {
wakeup();
}
@@ -193,18 +197,18 @@ void shutdownHandlerTasks() {
@Override
void startPoll(int fd, int events) {
// update events (or add to epoll on first usage)
- int err = epollCtl(epfd, EPOLL_CTL_MOD, fd, (events | EPOLLONESHOT));
+ int err = EPoll.ctl(epfd, EPOLL_CTL_MOD, fd, (events | EPOLLONESHOT));
if (err == ENOENT)
- err = epollCtl(epfd, EPOLL_CTL_ADD, fd, (events | EPOLLONESHOT));
+ err = EPoll.ctl(epfd, EPOLL_CTL_ADD, fd, (events | EPOLLONESHOT));
if (err != 0)
throw new AssertionError(); // should not happen
}
- /*
+ /**
* Task to process events from epoll and dispatch to the channel's
* onEvent handler.
*
- * Events are retreived from epoll in batch and offered to a BlockingQueue
+ * Events are retrieved from epoll in batch and offered to a BlockingQueue
* where they are consumed by handler threads. A special "NEED_TO_POLL"
* event is used to signal one consumer to re-poll when all events have
* been consumed.
@@ -213,8 +217,12 @@ private class EventHandlerTask implements Runnable {
private Event poll() throws IOException {
try {
for (;;) {
- int n = epollWait(epfd, address, MAX_EPOLL_EVENTS);
- /*
+ int n;
+ do {
+ n = EPoll.wait(epfd, address, MAX_EPOLL_EVENTS, -1);
+ } while (n == IOStatus.INTERRUPTED);
+
+ /**
* 'n' events have been read. Here we map them to their
* corresponding channel in batch and queue n-1 so that
* they can be handled by other handler threads. The last
@@ -223,14 +231,19 @@ private Event poll() throws IOException {
fdToChannelLock.readLock().lock();
try {
while (n-- > 0) {
- long eventAddress = getEvent(address, n);
- int fd = getDescriptor(eventAddress);
+ long eventAddress = EPoll.getEvent(address, n);
+ int fd = EPoll.getDescriptor(eventAddress);
// wakeup
if (fd == sp[0]) {
if (wakeupCount.decrementAndGet() == 0) {
- // no more wakeups so drain pipe
- drain1(sp[0]);
+ // consume one wakeup byte, never more as this
+ // would interfere with shutdown when there is
+ // a wakeup byte queued to wake each thread
+ int nread;
+ do {
+ nread = IOUtil.drain1(sp[0]);
+ } while (nread == IOStatus.INTERRUPTED);
}
// queue special event if there are more events
@@ -244,7 +257,7 @@ private Event poll() throws IOException {
PollableChannel channel = fdToChannel.get(fd);
if (channel != null) {
- int events = getEvents(eventAddress);
+ int events = EPoll.getEvents(eventAddress);
Event ev = new Event(channel, events);
// n-1 events are queued; This thread handles
@@ -328,18 +341,4 @@ public void run() {
}
}
}
-
- // -- Native methods --
-
- private static native void socketpair(int[] sv) throws IOException;
-
- private static native void interrupt(int fd) throws IOException;
-
- private static native void drain1(int fd) throws IOException;
-
- private static native void close0(int fd);
-
- static {
- IOUtil.load();
- }
}
diff --git a/src/java.base/zos/classes/sun/nio/ch/EPollSelectorImpl.java b/src/java.base/zos/classes/sun/nio/ch/EPollSelectorImpl.java
index a4a858dc910..eed8359bd3e 100644
--- a/src/java.base/zos/classes/sun/nio/ch/EPollSelectorImpl.java
+++ b/src/java.base/zos/classes/sun/nio/ch/EPollSelectorImpl.java
@@ -48,185 +48,251 @@
package sun.nio.ch;
import java.io.IOException;
-import java.nio.channels.*;
-import java.nio.channels.spi.*;
-import java.util.*;
+import java.nio.channels.ClosedSelectorException;
+import java.nio.channels.Selector;
+import java.nio.channels.spi.SelectorProvider;
+import java.util.ArrayDeque;
+import java.util.Deque;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+import static sun.nio.ch.EPoll.EPOLLIN;
+import static sun.nio.ch.EPoll.EPOLL_CTL_ADD;
+import static sun.nio.ch.EPoll.EPOLL_CTL_DEL;
+import static sun.nio.ch.EPoll.EPOLL_CTL_MOD;
+
/**
- * An implementation of Selector for Linux 2.6+ kernels that uses
- * the epoll event notification facility.
+ * Linux epoll based Selector implementation
*/
-class EPollSelectorImpl
- extends SelectorImpl
-{
- // File descriptors used for interrupt
- protected int fd0;
- protected int fd1;
+class EPollSelectorImpl extends SelectorImpl {
+
+ // maximum number of events to poll in one call to epoll_wait
+ private static final int NUM_EPOLLEVENTS = Math.min(IOUtil.fdLimit(), 1024);
+
+ // epoll file descriptor
+ private final int epfd;
- // The poll object
- EPollArrayWrapper pollWrapper;
+ // address of poll array when polling with epoll_wait
+ private final long pollArrayAddress;
- // Maps from file descriptors to keys
- private Map fdToKey;
+ // file descriptors used for interrupt
+ private final int fd0;
+ private final int fd1;
- // True if this Selector has been closed
- private volatile boolean closed;
+ // maps file descriptor to selection key, synchronize on selector
+ private final Map fdToKey = new HashMap<>();
- // Lock for interrupt triggering and clearing
+ // pending new registrations/updates, queued by setEventOps
+ private final Object updateLock = new Object();
+ private final Deque updateKeys = new ArrayDeque<>();
+
+ // interrupt triggering and clearing
private final Object interruptLock = new Object();
- private boolean interruptTriggered = false;
+ private boolean interruptTriggered;
- /**
- * Package private constructor called by factory method in
- * the abstract superclass Selector.
- */
EPollSelectorImpl(SelectorProvider sp) throws IOException {
super(sp);
- long pipeFds = IOUtil.makePipe(false);
- fd0 = (int) (pipeFds >>> 32);
- fd1 = (int) pipeFds;
+
+ this.epfd = EPoll.create();
+ this.pollArrayAddress = EPoll.allocatePollArray(NUM_EPOLLEVENTS);
+
try {
- pollWrapper = new EPollArrayWrapper();
- pollWrapper.initInterrupt(fd0, fd1);
- fdToKey = new HashMap<>();
- } catch (Throwable t) {
- try {
- FileDispatcherImpl.closeIntFD(fd0);
- } catch (IOException ioe0) {
- t.addSuppressed(ioe0);
- }
- try {
- FileDispatcherImpl.closeIntFD(fd1);
- } catch (IOException ioe1) {
- t.addSuppressed(ioe1);
- }
- throw t;
+ long fds = IOUtil.makePipe(false);
+ this.fd0 = (int) (fds >>> 32);
+ this.fd1 = (int) fds;
+ } catch (IOException ioe) {
+ EPoll.freePollArray(pollArrayAddress);
+ FileDispatcherImpl.closeIntFD(epfd);
+ throw ioe;
}
+
+ // register one end of the socket pair for wakeups
+ EPoll.ctl(epfd, EPOLL_CTL_ADD, fd0, EPOLLIN);
}
- protected int doSelect(long timeout) throws IOException {
- if (closed)
+ private void ensureOpen() {
+ if (!isOpen())
throw new ClosedSelectorException();
+ }
+
+ @Override
+ protected int doSelect(long timeout) throws IOException {
+ assert Thread.holdsLock(this);
+
+ // epoll_wait timeout is int
+ int to = (int) Math.min(timeout, Integer.MAX_VALUE);
+ boolean blocking = (to != 0);
+ boolean timedPoll = (to > 0);
+
+ int numEntries;
+ processUpdateQueue();
processDeregisterQueue();
try {
- begin();
- pollWrapper.poll(timeout);
+ begin(blocking);
+
+ do {
+ long startTime = timedPoll ? System.nanoTime() : 0;
+ numEntries = EPoll.wait(epfd, pollArrayAddress, NUM_EPOLLEVENTS, to);
+ if (numEntries == IOStatus.INTERRUPTED && timedPoll) {
+ // timed poll interrupted so need to adjust timeout
+ long adjust = System.nanoTime() - startTime;
+ to -= TimeUnit.MILLISECONDS.convert(adjust, TimeUnit.NANOSECONDS);
+ if (to <= 0) {
+ // timeout expired so no retry
+ numEntries = 0;
+ }
+ }
+ } while (numEntries == IOStatus.INTERRUPTED);
+ assert IOStatus.check(numEntries);
+
} finally {
- end();
+ end(blocking);
}
processDeregisterQueue();
- int numKeysUpdated = updateSelectedKeys();
- if (pollWrapper.interrupted()) {
- // Clear the wakeup pipe
- pollWrapper.putEventOps(pollWrapper.interruptedIndex(), 0);
- synchronized (interruptLock) {
- pollWrapper.clearInterrupted();
- IOUtil.drain(fd0);
- interruptTriggered = false;
+ return updateSelectedKeys(numEntries);
+ }
+
+ /**
+ * Process changes to the interest ops.
+ */
+ private void processUpdateQueue() {
+ assert Thread.holdsLock(this);
+
+ synchronized (updateLock) {
+ SelectionKeyImpl ski;
+ while ((ski = updateKeys.pollFirst()) != null) {
+ if (ski.isValid()) {
+ int fd = ski.getFDVal();
+ // add to fdToKey if needed
+ SelectionKeyImpl previous = fdToKey.putIfAbsent(fd, ski);
+ assert (previous == null) || (previous == ski);
+
+ int newEvents = ski.translateInterestOps();
+ int registeredEvents = ski.registeredEvents();
+ if (newEvents != registeredEvents) {
+ if (newEvents == 0) {
+ // remove from epoll
+ EPoll.ctl(epfd, EPOLL_CTL_DEL, fd, 0);
+ } else {
+ if (registeredEvents == 0) {
+ // add to epoll
+ EPoll.ctl(epfd, EPOLL_CTL_ADD, fd, newEvents);
+ } else {
+ // modify events
+ EPoll.ctl(epfd, EPOLL_CTL_MOD, fd, newEvents);
+ }
+ }
+ ski.registeredEvents(newEvents);
+ }
+ }
}
}
- return numKeysUpdated;
}
/**
- * Update the keys whose fd's have been selected by the epoll.
- * Add the ready keys to the ready queue.
+ * Update the keys of file descriptors that were polled and add them to
+ * the selected-key set.
+ * If the interrupt fd has been selected, drain it and clear the interrupt.
*/
- private int updateSelectedKeys() {
- int entries = pollWrapper.updated;
+ private int updateSelectedKeys(int numEntries) throws IOException {
+ assert Thread.holdsLock(this);
+ assert Thread.holdsLock(nioSelectedKeys());
+
+ boolean interrupted = false;
int numKeysUpdated = 0;
- for (int i=0; i i = keys.iterator();
- while (i.hasNext()) {
- SelectionKeyImpl ski = (SelectionKeyImpl)i.next();
- deregister(ski);
- SelectableChannel selch = ski.channel();
- if (!selch.isOpen() && !selch.isRegistered())
- ((SelChImpl)selch).kill();
- i.remove();
- }
-
- fd0 = -1;
- fd1 = -1;
- }
-
- protected void implRegister(SelectionKeyImpl ski) {
- if (closed)
- throw new ClosedSelectorException();
- SelChImpl ch = ski.channel;
- int fd = Integer.valueOf(ch.getFDVal());
- fdToKey.put(fd, ski);
- pollWrapper.add(fd);
- keys.add(ski);
}
+ @Override
protected void implDereg(SelectionKeyImpl ski) throws IOException {
- assert (ski.getIndex() >= 0);
- SelChImpl ch = ski.channel;
- int fd = ch.getFDVal();
- fdToKey.remove(Integer.valueOf(fd));
- pollWrapper.remove(fd);
- ski.setIndex(-1);
- keys.remove(ski);
- selectedKeys.remove(ski);
- deregister((AbstractSelectionKey)ski);
- SelectableChannel selch = ski.channel();
- if (!selch.isOpen() && !selch.isRegistered())
- ((SelChImpl)selch).kill();
+ assert !ski.isValid();
+ assert Thread.holdsLock(this);
+
+ int fd = ski.getFDVal();
+ if (fdToKey.remove(fd) != null) {
+ if (ski.registeredEvents() != 0) {
+ EPoll.ctl(epfd, EPOLL_CTL_DEL, fd, 0);
+ ski.registeredEvents(0);
+ }
+ } else {
+ assert ski.registeredEvents() == 0;
+ }
}
- public void putEventOps(SelectionKeyImpl ski, int ops) {
- if (closed)
- throw new ClosedSelectorException();
- SelChImpl ch = ski.channel;
- pollWrapper.setInterest(ch.getFDVal(), ops);
+ @Override
+ public void setEventOps(SelectionKeyImpl ski) {
+ ensureOpen();
+ synchronized (updateLock) {
+ updateKeys.addLast(ski);
+ }
}
+ @Override
public Selector wakeup() {
synchronized (interruptLock) {
if (!interruptTriggered) {
- pollWrapper.interrupt();
+ try {
+ IOUtil.write1(fd1, (byte)0);
+ } catch (IOException ioe) {
+ throw new InternalError(ioe);
+ }
interruptTriggered = true;
}
}
return this;
}
+
+ private void clearInterrupt() throws IOException {
+ synchronized (interruptLock) {
+ IOUtil.drain(fd0);
+ interruptTriggered = false;
+ }
+ }
}
diff --git a/src/java.desktop/macosx/classes/com/apple/eawt/FullScreenUtilities.java b/src/java.desktop/macosx/classes/com/apple/eawt/FullScreenUtilities.java
index f70e93b7963..46d0143b220 100644
--- a/src/java.desktop/macosx/classes/com/apple/eawt/FullScreenUtilities.java
+++ b/src/java.desktop/macosx/classes/com/apple/eawt/FullScreenUtilities.java
@@ -37,8 +37,7 @@
* Utility class perform animated full screen actions to top-level {@link Window}s.
*
* This class manages the relationship between {@link Window}s and the {@link FullScreenListener}s
- * attached to them. It's design is similar to the Java SE 6u10 {@code com.sun.awt.AWTUtilities}
- * class which adds additional functionality to AWT Windows, without adding new API to the
+ * attached to them. It adds additional functionality to AWT Windows, without adding new API to the
* {@link java.awt.Window} class.
*
* Full screen operations can only be performed on top-level {@link Window}s that are also {@link RootPaneContainer}s.
diff --git a/src/java.desktop/macosx/classes/com/apple/eawt/event/GestureUtilities.java b/src/java.desktop/macosx/classes/com/apple/eawt/event/GestureUtilities.java
index bb8922ee7c9..14561b02c62 100644
--- a/src/java.desktop/macosx/classes/com/apple/eawt/event/GestureUtilities.java
+++ b/src/java.desktop/macosx/classes/com/apple/eawt/event/GestureUtilities.java
@@ -33,8 +33,7 @@
* Registration utility class to add {@link GestureListener}s to Swing components.
*
* This class manages the relationship between {@link JComponent}s and the {@link GestureListener}s
- * attached to them. It's design is similar to the Java SE 6u10 {@code com.sun.awt.AWTUtilities}
- * class which adds additional functionality to AWT Windows, without adding new API to the
+ * attached to them. It adds additional functionality to AWT Windows, without adding new API to the
* {@link java.awt.Window} class.
*
* To add a {@link GestureListener} to a top-level Swing window, use the {@link JRootPane} of the
diff --git a/src/java.desktop/share/classes/com/sun/awt/AWTUtilities.java b/src/java.desktop/share/classes/com/sun/awt/AWTUtilities.java
deleted file mode 100644
index 1d16510d267..00000000000
--- a/src/java.desktop/share/classes/com/sun/awt/AWTUtilities.java
+++ /dev/null
@@ -1,500 +0,0 @@
-/*
- * Copyright (c) 2008, 2017, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package com.sun.awt;
-
-import java.awt.Color;
-import java.awt.Component;
-import java.awt.Dialog;
-import java.awt.Frame;
-import java.awt.GraphicsConfiguration;
-import java.awt.GraphicsDevice;
-import java.awt.GraphicsEnvironment;
-import java.awt.Shape;
-import java.awt.Toolkit;
-import java.awt.Window;
-
-import javax.swing.JRootPane;
-
-import sun.awt.AWTAccessor;
-import sun.awt.SunToolkit;
-
-/**
- * A collection of utility methods for AWT.
- *
- * The functionality provided by the static methods of the class includes:
- *
- * - Setting shapes on top-level windows
- *
- Setting a constant alpha value for each pixel of a top-level window
- *
- Making a window non-opaque, after that it paints only explicitly
- * painted pixels on the screen, with arbitrary alpha values for every pixel.
- *
- Setting a 'mixing-cutout' shape for a component.
- *
- *
- * A "top-level window" is an instance of the {@code Window} class (or its
- * descendant, such as {@code JFrame}).
- *
- * Some of the mentioned features may not be supported by the native platform.
- * To determine whether a particular feature is supported, the user must use
- * the {@code isTranslucencySupported()} method of the class passing a desired
- * translucency kind (a member of the {@code Translucency} enum) as an
- * argument.
- *
- * The per-pixel alpha feature also requires the user to create her/his
- * windows using a translucency-capable graphics configuration.
- * The {@code isTranslucencyCapable()} method must
- * be used to verify whether any given GraphicsConfiguration supports
- * the translucency effects.
- *
- * WARNING: This class is an implementation detail and only meant
- * for limited use outside of the core platform. This API may change
- * drastically between update release, and it may even be
- * removed or be moved in some other package(s)/class(es).
- */
-@Deprecated(forRemoval = true, since = "10")
-public final class AWTUtilities {
-
- /**
- * The AWTUtilities class should not be instantiated
- */
- private AWTUtilities() {
- }
-
- /** Kinds of translucency supported by the underlying system.
- * @see #isTranslucencySupported
- */
- public static enum Translucency {
- /**
- * Represents support in the underlying system for windows each pixel
- * of which is guaranteed to be either completely opaque, with
- * an alpha value of 1.0, or completely transparent, with an alpha
- * value of 0.0.
- */
- PERPIXEL_TRANSPARENT,
-
- /**
- * Represents support in the underlying system for windows all of
- * the pixels of which have the same alpha value between or including
- * 0.0 and 1.0.
- */
- TRANSLUCENT,
-
- /**
- * Represents support in the underlying system for windows that
- * contain or might contain pixels with arbitrary alpha values
- * between and including 0.0 and 1.0.
- */
- PERPIXEL_TRANSLUCENT;
- }
-
-
- /**
- * Returns whether the given level of translucency is supported by
- * the underlying system.
- *
- * Note that this method may sometimes return the value
- * indicating that the particular level is supported, but
- * the native windowing system may still not support the
- * given level of translucency (due to the bugs in
- * the windowing system).
- *
- * @param translucencyKind a kind of translucency support
- * (either PERPIXEL_TRANSPARENT,
- * TRANSLUCENT, or PERPIXEL_TRANSLUCENT)
- * @return whether the given translucency kind is supported
- * @deprecated use {@link GraphicsDevice#isWindowTranslucencySupported}
- * instead
- */
- @Deprecated(forRemoval = true, since = "10")
- public static boolean isTranslucencySupported(Translucency translucencyKind) {
- switch (translucencyKind) {
- case PERPIXEL_TRANSPARENT:
- return isWindowShapingSupported();
- case TRANSLUCENT:
- return isWindowOpacitySupported();
- case PERPIXEL_TRANSLUCENT:
- return isWindowTranslucencySupported();
- }
- return false;
- }
-
-
- /**
- * Returns whether the windowing system supports changing the opacity
- * value of top-level windows.
- * Note that this method may sometimes return true, but the native
- * windowing system may still not support the concept of
- * translucency (due to the bugs in the windowing system).
- */
- private static boolean isWindowOpacitySupported() {
- Toolkit curToolkit = Toolkit.getDefaultToolkit();
- if (!(curToolkit instanceof SunToolkit)) {
- return false;
- }
- return ((SunToolkit)curToolkit).isWindowOpacitySupported();
- }
-
- /**
- * Set the opacity of the window. The opacity is at the range [0..1].
- * Note that setting the opacity level of 0 may or may not disable
- * the mouse event handling on this window. This is
- * a platform-dependent behavior.
- *
- * In order for this method to enable the translucency effect,
- * the isTranslucencySupported() method should indicate that the
- * TRANSLUCENT level of translucency is supported.
- *
- *
Also note that the window must not be in the full-screen mode
- * when setting the opacity value < 1.0f. Otherwise
- * the IllegalArgumentException is thrown.
- *
- * @param window the window to set the opacity level to
- * @param opacity the opacity level to set to the window
- * @throws NullPointerException if the window argument is null
- * @throws IllegalArgumentException if the opacity is out of
- * the range [0..1]
- * @throws IllegalArgumentException if the window is in full screen mode,
- * and the opacity is less than 1.0f
- * @throws UnsupportedOperationException if the TRANSLUCENT translucency
- * kind is not supported
- * @deprecated use {@link Window#setOpacity} instead
- */
- @Deprecated(forRemoval = true, since = "10")
- public static void setWindowOpacity(Window window, float opacity) {
- if (window == null) {
- throw new NullPointerException(
- "The window argument should not be null.");
- }
- window.setOpacity(opacity);
- }
-
- /**
- * Get the opacity of the window. If the opacity has not
- * yet being set, this method returns 1.0.
- *
- * @param window the window to get the opacity level from
- * @throws NullPointerException if the window argument is null
- * @deprecated use {@link Window#getOpacity} instead
- */
- @Deprecated(forRemoval = true, since = "10")
- public static float getWindowOpacity(Window window) {
- if (window == null) {
- throw new NullPointerException(
- "The window argument should not be null.");
- }
-
- return window.getOpacity();
- }
-
- /**
- * Returns whether the windowing system supports changing the shape
- * of top-level windows.
- * Note that this method may sometimes return true, but the native
- * windowing system may still not support the concept of
- * shaping (due to the bugs in the windowing system).
- * @deprecated use {@link GraphicsDevice#isWindowTranslucencySupported}
- * instead
- */
- @Deprecated(forRemoval = true, since = "10")
- public static boolean isWindowShapingSupported() {
- Toolkit curToolkit = Toolkit.getDefaultToolkit();
- if (!(curToolkit instanceof SunToolkit)) {
- return false;
- }
- return ((SunToolkit)curToolkit).isWindowShapingSupported();
- }
-
- /**
- * Returns an object that implements the Shape interface and represents
- * the shape previously set with the call to the setWindowShape() method.
- * If no shape has been set yet, or the shape has been reset to null,
- * this method returns null.
- *
- * @param window the window to get the shape from
- * @return the current shape of the window
- * @throws NullPointerException if the window argument is null
- * @deprecated use {@link Window#getShape} instead
- */
- @Deprecated(forRemoval = true, since = "10")
- public static Shape getWindowShape(Window window) {
- if (window == null) {
- throw new NullPointerException(
- "The window argument should not be null.");
- }
- return window.getShape();
- }
-
- /**
- * Sets a shape for the given window.
- * If the shape argument is null, this methods restores
- * the default shape making the window rectangular.
- *
Note that in order to set a shape, the window must be undecorated.
- * If the window is decorated, this method ignores the {@code shape}
- * argument and resets the shape to null.
- *
Also note that the window must not be in the full-screen mode
- * when setting a non-null shape. Otherwise the IllegalArgumentException
- * is thrown.
- *
Depending on the platform, the method may return without
- * effecting the shape of the window if the window has a non-null warning
- * string ({@link Window#getWarningString()}). In this case the passed
- * shape object is ignored.
- *
- * @param window the window to set the shape to
- * @param shape the shape to set to the window
- * @throws NullPointerException if the window argument is null
- * @throws IllegalArgumentException if the window is in full screen mode,
- * and the shape is not null
- * @throws UnsupportedOperationException if the PERPIXEL_TRANSPARENT
- * translucency kind is not supported
- * @deprecated use {@link Window#setShape} instead
- */
- @Deprecated(forRemoval = true, since = "10")
- public static void setWindowShape(Window window, Shape shape) {
- if (window == null) {
- throw new NullPointerException(
- "The window argument should not be null.");
- }
- window.setShape(shape);
- }
-
- private static boolean isWindowTranslucencySupported() {
- /*
- * Per-pixel alpha is supported if all the conditions are TRUE:
- * 1. The toolkit is a sort of SunToolkit
- * 2. The toolkit supports translucency in general
- * (isWindowTranslucencySupported())
- * 3. There's at least one translucency-capable
- * GraphicsConfiguration
- */
-
- Toolkit curToolkit = Toolkit.getDefaultToolkit();
- if (!(curToolkit instanceof SunToolkit)) {
- return false;
- }
-
- if (!((SunToolkit)curToolkit).isWindowTranslucencySupported()) {
- return false;
- }
-
- GraphicsEnvironment env =
- GraphicsEnvironment.getLocalGraphicsEnvironment();
-
- // If the default GC supports translucency return true.
- // It is important to optimize the verification this way,
- // see CR 6661196 for more details.
- if (isTranslucencyCapable(env.getDefaultScreenDevice()
- .getDefaultConfiguration()))
- {
- return true;
- }
-
- // ... otherwise iterate through all the GCs.
- GraphicsDevice[] devices = env.getScreenDevices();
-
- for (int i = 0; i < devices.length; i++) {
- GraphicsConfiguration[] configs = devices[i].getConfigurations();
- for (int j = 0; j < configs.length; j++) {
- if (isTranslucencyCapable(configs[j])) {
- return true;
- }
- }
- }
-
- return false;
- }
-
- /**
- * Enables the per-pixel alpha support for the given window.
- * Once the window becomes non-opaque (the isOpaque is set to false),
- * the drawing sub-system is starting to respect the alpha value of each
- * separate pixel. If a pixel gets painted with alpha color component
- * equal to zero, it becomes visually transparent, if the alpha of the
- * pixel is equal to 255, the pixel is fully opaque. Interim values
- * of the alpha color component make the pixel semi-transparent (i.e.
- * translucent).
- *
Note that in order for the window to support the per-pixel alpha
- * mode, the window must be created using the GraphicsConfiguration
- * for which the {@link #isTranslucencyCapable}
- * method returns true.
- *
Also note that some native systems enable the per-pixel translucency
- * mode for any window created using the translucency-compatible
- * graphics configuration. However, it is highly recommended to always
- * invoke the setWindowOpaque() method for these windows, at least for
- * the sake of cross-platform compatibility reasons.
- *
Also note that the window must not be in the full-screen mode
- * when making it non-opaque. Otherwise the IllegalArgumentException
- * is thrown.
- *
If the window is a {@code Frame} or a {@code Dialog}, the window must
- * be undecorated prior to enabling the per-pixel translucency effect (see
- * {@link Frame#setUndecorated} and/or {@link Dialog#setUndecorated}).
- * If the window becomes decorated through a subsequent call to the
- * corresponding {@code setUndecorated()} method, the per-pixel
- * translucency effect will be disabled and the opaque property reset to
- * {@code true}.
- *
Depending on the platform, the method may return without
- * effecting the opaque property of the window if the window has a non-null
- * warning string ({@link Window#getWarningString()}). In this case
- * the passed 'isOpaque' value is ignored.
- *
- * @param window the window to set the shape to
- * @param isOpaque whether the window must be opaque (true),
- * or translucent (false)
- * @throws NullPointerException if the window argument is null
- * @throws IllegalArgumentException if the window uses
- * a GraphicsConfiguration for which the
- * {@code isTranslucencyCapable()}
- * method returns false
- * @throws IllegalArgumentException if the window is in full screen mode,
- * and the isOpaque is false
- * @throws IllegalArgumentException if the window is decorated and the
- * isOpaque argument is {@code false}.
- * @throws UnsupportedOperationException if the PERPIXEL_TRANSLUCENT
- * translucency kind is not supported
- * @deprecated use {@link Window#setBackground} instead
- */
- @Deprecated(forRemoval = true, since = "10")
- public static void setWindowOpaque(Window window, boolean isOpaque) {
- if (window == null) {
- throw new NullPointerException(
- "The window argument should not be null.");
- }
- if (!isOpaque && !isTranslucencySupported(Translucency.PERPIXEL_TRANSLUCENT)) {
- throw new UnsupportedOperationException(
- "The PERPIXEL_TRANSLUCENT translucency kind is not supported");
- }
- Color bg = window.getBackground();
- if (bg == null) {
- bg = new Color(0, 0, 0, 0);
- }
- window.setBackground(new Color(bg.getRed(), bg.getGreen(), bg.getBlue(),
- isOpaque ? 255 : 0));
- }
-
- /**
- * Returns whether the window is opaque or translucent.
- *
- * @param window the window to set the shape to
- * @return whether the window is currently opaque (true)
- * or translucent (false)
- * @throws NullPointerException if the window argument is null
- * @deprecated use {@link Window#isOpaque} instead
- */
- @Deprecated(forRemoval = true, since = "10")
- public static boolean isWindowOpaque(Window window) {
- if (window == null) {
- throw new NullPointerException(
- "The window argument should not be null.");
- }
-
- return window.isOpaque();
- }
-
- /**
- * Verifies whether a given GraphicsConfiguration supports
- * the PERPIXEL_TRANSLUCENT kind of translucency.
- * All windows that are intended to be used with the {@link #setWindowOpaque}
- * method must be created using a GraphicsConfiguration for which this method
- * returns true.
- *
Note that some native systems enable the per-pixel translucency
- * mode for any window created using a translucency-capable
- * graphics configuration. However, it is highly recommended to always
- * invoke the setWindowOpaque() method for these windows, at least
- * for the sake of cross-platform compatibility reasons.
- *
- * @param gc GraphicsConfiguration
- * @throws NullPointerException if the gc argument is null
- * @return whether the given GraphicsConfiguration supports
- * the translucency effects.
- * @deprecated use {@link GraphicsConfiguration#isTranslucencyCapable}
- * instead
- */
- @Deprecated(forRemoval = true, since = "10")
- public static boolean isTranslucencyCapable(GraphicsConfiguration gc) {
- if (gc == null) {
- throw new NullPointerException("The gc argument should not be null");
- }
- /*
- return gc.isTranslucencyCapable();
- */
- Toolkit curToolkit = Toolkit.getDefaultToolkit();
- if (!(curToolkit instanceof SunToolkit)) {
- return false;
- }
- return ((SunToolkit)curToolkit).isTranslucencyCapable(gc);
- }
-
- /**
- * Sets a 'mixing-cutout' shape for the given component.
- *
- * By default a lightweight component is treated as an opaque rectangle for
- * the purposes of the Heavyweight/Lightweight Components Mixing feature.
- * This method enables developers to set an arbitrary shape to be cut out
- * from heavyweight components positioned underneath the lightweight
- * component in the z-order.
- *
- * The {@code shape} argument may have the following values:
- *
- * - {@code null} - reverts the default cutout shape (the rectangle equal
- * to the component's {@code getBounds()})
- *
- empty-shape - does not cut out anything from heavyweight
- * components. This makes the given lightweight component effectively
- * transparent. Note that descendants of the lightweight component still
- * affect the shapes of heavyweight components. An example of an
- * empty-shape is {@code new Rectangle()}.
- *
- non-empty-shape - the given shape will be cut out from
- * heavyweight components.
- *
- *
- * The most common example when the 'mixing-cutout' shape is needed is a
- * glass pane component. The {@link JRootPane#setGlassPane} method
- * automatically sets the empty-shape as the 'mixing-cutout' shape
- * for the given glass pane component. If a developer needs some other
- * 'mixing-cutout' shape for the glass pane (which is rare), this must be
- * changed manually after installing the glass pane to the root pane.
- *
- * Note that the 'mixing-cutout' shape neither affects painting, nor the
- * mouse events handling for the given component. It is used exclusively
- * for the purposes of the Heavyweight/Lightweight Components Mixing
- * feature.
- *
- * @param component the component that needs non-default
- * 'mixing-cutout' shape
- * @param shape the new 'mixing-cutout' shape
- * @throws NullPointerException if the component argument is {@code null}
- * @deprecated use {@link Component#setMixingCutoutShape} instead
- */
- @Deprecated(forRemoval = true, since = "9")
- public static void setComponentMixingCutoutShape(Component component,
- Shape shape)
- {
- if (component == null) {
- throw new NullPointerException(
- "The component argument should not be null.");
- }
-
- component.setMixingCutoutShape(shape);
- }
-}
-
diff --git a/src/java.desktop/share/classes/java/awt/Container.java b/src/java.desktop/share/classes/java/awt/Container.java
index 5b3d404ff4f..88b07fe9b6e 100644
--- a/src/java.desktop/share/classes/java/awt/Container.java
+++ b/src/java.desktop/share/classes/java/awt/Container.java
@@ -35,6 +35,7 @@
import java.beans.PropertyChangeListener;
import java.io.IOException;
+import java.io.InvalidObjectException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamField;
@@ -3720,8 +3721,15 @@ private void readObject(ObjectInputStream s)
throws ClassNotFoundException, IOException
{
ObjectInputStream.GetField f = s.readFields();
- Component [] tmpComponent = (Component[])f.get("component", EMPTY_ARRAY);
+ // array of components may not be present in the stream or may be null
+ Component [] tmpComponent = (Component[])f.get("component", null);
+ if (tmpComponent == null) {
+ tmpComponent = EMPTY_ARRAY;
+ }
int ncomponents = (Integer) f.get("ncomponents", 0);
+ if (ncomponents < 0 || ncomponents > tmpComponent.length) {
+ throw new InvalidObjectException("Incorrect number of components");
+ }
component = new java.util.ArrayList(ncomponents);
for (int i = 0; i < ncomponents; ++i) {
component.add(tmpComponent[i]);
diff --git a/src/java.desktop/share/classes/javax/swing/JViewport.java b/src/java.desktop/share/classes/javax/swing/JViewport.java
index 44576585435..3fb3b6d76ec 100644
--- a/src/java.desktop/share/classes/javax/swing/JViewport.java
+++ b/src/java.desktop/share/classes/javax/swing/JViewport.java
@@ -61,7 +61,7 @@
*
* NOTE:We have implemented a faster scrolling algorithm that
* does not require a buffer to draw in. The algorithm works as follows:
- *
- The view and parent view and checked to see if they are
+ *
- The view and parent view are checked to see if they are
*
JComponents
,
* if they aren't, stop and repaint the whole viewport.
* - If the viewport is obscured by an ancestor, stop and repaint the whole
diff --git a/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthParser.java b/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthParser.java
index d590b3f2317..8bebd502302 100644
--- a/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthParser.java
+++ b/src/java.desktop/share/classes/javax/swing/plaf/synth/SynthParser.java
@@ -746,12 +746,7 @@ else if (aName.equals(ATTRIBUTE_KEY)) {
value = lookup(aValue, Object.class);
break;
case 1: // boolean
- if (aValue.toUpperCase().equals("TRUE")) {
- value = Boolean.TRUE;
- }
- else {
- value = Boolean.FALSE;
- }
+ value = Boolean.parseBoolean(aValue);
break;
case 2: // dimension
StringTokenizer tok = new StringTokenizer(aValue);
@@ -939,11 +934,11 @@ else if (key.equals(ATTRIBUTE_DEST_INSETS)) {
": destinationInsets must be top left bottom right");
}
else if (key.equals(ATTRIBUTE_PAINT_CENTER)) {
- paintCenter = value.toLowerCase().equals("true");
+ paintCenter = Boolean.parseBoolean(value);
paintCenterSpecified = true;
}
else if (key.equals(ATTRIBUTE_STRETCH)) {
- stretch = value.toLowerCase().equals("true");
+ stretch = Boolean.parseBoolean(value);
stretchSpecified = true;
}
else if (key.equals(ATTRIBUTE_DIRECTION)) {
@@ -989,7 +984,7 @@ else if (value == "VERTICAL_SPLIT") {
}
}
else if (key.equals(ATTRIBUTE_CENTER)) {
- center = value.toLowerCase().equals("true");
+ center = Boolean.parseBoolean(value);
}
}
if (painter == null) {
diff --git a/src/java.desktop/share/classes/sun/applet/AppletSecurity.java b/src/java.desktop/share/classes/sun/applet/AppletSecurity.java
index b9155e81072..2d4c7fce90a 100644
--- a/src/java.desktop/share/classes/sun/applet/AppletSecurity.java
+++ b/src/java.desktop/share/classes/sun/applet/AppletSecurity.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1995, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -370,30 +370,6 @@ public void checkPackageAccess(final String pkgname) {
}
}
- /**
- * Tests if a client can get access to the AWT event queue.
- *
- * This method calls {@code checkPermission} with the
- * {@code AWTPermission("accessEventQueue")} permission.
- *
- * @since 1.1
- * @exception SecurityException if the caller does not have
- * permission to access the AWT event queue.
- */
- @SuppressWarnings({"deprecation",
- "removal"}) // SecurityManager.checkAwtEventQueueAccess
- public void checkAwtEventQueueAccess() {
- AppContext appContext = AppContext.getAppContext();
- AppletClassLoader appletClassLoader = currentAppletClassLoader();
-
- if (AppContext.isMainContext(appContext) && (appletClassLoader != null)) {
- // If we're about to allow access to the main EventQueue,
- // and anything untrusted is on the class context stack,
- // disallow access.
- super.checkPermission(AWTPermissions.CHECK_AWT_EVENTQUEUE_PERMISSION);
- }
- } // checkAwtEventQueueAccess()
-
/**
* Returns the thread group of the applet. We consult the classloader
* if there is one.
diff --git a/src/java.desktop/share/classes/sun/applet/resources/MsgAppletViewer.java b/src/java.desktop/share/classes/sun/applet/resources/MsgAppletViewer.java
index d9ba0253213..70e87bd0353 100644
--- a/src/java.desktop/share/classes/sun/applet/resources/MsgAppletViewer.java
+++ b/src/java.desktop/share/classes/sun/applet/resources/MsgAppletViewer.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -188,10 +188,7 @@ public Object[][] getContents() {
{"appletsecurityexception.checkpackageaccess", "Security Exception: cannot access package: {0}"},
{"appletsecurityexception.checkpackagedefinition", "Security Exception: cannot define package: {0}"},
{"appletsecurityexception.cannotsetfactory", "Security Exception: cannot set factory"},
- {"appletsecurityexception.checkmemberaccess", "Security Exception: check member access"},
{"appletsecurityexception.checkgetprintjob", "Security Exception: getPrintJob"},
- {"appletsecurityexception.checksystemclipboardaccess", "Security Exception: getSystemClipboard"},
- {"appletsecurityexception.checkawteventqueueaccess", "Security Exception: getEventQueue"},
{"appletsecurityexception.checksecurityaccess", "Security Exception: security operation: {0}"},
{"appletsecurityexception.getsecuritycontext.unknown", "unknown class loader type. unable to check for getContext"},
{"appletsecurityexception.checkread.unknown", "unknown class loader type. unable to check for checking read {0}"},
diff --git a/src/java.desktop/share/classes/sun/awt/image/BufImgSurfaceData.java b/src/java.desktop/share/classes/sun/awt/image/BufImgSurfaceData.java
index ac42b424152..025ed19b918 100644
--- a/src/java.desktop/share/classes/sun/awt/image/BufImgSurfaceData.java
+++ b/src/java.desktop/share/classes/sun/awt/image/BufImgSurfaceData.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -25,7 +25,6 @@
package sun.awt.image;
-import java.awt.Color;
import java.awt.Rectangle;
import java.awt.GraphicsConfiguration;
import java.awt.image.ColorModel;
@@ -38,9 +37,6 @@
import sun.java2d.SurfaceData;
import sun.java2d.SunGraphics2D;
-import sun.java2d.StateTrackable;
-import sun.java2d.StateTrackable.*;
-import sun.java2d.StateTracker;
import sun.java2d.loops.SurfaceType;
import sun.java2d.loops.CompositeType;
import sun.java2d.loops.RenderLoops;
@@ -446,8 +442,6 @@ protected void checkCustomComposite() {
// their pixels are immediately retrievable anyway.
}
- private static native void freeNativeICMData(long pData);
-
/**
* Returns destination Image associated with this SurfaceData.
*/
@@ -471,13 +465,5 @@ public static final class ICMColorData {
private ICMColorData(long pData) {
this.pData = pData;
}
-
- @SuppressWarnings("deprecation")
- public void finalize() {
- if (pData != 0L) {
- BufImgSurfaceData.freeNativeICMData(pData);
- pData = 0L;
- }
- }
}
}
diff --git a/src/java.desktop/share/legal/lcms.md b/src/java.desktop/share/legal/lcms.md
index d74475540d5..a8a06325cd0 100644
--- a/src/java.desktop/share/legal/lcms.md
+++ b/src/java.desktop/share/legal/lcms.md
@@ -1,10 +1,10 @@
-## Little Color Management System (LCMS) v2.8
+## Little Color Management System (LCMS) v2.9
### LCMS License
Little Color Management System
-Copyright (c) 1998-2016 Marti Maria Saguer
+Copyright (c) 1998-2011 Marti Maria Saguer
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the "Software"),
diff --git a/src/java.desktop/share/native/common/awt/medialib/mlib_ImageCreate.c b/src/java.desktop/share/native/common/awt/medialib/mlib_ImageCreate.c
index b91bf8891c9..da65a9f433d 100644
--- a/src/java.desktop/share/native/common/awt/medialib/mlib_ImageCreate.c
+++ b/src/java.desktop/share/native/common/awt/medialib/mlib_ImageCreate.c
@@ -227,7 +227,7 @@ mlib_image* mlib_ImageSet(mlib_image *image,
}
/***************************************************************/
-mlib_image *mlib_ImageCreateStruct(mlib_type type,
+JNIEXPORT mlib_image* JNICALL mlib_ImageCreateStruct(mlib_type type,
mlib_s32 channels,
mlib_s32 width,
mlib_s32 height,
@@ -253,7 +253,7 @@ mlib_image *mlib_ImageCreateStruct(mlib_type type,
}
/***************************************************************/
-mlib_image *mlib_ImageCreate(mlib_type type,
+JNIEXPORT mlib_image* JNICALL mlib_ImageCreate(mlib_type type,
mlib_s32 channels,
mlib_s32 width,
mlib_s32 height)
@@ -352,7 +352,7 @@ mlib_image *mlib_ImageCreate(mlib_type type,
}
/***************************************************************/
-void mlib_ImageDelete(mlib_image *img)
+JNIEXPORT void JNICALL mlib_ImageDelete(mlib_image *img)
{
if (img == NULL) return;
if ((img -> flags & MLIB_IMAGE_USERALLOCATED) == 0) {
diff --git a/src/java.desktop/share/native/libawt/awt/image/BufImgSurfaceData.c b/src/java.desktop/share/native/libawt/awt/image/BufImgSurfaceData.c
index 4c33baeca36..c13bbdfd7e5 100644
--- a/src/java.desktop/share/native/libawt/awt/image/BufImgSurfaceData.c
+++ b/src/java.desktop/share/native/libawt/awt/image/BufImgSurfaceData.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -32,6 +32,7 @@
#include "jni_util.h"
/* Define uintptr_t */
#include "gdefs.h"
+#include "Disposer.h"
/**
* This include file contains support code for loops using the
@@ -79,19 +80,6 @@ Java_sun_awt_image_BufImgSurfaceData_initIDs
"Lsun/awt/image/BufImgSurfaceData$ICMColorData;"));
}
-/*
- * Class: sun_java2d_SurfaceData
- * Method: freeNativeICMData
- * Signature: (Ljava/awt/image/IndexColorModel;)V
- */
-JNIEXPORT void JNICALL
-Java_sun_awt_image_BufImgSurfaceData_freeNativeICMData
- (JNIEnv *env, jclass sd, jlong pData)
-{
- ColorData *cdata = (ColorData*)jlong_to_ptr(pData);
- freeICMColorData(cdata);
-}
-
/*
* Class: sun_awt_image_BufImgSurfaceData
* Method: initOps
@@ -139,6 +127,15 @@ Java_sun_awt_image_BufImgSurfaceData_initRaster(JNIEnv *env, jobject bisd,
bisdo->rasbounds.y2 = height;
}
+/*
+ * Releases native structures associated with BufImgSurfaceData.ICMColorData.
+ */
+static void BufImg_Dispose_ICMColorData(JNIEnv *env, jlong pData)
+{
+ ColorData *cdata = (ColorData*)jlong_to_ptr(pData);
+ freeICMColorData(cdata);
+}
+
/*
* Method for disposing native BufImgSD
*/
@@ -373,6 +370,7 @@ static ColorData *BufImg_SetupICM(JNIEnv *env,
}
(*env)->SetObjectField(env, bisdo->icm, colorDataID, colorData);
+ Disposer_AddRecord(env, colorData, BufImg_Dispose_ICMColorData, pData);
}
}
diff --git a/src/java.desktop/share/native/liblcms/LCMS.c b/src/java.desktop/share/native/liblcms/LCMS.c
index 17c49ad826c..329801b07f4 100644
--- a/src/java.desktop/share/native/liblcms/LCMS.c
+++ b/src/java.desktop/share/native/liblcms/LCMS.c
@@ -391,12 +391,12 @@ JNIEXPORT jbyteArray JNICALL Java_sun_java2d_cmm_lcms_LCMS_getTagNative
{
lcmsProfile_p sProf = (lcmsProfile_p)jlong_to_ptr(id);
TagSignature_t sig;
- cmsInt32Number tagSize;
+ cmsUInt32Number tagSize;
jbyte* dataArray = NULL;
jbyteArray data = NULL;
- jint bufSize;
+ cmsUInt32Number bufSize;
sig.j = tagSig;
@@ -839,7 +839,7 @@ static cmsHPROFILE _writeCookedTag(const cmsHPROFILE pfTarget,
for (i = 0; i < tagCount; i++) {
cmsBool isTagReady = FALSE;
const cmsTagSignature s = cmsGetTagSignature(pfTarget, i);
- const cmsInt32Number tagSize = cmsReadRawTag(pfTarget, s, NULL, 0);
+ const cmsUInt32Number tagSize = cmsReadRawTag(pfTarget, s, NULL, 0);
if (s == sig) {
// skip the user supplied tag
diff --git a/src/java.desktop/share/native/liblcms/cmsalpha.c b/src/java.desktop/share/native/liblcms/cmsalpha.c
index 277ed5598c3..d1ad61ab48d 100644
--- a/src/java.desktop/share/native/liblcms/cmsalpha.c
+++ b/src/java.desktop/share/native/liblcms/cmsalpha.c
@@ -30,7 +30,7 @@
//---------------------------------------------------------------------------------
//
// Little Color Management System
-// Copyright (c) 1998-2016 Marti Maria Saguer
+// Copyright (c) 1998-2017 Marti Maria Saguer
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
@@ -55,7 +55,6 @@
#include "lcms2_internal.h"
-
// Alpha copy ------------------------------------------------------------------------------------------------------------------
// Floor to byte, taking care of saturation
@@ -71,16 +70,16 @@ cmsINLINE cmsUInt8Number _cmsQuickSaturateByte(cmsFloat64Number d)
// Return the size in bytes of a given formatter
static
-int trueBytesSize(cmsUInt32Number Format)
+cmsUInt32Number trueBytesSize(cmsUInt32Number Format)
{
- int fmt_bytes = T_BYTES(Format);
+ cmsUInt32Number fmt_bytes = T_BYTES(Format);
- // For double, the T_BYTES field returns zero
- if (fmt_bytes == 0)
- return sizeof(double);
+ // For double, the T_BYTES field returns zero
+ if (fmt_bytes == 0)
+ return sizeof(double);
- // Otherwise, it is already correct for all formats
- return fmt_bytes;
+ // Otherwise, it is already correct for all formats
+ return fmt_bytes;
}
@@ -119,8 +118,13 @@ void from8toDBL(void* dst, const void* src)
static
void from8toHLF(void* dst, const void* src)
{
+#ifndef CMS_NO_HALF_SUPPORT
cmsFloat32Number n = (*(cmsUInt8Number*)src) / 255.0f;
*(cmsUInt16Number*)dst = _cmsFloat2Half(n);
+#else
+ cmsUNUSED_PARAMETER(dst);
+ cmsUNUSED_PARAMETER(src);
+#endif
}
// From 16
@@ -151,8 +155,13 @@ void from16toDBL(void* dst, const void* src)
static
void from16toHLF(void* dst, const void* src)
{
+#ifndef CMS_NO_HALF_SUPPORT
cmsFloat32Number n = (*(cmsUInt16Number*)src) / 65535.0f;
*(cmsUInt16Number*)dst = _cmsFloat2Half(n);
+#else
+ cmsUNUSED_PARAMETER(dst);
+ cmsUNUSED_PARAMETER(src);
+#endif
}
// From Float
@@ -187,8 +196,13 @@ void fromFLTtoDBL(void* dst, const void* src)
static
void fromFLTtoHLF(void* dst, const void* src)
{
+#ifndef CMS_NO_HALF_SUPPORT
cmsFloat32Number n = *(cmsFloat32Number*)src;
*(cmsUInt16Number*)dst = _cmsFloat2Half(n);
+#else
+ cmsUNUSED_PARAMETER(dst);
+ cmsUNUSED_PARAMETER(src);
+#endif
}
@@ -197,27 +211,48 @@ void fromFLTtoHLF(void* dst, const void* src)
static
void fromHLFto8(void* dst, const void* src)
{
+#ifndef CMS_NO_HALF_SUPPORT
cmsFloat32Number n = _cmsHalf2Float(*(cmsUInt16Number*)src);
*(cmsUInt8Number*)dst = _cmsQuickSaturateByte(n * 255.0f);
+#else
+ cmsUNUSED_PARAMETER(dst);
+ cmsUNUSED_PARAMETER(src);
+#endif
+
}
static
void fromHLFto16(void* dst, const void* src)
{
+#ifndef CMS_NO_HALF_SUPPORT
cmsFloat32Number n = _cmsHalf2Float(*(cmsUInt16Number*)src);
*(cmsUInt16Number*)dst = _cmsQuickSaturateWord(n * 65535.0f);
+#else
+ cmsUNUSED_PARAMETER(dst);
+ cmsUNUSED_PARAMETER(src);
+#endif
}
static
void fromHLFtoFLT(void* dst, const void* src)
{
+#ifndef CMS_NO_HALF_SUPPORT
*(cmsFloat32Number*)dst = _cmsHalf2Float(*(cmsUInt16Number*)src);
+#else
+ cmsUNUSED_PARAMETER(dst);
+ cmsUNUSED_PARAMETER(src);
+#endif
}
static
void fromHLFtoDBL(void* dst, const void* src)
{
+#ifndef CMS_NO_HALF_SUPPORT
*(cmsFloat64Number*)dst = (cmsFloat64Number)_cmsHalf2Float(*(cmsUInt16Number*)src);
+#else
+ cmsUNUSED_PARAMETER(dst);
+ cmsUNUSED_PARAMETER(src);
+#endif
}
// From double
@@ -245,8 +280,13 @@ void fromDBLtoFLT(void* dst, const void* src)
static
void fromDBLtoHLF(void* dst, const void* src)
{
+#ifndef CMS_NO_HALF_SUPPORT
cmsFloat32Number n = (cmsFloat32Number) *(cmsFloat64Number*)src;
*(cmsUInt16Number*)dst = _cmsFloat2Half(n);
+#else
+ cmsUNUSED_PARAMETER(dst);
+ cmsUNUSED_PARAMETER(src);
+#endif
}
static
@@ -260,21 +300,22 @@ void copy64(void* dst, const void* src)
static
int FormatterPos(cmsUInt32Number frm)
{
- int b = T_BYTES(frm);
-
- if (b == 0 && T_FLOAT(frm))
- return 4; // DBL
- if (b == 2 && T_FLOAT(frm))
- return 2; // HLF
- if (b == 4 && T_FLOAT(frm))
- return 3; // FLT
- if (b == 2 && !T_FLOAT(frm))
- return 1; // 16
- if (b == 1 && !T_FLOAT(frm))
- return 0; // 8
+ cmsUInt32Number b = T_BYTES(frm);
- return -1; // not recognized
+ if (b == 0 && T_FLOAT(frm))
+ return 4; // DBL
+#ifndef CMS_NO_HALF_SUPPORT
+ if (b == 2 && T_FLOAT(frm))
+ return 2; // HLF
+#endif
+ if (b == 4 && T_FLOAT(frm))
+ return 3; // FLT
+ if (b == 2 && !T_FLOAT(frm))
+ return 1; // 16
+ if (b == 1 && !T_FLOAT(frm))
+ return 0; // 8
+ return -1; // not recognized
}
// Obtains a alpha-to-alpha funmction formatter
@@ -310,12 +351,12 @@ void ComputeIncrementsForChunky(cmsUInt32Number Format,
cmsUInt32Number ComponentPointerIncrements[])
{
cmsUInt32Number channels[cmsMAXCHANNELS];
- int extra = T_EXTRA(Format);
- int nchannels = T_CHANNELS(Format);
- int total_chans = nchannels + extra;
- int i;
- int channelSize = trueBytesSize(Format);
- int pixelSize = channelSize * total_chans;
+ cmsUInt32Number extra = T_EXTRA(Format);
+ cmsUInt32Number nchannels = T_CHANNELS(Format);
+ cmsUInt32Number total_chans = nchannels + extra;
+ cmsUInt32Number i;
+ cmsUInt32Number channelSize = trueBytesSize(Format);
+ cmsUInt32Number pixelSize = channelSize * total_chans;
// Sanity check
if (total_chans <= 0 || total_chans >= cmsMAXCHANNELS)
@@ -368,11 +409,11 @@ void ComputeIncrementsForPlanar(cmsUInt32Number Format,
cmsUInt32Number ComponentPointerIncrements[])
{
cmsUInt32Number channels[cmsMAXCHANNELS];
- int extra = T_EXTRA(Format);
- int nchannels = T_CHANNELS(Format);
- int total_chans = nchannels + extra;
- int i;
- int channelSize = trueBytesSize(Format);
+ cmsUInt32Number extra = T_EXTRA(Format);
+ cmsUInt32Number nchannels = T_CHANNELS(Format);
+ cmsUInt32Number total_chans = nchannels + extra;
+ cmsUInt32Number i;
+ cmsUInt32Number channelSize = trueBytesSize(Format);
// Sanity check
if (total_chans <= 0 || total_chans >= cmsMAXCHANNELS)
diff --git a/src/java.desktop/share/native/liblcms/cmscam02.c b/src/java.desktop/share/native/liblcms/cmscam02.c
index ae7038c5ea9..268677fd6f4 100644
--- a/src/java.desktop/share/native/liblcms/cmscam02.c
+++ b/src/java.desktop/share/native/liblcms/cmscam02.c
@@ -30,7 +30,7 @@
//---------------------------------------------------------------------------------
//
// Little Color Management System
-// Copyright (c) 1998-2016 Marti Maria Saguer
+// Copyright (c) 1998-2017 Marti Maria Saguer
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
diff --git a/src/java.desktop/share/native/liblcms/cmscgats.c b/src/java.desktop/share/native/liblcms/cmscgats.c
index c4f4fb5d31a..ff88ffb1367 100644
--- a/src/java.desktop/share/native/liblcms/cmscgats.c
+++ b/src/java.desktop/share/native/liblcms/cmscgats.c
@@ -30,7 +30,7 @@
//---------------------------------------------------------------------------------
//
// Little Color Management System
-// Copyright (c) 1998-2016 Marti Maria Saguer
+// Copyright (c) 1998-2017 Marti Maria Saguer
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
@@ -176,23 +176,24 @@ typedef struct {
SUBALLOCATOR Allocator; // String suballocator -- just to keep it fast
// Parser state machine
- SYMBOL sy; // Current symbol
- int ch; // Current character
+ SYMBOL sy; // Current symbol
+ int ch; // Current character
+
+ cmsInt32Number inum; // integer value
+ cmsFloat64Number dnum; // real value
- int inum; // integer value
- cmsFloat64Number dnum; // real value
char id[MAXID]; // identifier
char str[MAXSTR]; // string
// Allowed keywords & datasets. They have visibility on whole stream
- KEYVALUE* ValidKeywords;
- KEYVALUE* ValidSampleID;
+ KEYVALUE* ValidKeywords;
+ KEYVALUE* ValidSampleID;
char* Source; // Points to loc. being parsed
- int lineno; // line counter for error reporting
+ cmsInt32Number lineno; // line counter for error reporting
FILECTX* FileStack[MAXINCLUDE]; // Stack of files being parsed
- int IncludeSP; // Include Stack Pointer
+ cmsInt32Number IncludeSP; // Include Stack Pointer
char* MemoryBlock; // The stream if holded in memory
@@ -265,65 +266,64 @@ static PROPERTY PredefinedProperties[] = {
{"PROD_DATE", WRITE_STRINGIFY}, // Identifies year and month of production of the target in the form yyyy:mm.
{"SERIAL", WRITE_STRINGIFY}, // Uniquely identifies individual physical target.
- {"MATERIAL", WRITE_STRINGIFY}, // Identifies the material on which the target was produced using a code
- // uniquely identifying th e material. This is intend ed to be used for IT8.7
- // physical targets only (i.e . IT8.7/1 a nd IT8.7/2).
-
- {"INSTRUMENTATION", WRITE_STRINGIFY}, // Used to report the specific instrumentation used (manufacturer and
- // model number) to generate the data reported. This data will often
- // provide more information about the particular data collected than an
- // extensive list of specific details. This is particularly important for
- // spectral data or data derived from spectrophotometry.
+ {"MATERIAL", WRITE_STRINGIFY}, // Identifies the material on which the target was produced using a code
+ // uniquely identifying th e material. This is intend ed to be used for IT8.7
+ // physical targets only (i.e . IT8.7/1 a nd IT8.7/2).
- {"MEASUREMENT_SOURCE", WRITE_STRINGIFY}, // Illumination used for spectral measurements. This data helps provide
- // a guide to the potential for issues of paper fluorescence, etc.
+ {"INSTRUMENTATION", WRITE_STRINGIFY}, // Used to report the specific instrumentation used (manufacturer and
+ // model number) to generate the data reported. This data will often
+ // provide more information about the particular data collected than an
+ // extensive list of specific details. This is particularly important for
+ // spectral data or data derived from spectrophotometry.
- {"PRINT_CONDITIONS", WRITE_STRINGIFY}, // Used to define the characteristics of the printed sheet being reported.
- // Where standard conditions have been defined (e.g., SWOP at nominal)
- // named conditions may suffice. Otherwise, detailed information is
- // needed.
+ {"MEASUREMENT_SOURCE", WRITE_STRINGIFY}, // Illumination used for spectral measurements. This data helps provide
+ // a guide to the potential for issues of paper fluorescence, etc.
- {"SAMPLE_BACKING", WRITE_STRINGIFY}, // Identifies the backing material used behind the sample during
- // measurement. Allowed values are “black”, “white”, or {"na".
+ {"PRINT_CONDITIONS", WRITE_STRINGIFY}, // Used to define the characteristics of the printed sheet being reported.
+ // Where standard conditions have been defined (e.g., SWOP at nominal)
+ // named conditions may suffice. Otherwise, detailed information is
+ // needed.
- {"CHISQ_DOF", WRITE_STRINGIFY}, // Degrees of freedom associated with the Chi squared statistic
+ {"SAMPLE_BACKING", WRITE_STRINGIFY}, // Identifies the backing material used behind the sample during
+ // measurement. Allowed values are “black”, “white”, or {"na".
- // below properties are new in recent specs:
+ {"CHISQ_DOF", WRITE_STRINGIFY}, // Degrees of freedom associated with the Chi squared statistic
+ // below properties are new in recent specs:
{"MEASUREMENT_GEOMETRY", WRITE_STRINGIFY}, // The type of measurement, either reflection or transmission, should be indicated
- // along with details of the geometry and the aperture size and shape. For example,
- // for transmission measurements it is important to identify 0/diffuse, diffuse/0,
- // opal or integrating sphere, etc. For reflection it is important to identify 0/45,
- // 45/0, sphere (specular included or excluded), etc.
+ // along with details of the geometry and the aperture size and shape. For example,
+ // for transmission measurements it is important to identify 0/diffuse, diffuse/0,
+ // opal or integrating sphere, etc. For reflection it is important to identify 0/45,
+ // 45/0, sphere (specular included or excluded), etc.
- {"FILTER", WRITE_STRINGIFY}, // Identifies the use of physical filter(s) during measurement. Typically used to
- // denote the use of filters such as none, D65, Red, Green or Blue.
+ {"FILTER", WRITE_STRINGIFY}, // Identifies the use of physical filter(s) during measurement. Typically used to
+ // denote the use of filters such as none, D65, Red, Green or Blue.
- {"POLARIZATION", WRITE_STRINGIFY}, // Identifies the use of a physical polarization filter during measurement. Allowed
- // values are {"yes”, “white”, “none” or “na”.
+ {"POLARIZATION", WRITE_STRINGIFY}, // Identifies the use of a physical polarization filter during measurement. Allowed
+ // values are {"yes”, “white”, “none” or “na”.
- {"WEIGHTING_FUNCTION", WRITE_PAIR}, // Indicates such functions as: the CIE standard observer functions used in the
- // calculation of various data parameters (2 degree and 10 degree), CIE standard
- // illuminant functions used in the calculation of various data parameters (e.g., D50,
- // D65, etc.), density status response, etc. If used there shall be at least one
- // name-value pair following the WEIGHTING_FUNCTION tag/keyword. The first attribute
- // in the set shall be {"name" and shall identify the particular parameter used.
- // The second shall be {"value" and shall provide the value associated with that name.
- // For ASCII data, a string containing the Name and Value attribute pairs shall follow
- // the weighting function keyword. A semi-colon separates attribute pairs from each
- // other and within the attribute the name and value are separated by a comma.
+ {"WEIGHTING_FUNCTION", WRITE_PAIR}, // Indicates such functions as: the CIE standard observer functions used in the
+ // calculation of various data parameters (2 degree and 10 degree), CIE standard
+ // illuminant functions used in the calculation of various data parameters (e.g., D50,
+ // D65, etc.), density status response, etc. If used there shall be at least one
+ // name-value pair following the WEIGHTING_FUNCTION tag/keyword. The first attribute
+ // in the set shall be {"name" and shall identify the particular parameter used.
+ // The second shall be {"value" and shall provide the value associated with that name.
+ // For ASCII data, a string containing the Name and Value attribute pairs shall follow
+ // the weighting function keyword. A semi-colon separates attribute pairs from each
+ // other and within the attribute the name and value are separated by a comma.
- {"COMPUTATIONAL_PARAMETER", WRITE_PAIR}, // Parameter that is used in computing a value from measured data. Name is the name
- // of the calculation, parameter is the name of the parameter used in the calculation
- // and value is the value of the parameter.
+ {"COMPUTATIONAL_PARAMETER", WRITE_PAIR}, // Parameter that is used in computing a value from measured data. Name is the name
+ // of the calculation, parameter is the name of the parameter used in the calculation
+ // and value is the value of the parameter.
- {"TARGET_TYPE", WRITE_STRINGIFY}, // The type of target being measured, e.g. IT8.7/1, IT8.7/3, user defined, etc.
+ {"TARGET_TYPE", WRITE_STRINGIFY}, // The type of target being measured, e.g. IT8.7/1, IT8.7/3, user defined, etc.
- {"COLORANT", WRITE_STRINGIFY}, // Identifies the colorant(s) used in creating the target.
+ {"COLORANT", WRITE_STRINGIFY}, // Identifies the colorant(s) used in creating the target.
- {"TABLE_DESCRIPTOR", WRITE_STRINGIFY}, // Describes the purpose or contents of a data table.
+ {"TABLE_DESCRIPTOR", WRITE_STRINGIFY}, // Describes the purpose or contents of a data table.
- {"TABLE_NAME", WRITE_STRINGIFY} // Provides a short name for a data table.
+ {"TABLE_NAME", WRITE_STRINGIFY} // Provides a short name for a data table.
};
#define NUMPREDEFINEDPROPS (sizeof(PredefinedProperties)/sizeof(PROPERTY))
@@ -564,13 +564,13 @@ cmsFloat64Number xpow10(int n)
// Reads a Real number, tries to follow from integer number
static
-void ReadReal(cmsIT8* it8, int inum)
+void ReadReal(cmsIT8* it8, cmsInt32Number inum)
{
- it8->dnum = (cmsFloat64Number) inum;
+ it8->dnum = (cmsFloat64Number)inum;
while (isdigit(it8->ch)) {
- it8->dnum = it8->dnum * 10.0 + (it8->ch - '0');
+ it8->dnum = (cmsFloat64Number)it8->dnum * 10.0 + (cmsFloat64Number)(it8->ch - '0');
NextCh(it8);
}
@@ -583,7 +583,7 @@ void ReadReal(cmsIT8* it8, int inum)
while (isdigit(it8->ch)) {
- frac = frac * 10.0 + (it8->ch - '0');
+ frac = frac * 10.0 + (cmsFloat64Number)(it8->ch - '0');
prec++;
NextCh(it8);
}
@@ -594,8 +594,8 @@ void ReadReal(cmsIT8* it8, int inum)
// Exponent, example 34.00E+20
if (toupper(it8->ch) == 'E') {
- int e;
- int sgn;
+ cmsInt32Number e;
+ cmsInt32Number sgn;
NextCh(it8); sgn = 1;
@@ -610,17 +610,19 @@ void ReadReal(cmsIT8* it8, int inum)
NextCh(it8);
}
- e = 0;
- while (isdigit(it8->ch)) {
+ e = 0;
+ while (isdigit(it8->ch)) {
- if ((cmsFloat64Number) e * 10L < INT_MAX)
- e = e * 10 + (it8->ch - '0');
+ cmsInt32Number digit = (it8->ch - '0');
- NextCh(it8);
- }
+ if ((cmsFloat64Number)e * 10.0 + (cmsFloat64Number)digit < (cmsFloat64Number)+2147483647.0)
+ e = e * 10 + digit;
+
+ NextCh(it8);
+ }
- e = sgn*e;
- it8 -> dnum = it8 -> dnum * xpow10(e);
+ e = sgn*e;
+ it8->dnum = it8->dnum * xpow10(e);
}
}
@@ -638,12 +640,12 @@ cmsFloat64Number ParseFloatNumber(const char *Buffer)
if (*Buffer == '-' || *Buffer == '+') {
- sign = (*Buffer == '-') ? -1 : 1;
- Buffer++;
+ sign = (*Buffer == '-') ? -1 : 1;
+ Buffer++;
}
- while (*Buffer && isdigit((int) *Buffer)) {
+ while (*Buffer && isdigit((int)*Buffer)) {
dnum = dnum * 10.0 + (*Buffer - '0');
if (*Buffer) Buffer++;
@@ -652,11 +654,11 @@ cmsFloat64Number ParseFloatNumber(const char *Buffer)
if (*Buffer == '.') {
cmsFloat64Number frac = 0.0; // fraction
- int prec = 0; // precission
+ int prec = 0; // precision
if (*Buffer) Buffer++;
- while (*Buffer && isdigit((int) *Buffer)) {
+ while (*Buffer && isdigit((int)*Buffer)) {
frac = frac * 10.0 + (*Buffer - '0');
prec++;
@@ -687,17 +689,19 @@ cmsFloat64Number ParseFloatNumber(const char *Buffer)
if (*Buffer) Buffer++;
}
- e = 0;
- while (*Buffer && isdigit((int) *Buffer)) {
+ e = 0;
+ while (*Buffer && isdigit((int)*Buffer)) {
- if ((cmsFloat64Number) e * 10L < INT_MAX)
- e = e * 10 + (*Buffer - '0');
+ cmsInt32Number digit = (*Buffer - '0');
- if (*Buffer) Buffer++;
- }
+ if ((cmsFloat64Number)e * 10.0 + digit < (cmsFloat64Number)+2147483647.0)
+ e = e * 10 + digit;
+
+ if (*Buffer) Buffer++;
+ }
- e = sgn*e;
- dnum = dnum * xpow10(e);
+ e = sgn*e;
+ dnum = dnum * xpow10(e);
}
return sign * dnum;
@@ -766,7 +770,7 @@ void InSymbol(cmsIT8* it8)
if (it8->ch >= 'A' && it8->ch <= 'F') j = it8->ch -'A'+10;
else j = it8->ch - '0';
- if ((long) it8->inum * 16L > (long) INT_MAX)
+ if ((cmsFloat64Number) it8->inum * 16.0 + (cmsFloat64Number) j > (cmsFloat64Number)+2147483647.0)
{
SynError(it8, "Invalid hexadecimal number");
return;
@@ -787,7 +791,7 @@ void InSymbol(cmsIT8* it8)
{
j = it8->ch - '0';
- if ((long) it8->inum * 2L > (long) INT_MAX)
+ if ((cmsFloat64Number) it8->inum * 2.0 + j > (cmsFloat64Number)+2147483647.0)
{
SynError(it8, "Invalid binary number");
return;
@@ -803,14 +807,16 @@ void InSymbol(cmsIT8* it8)
while (isdigit(it8->ch)) {
- if ((long) it8->inum * 10L > (long) INT_MAX) {
+ cmsInt32Number digit = (it8->ch - '0');
+
+ if ((cmsFloat64Number) it8->inum * 10.0 + (cmsFloat64Number) digit > (cmsFloat64Number) +2147483647.0) {
ReadReal(it8, it8->inum);
it8->sy = SDNUM;
it8->dnum *= sign;
return;
}
- it8->inum = it8->inum * 10 + (it8->ch - '0');
+ it8->inum = it8->inum * 10 + digit;
NextCh(it8);
}
@@ -1515,8 +1521,8 @@ cmsBool SetDataFormat(cmsIT8* it8, int n, const char *label)
cmsBool CMSEXPORT cmsIT8SetDataFormat(cmsHANDLE h, int n, const char *Sample)
{
- cmsIT8* it8 = (cmsIT8*) h;
- return SetDataFormat(it8, n, Sample);
+ cmsIT8* it8 = (cmsIT8*)h;
+ return SetDataFormat(it8, n, Sample);
}
static
@@ -1541,8 +1547,8 @@ static
char* GetData(cmsIT8* it8, int nSet, int nField)
{
TABLE* t = GetTable(it8);
- int nSamples = t -> nSamples;
- int nPatches = t -> nPatches;
+ int nSamples = t -> nSamples;
+ int nPatches = t -> nPatches;
if (nSet >= nPatches || nField >= nSamples)
return NULL;
@@ -1973,67 +1979,67 @@ cmsBool HeaderSection(cmsIT8* it8)
case SIDENT:
- strncpy(VarName, it8->id, MAXID-1);
- VarName[MAXID-1] = 0;
+ strncpy(VarName, it8->id, MAXID - 1);
+ VarName[MAXID - 1] = 0;
- if (!IsAvailableOnList(it8-> ValidKeywords, VarName, NULL, &Key)) {
+ if (!IsAvailableOnList(it8->ValidKeywords, VarName, NULL, &Key)) {
#ifdef CMS_STRICT_CGATS
- return SynError(it8, "Undefined keyword '%s'", VarName);
+ return SynError(it8, "Undefined keyword '%s'", VarName);
#else
- Key = AddAvailableProperty(it8, VarName, WRITE_UNCOOKED);
- if (Key == NULL) return FALSE;
+ Key = AddAvailableProperty(it8, VarName, WRITE_UNCOOKED);
+ if (Key == NULL) return FALSE;
#endif
- }
+ }
- InSymbol(it8);
- if (!GetVal(it8, Buffer, MAXSTR-1, "Property data expected")) return FALSE;
+ InSymbol(it8);
+ if (!GetVal(it8, Buffer, MAXSTR - 1, "Property data expected")) return FALSE;
- if(Key->WriteAs != WRITE_PAIR) {
- AddToList(it8, &GetTable(it8)->HeaderList, VarName, NULL, Buffer,
- (it8->sy == SSTRING) ? WRITE_STRINGIFY : WRITE_UNCOOKED);
- }
- else {
- const char *Subkey;
- char *Nextkey;
- if (it8->sy != SSTRING)
- return SynError(it8, "Invalid value '%s' for property '%s'.", Buffer, VarName);
-
- // chop the string as a list of "subkey, value" pairs, using ';' as a separator
- for (Subkey = Buffer; Subkey != NULL; Subkey = Nextkey)
- {
- char *Value, *temp;
-
- // identify token pair boundary
- Nextkey = (char*) strchr(Subkey, ';');
- if(Nextkey)
- *Nextkey++ = '\0';
-
- // for each pair, split the subkey and the value
- Value = (char*) strrchr(Subkey, ',');
- if(Value == NULL)
- return SynError(it8, "Invalid value for property '%s'.", VarName);
-
- // gobble the spaces before the coma, and the coma itself
- temp = Value++;
- do *temp-- = '\0'; while(temp >= Subkey && *temp == ' ');
-
- // gobble any space at the right
- temp = Value + strlen(Value) - 1;
- while(*temp == ' ') *temp-- = '\0';
-
- // trim the strings from the left
- Subkey += strspn(Subkey, " ");
- Value += strspn(Value, " ");
-
- if(Subkey[0] == 0 || Value[0] == 0)
- return SynError(it8, "Invalid value for property '%s'.", VarName);
- AddToList(it8, &GetTable(it8)->HeaderList, VarName, Subkey, Value, WRITE_PAIR);
- }
+ if (Key->WriteAs != WRITE_PAIR) {
+ AddToList(it8, &GetTable(it8)->HeaderList, VarName, NULL, Buffer,
+ (it8->sy == SSTRING) ? WRITE_STRINGIFY : WRITE_UNCOOKED);
+ }
+ else {
+ const char *Subkey;
+ char *Nextkey;
+ if (it8->sy != SSTRING)
+ return SynError(it8, "Invalid value '%s' for property '%s'.", Buffer, VarName);
+
+ // chop the string as a list of "subkey, value" pairs, using ';' as a separator
+ for (Subkey = Buffer; Subkey != NULL; Subkey = Nextkey)
+ {
+ char *Value, *temp;
+
+ // identify token pair boundary
+ Nextkey = (char*)strchr(Subkey, ';');
+ if (Nextkey)
+ *Nextkey++ = '\0';
+
+ // for each pair, split the subkey and the value
+ Value = (char*)strrchr(Subkey, ',');
+ if (Value == NULL)
+ return SynError(it8, "Invalid value for property '%s'.", VarName);
+
+ // gobble the spaces before the coma, and the coma itself
+ temp = Value++;
+ do *temp-- = '\0'; while (temp >= Subkey && *temp == ' ');
+
+ // gobble any space at the right
+ temp = Value + strlen(Value) - 1;
+ while (*temp == ' ') *temp-- = '\0';
+
+ // trim the strings from the left
+ Subkey += strspn(Subkey, " ");
+ Value += strspn(Value, " ");
+
+ if (Subkey[0] == 0 || Value[0] == 0)
+ return SynError(it8, "Invalid value for property '%s'.", VarName);
+ AddToList(it8, &GetTable(it8)->HeaderList, VarName, Subkey, Value, WRITE_PAIR);
}
+ }
- InSymbol(it8);
- break;
+ InSymbol(it8);
+ break;
case SEOLN: break;
@@ -2062,7 +2068,6 @@ void ReadType(cmsIT8* it8, char* SheetTypePtr)
while (it8->ch != '\r' && it8 ->ch != '\n' && it8->ch != '\t' && it8 -> ch != 0) {
- *SheetTypePtr++= (char) it8 ->ch;
if (cnt++ < MAXSTR)
*SheetTypePtr++= (char) it8 ->ch;
NextCh(it8);
@@ -2257,10 +2262,10 @@ void CookPointers(cmsIT8* it8)
// that should be something like some printable characters plus a \n
// returns 0 if this is not like a CGATS, or an integer otherwise. This integer is the number of words in first line?
static
-int IsMyBlock(const cmsUInt8Number* Buffer, int n)
+int IsMyBlock(const cmsUInt8Number* Buffer, cmsUInt32Number n)
{
int words = 1, space = 0, quot = 0;
- int i;
+ cmsUInt32Number i;
if (n < 10) return 0; // Too small
@@ -2748,7 +2753,7 @@ int CMSEXPORT cmsIT8SetTableByLabel(cmsHANDLE hIT8, const char* cSet, const char
{
const char* cLabelFld;
char Type[256], Label[256];
- int nTable;
+ cmsUInt32Number nTable;
_cmsAssert(hIT8 != NULL);
@@ -2761,7 +2766,7 @@ int CMSEXPORT cmsIT8SetTableByLabel(cmsHANDLE hIT8, const char* cSet, const char
cLabelFld = cmsIT8GetData(hIT8, cSet, cField);
if (!cLabelFld) return -1;
- if (sscanf(cLabelFld, "%255s %d %255s", Label, &nTable, Type) != 3)
+ if (sscanf(cLabelFld, "%255s %u %255s", Label, &nTable, Type) != 3)
return -1;
if (ExpectedType != NULL && *ExpectedType == 0)
diff --git a/src/java.desktop/share/native/liblcms/cmscnvrt.c b/src/java.desktop/share/native/liblcms/cmscnvrt.c
index 2ac99be19e4..04c6419fc15 100644
--- a/src/java.desktop/share/native/liblcms/cmscnvrt.c
+++ b/src/java.desktop/share/native/liblcms/cmscnvrt.c
@@ -30,7 +30,7 @@
//---------------------------------------------------------------------------------
//
// Little Color Management System
-// Copyright (c) 1998-2016 Marti Maria Saguer
+// Copyright (c) 1998-2017 Marti Maria Saguer
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
@@ -392,11 +392,12 @@ cmsBool IsEmptyLayer(cmsMAT3* m, cmsVEC3* off)
// Compute the conversion layer
static
-cmsBool ComputeConversion(int i, cmsHPROFILE hProfiles[],
- cmsUInt32Number Intent,
- cmsBool BPC,
- cmsFloat64Number AdaptationState,
- cmsMAT3* m, cmsVEC3* off)
+cmsBool ComputeConversion(cmsUInt32Number i,
+ cmsHPROFILE hProfiles[],
+ cmsUInt32Number Intent,
+ cmsBool BPC,
+ cmsFloat64Number AdaptationState,
+ cmsMAT3* m, cmsVEC3* off)
{
int k;
@@ -708,7 +709,7 @@ cmsPipeline* CMSEXPORT _cmsDefaultICCintents(cmsContext ContextID,
// Translate black-preserving intents to ICC ones
static
-int TranslateNonICCIntents(int Intent)
+cmsUInt32Number TranslateNonICCIntents(cmsUInt32Number Intent)
{
switch (Intent) {
case INTENT_PRESERVE_K_ONLY_PERCEPTUAL:
diff --git a/src/java.desktop/share/native/liblcms/cmserr.c b/src/java.desktop/share/native/liblcms/cmserr.c
index fc74aa7fa01..8e1e7566e0a 100644
--- a/src/java.desktop/share/native/liblcms/cmserr.c
+++ b/src/java.desktop/share/native/liblcms/cmserr.c
@@ -30,7 +30,7 @@
//---------------------------------------------------------------------------------
//
// Little Color Management System
-// Copyright (c) 1998-2016 Marti Maria Saguer
+// Copyright (c) 1998-2017 Marti Maria Saguer
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
@@ -83,9 +83,11 @@ long int CMSEXPORT cmsfilelength(FILE* f)
long int p , n;
p = ftell(f); // register current file position
+ if (p == -1L)
+ return -1L;
if (fseek(f, 0, SEEK_END) != 0) {
- return -1;
+ return -1L;
}
n = ftell(f);
@@ -115,7 +117,7 @@ cmsBool _cmsRegisterMemHandlerPlugin(cmsContext ContextID, cmsPluginBase* Plug
// *********************************************************************************
// This is the default memory allocation function. It does a very coarse
-// check of amout of memory, just to prevent exploits
+// check of amount of memory, just to prevent exploits
static
void* _cmsMallocDefaultFn(cmsContext ContextID, cmsUInt32Number size)
{
@@ -222,7 +224,7 @@ void _cmsAllocMemPluginChunk(struct _cmsContext_struct* ctx, const struct _cmsCo
}
else {
- // To reset it, we use the default allocators, which cannot be overriden
+ // To reset it, we use the default allocators, which cannot be overridden
ctx ->chunks[MemPlugin] = &ctx ->DefaultMemoryManager;
}
}
diff --git a/src/java.desktop/share/native/liblcms/cmsgamma.c b/src/java.desktop/share/native/liblcms/cmsgamma.c
index e940fe28feb..9f0645fb8bc 100644
--- a/src/java.desktop/share/native/liblcms/cmsgamma.c
+++ b/src/java.desktop/share/native/liblcms/cmsgamma.c
@@ -73,10 +73,11 @@
// The list of supported parametric curves
typedef struct _cmsParametricCurvesCollection_st {
- int nFunctions; // Number of supported functions in this chunk
- int FunctionTypes[MAX_TYPES_IN_LCMS_PLUGIN]; // The identification types
- int ParameterCount[MAX_TYPES_IN_LCMS_PLUGIN]; // Number of parameters for each function
- cmsParametricCurveEvaluator Evaluator; // The evaluator
+ cmsUInt32Number nFunctions; // Number of supported functions in this chunk
+ cmsInt32Number FunctionTypes[MAX_TYPES_IN_LCMS_PLUGIN]; // The identification types
+ cmsUInt32Number ParameterCount[MAX_TYPES_IN_LCMS_PLUGIN]; // Number of parameters for each function
+
+ cmsParametricCurveEvaluator Evaluator; // The evaluator
struct _cmsParametricCurvesCollection_st* Next; // Next in list
@@ -194,7 +195,7 @@ int IsInSet(int Type, _cmsParametricCurvesCollection* c)
{
int i;
- for (i=0; i < c ->nFunctions; i++)
+ for (i=0; i < (int) c ->nFunctions; i++)
if (abs(Type) == c ->FunctionTypes[i]) return i;
return -1;
@@ -238,20 +239,20 @@ _cmsParametricCurvesCollection *GetParametricCurveByType(cmsContext ContextID, i
// no optimation curve is computed. nSegments may also be zero in the inverse case, where only the
// optimization curve is given. Both features simultaneously is an error
static
-cmsToneCurve* AllocateToneCurveStruct(cmsContext ContextID, cmsInt32Number nEntries,
- cmsInt32Number nSegments, const cmsCurveSegment* Segments,
+cmsToneCurve* AllocateToneCurveStruct(cmsContext ContextID, cmsUInt32Number nEntries,
+ cmsUInt32Number nSegments, const cmsCurveSegment* Segments,
const cmsUInt16Number* Values)
{
cmsToneCurve* p;
- int i;
+ cmsUInt32Number i;
// We allow huge tables, which are then restricted for smoothing operations
- if (nEntries > 65530 || nEntries < 0) {
+ if (nEntries > 65530) {
cmsSignalError(ContextID, cmsERROR_RANGE, "Couldn't create tone curve of more than 65530 entries");
return NULL;
}
- if (nEntries <= 0 && nSegments <= 0) {
+ if (nEntries == 0 && nSegments == 0) {
cmsSignalError(ContextID, cmsERROR_RANGE, "Couldn't create tone curve with zero segments and no table");
return NULL;
}
@@ -261,7 +262,7 @@ cmsToneCurve* AllocateToneCurveStruct(cmsContext ContextID, cmsInt32Number nEntr
if (!p) return NULL;
// In this case, there are no segments
- if (nSegments <= 0) {
+ if (nSegments == 0) {
p ->Segments = NULL;
p ->Evals = NULL;
}
@@ -277,7 +278,7 @@ cmsToneCurve* AllocateToneCurveStruct(cmsContext ContextID, cmsInt32Number nEntr
// This 16-bit table contains a limited precision representation of the whole curve and is kept for
// increasing xput on certain operations.
- if (nEntries <= 0) {
+ if (nEntries == 0) {
p ->Table16 = NULL;
}
else {
@@ -303,7 +304,7 @@ cmsToneCurve* AllocateToneCurveStruct(cmsContext ContextID, cmsInt32Number nEntr
p ->SegInterp = (cmsInterpParams**) _cmsCalloc(ContextID, nSegments, sizeof(cmsInterpParams*));
if (p ->SegInterp == NULL) goto Error;
- for (i=0; i< nSegments; i++) {
+ for (i=0; i < nSegments; i++) {
// Type 0 is a special marker for table-based curves
if (Segments[i].Type == 0)
@@ -359,7 +360,7 @@ cmsFloat64Number DefaultEvalParametricFn(cmsInt32Number Type, const cmsFloat64Nu
// Type 1 Reversed: X = Y ^1/gamma
case -1:
- if (R < 0) {
+ if (R < 0) {
if (fabs(Params[0] - 1.0) < MATRIX_DET_TOLERANCE)
Val = R;
@@ -367,80 +368,123 @@ cmsFloat64Number DefaultEvalParametricFn(cmsInt32Number Type, const cmsFloat64Nu
Val = 0;
}
else
- Val = pow(R, 1/Params[0]);
+ {
+ if (fabs(Params[0]) < MATRIX_DET_TOLERANCE)
+ Val = PLUS_INF;
+ else
+ Val = pow(R, 1 / Params[0]);
+ }
break;
// CIE 122-1966
// Y = (aX + b)^Gamma | X >= -b/a
// Y = 0 | else
case 2:
- disc = -Params[2] / Params[1];
+ {
- if (R >= disc ) {
+ if (fabs(Params[1]) < MATRIX_DET_TOLERANCE)
+ {
+ Val = 0;
+ }
+ else
+ {
+ disc = -Params[2] / Params[1];
- e = Params[1]*R + Params[2];
+ if (R >= disc) {
- if (e > 0)
- Val = pow(e, Params[0]);
+ e = Params[1] * R + Params[2];
+
+ if (e > 0)
+ Val = pow(e, Params[0]);
+ else
+ Val = 0;
+ }
else
Val = 0;
}
- else
- Val = 0;
- break;
+ }
+ break;
// Type 2 Reversed
// X = (Y ^1/g - b) / a
case -2:
- if (R < 0)
+ {
+ if (fabs(Params[0]) < MATRIX_DET_TOLERANCE ||
+ fabs(Params[1]) < MATRIX_DET_TOLERANCE)
+ {
Val = 0;
+ }
else
- Val = (pow(R, 1.0/Params[0]) - Params[2]) / Params[1];
+ {
+ if (R < 0)
+ Val = 0;
+ else
+ Val = (pow(R, 1.0 / Params[0]) - Params[2]) / Params[1];
- if (Val < 0)
- Val = 0;
- break;
+ if (Val < 0)
+ Val = 0;
+ }
+ }
+ break;
// IEC 61966-3
// Y = (aX + b)^Gamma | X <= -b/a
// Y = c | else
case 3:
- disc = -Params[2] / Params[1];
- if (disc < 0)
- disc = 0;
+ {
+ if (fabs(Params[1]) < MATRIX_DET_TOLERANCE)
+ {
+ Val = 0;
+ }
+ else
+ {
+ disc = -Params[2] / Params[1];
+ if (disc < 0)
+ disc = 0;
- if (R >= disc) {
+ if (R >= disc) {
- e = Params[1]*R + Params[2];
+ e = Params[1] * R + Params[2];
- if (e > 0)
- Val = pow(e, Params[0]) + Params[3];
+ if (e > 0)
+ Val = pow(e, Params[0]) + Params[3];
+ else
+ Val = 0;
+ }
else
- Val = 0;
+ Val = Params[3];
}
- else
- Val = Params[3];
- break;
+ }
+ break;
// Type 3 reversed
// X=((Y-c)^1/g - b)/a | (Y>=c)
// X=-b/a | (Y= Params[3]) {
+ {
+ if (fabs(Params[1]) < MATRIX_DET_TOLERANCE)
+ {
+ Val = 0;
+ }
+ else
+ {
+ if (R >= Params[3]) {
- e = R - Params[3];
+ e = R - Params[3];
- if (e > 0)
- Val = (pow(e, 1/Params[0]) - Params[2]) / Params[1];
- else
- Val = 0;
- }
- else {
- Val = -Params[2] / Params[1];
+ if (e > 0)
+ Val = (pow(e, 1 / Params[0]) - Params[2]) / Params[1];
+ else
+ Val = 0;
+ }
+ else {
+ Val = -Params[2] / Params[1];
+ }
}
- break;
+ }
+ break;
// IEC 61966-2.1 (sRGB)
@@ -464,20 +508,31 @@ cmsFloat64Number DefaultEvalParametricFn(cmsInt32Number Type, const cmsFloat64Nu
// X=((Y^1/g-b)/a) | Y >= (ad+b)^g
// X=Y/c | Y< (ad+b)^g
case -4:
- e = Params[1] * Params[4] + Params[2];
- if (e < 0)
- disc = 0;
+ {
+ if (fabs(Params[0]) < MATRIX_DET_TOLERANCE ||
+ fabs(Params[1]) < MATRIX_DET_TOLERANCE ||
+ fabs(Params[3]) < MATRIX_DET_TOLERANCE)
+ {
+ Val = 0;
+ }
else
- disc = pow(e, Params[0]);
+ {
+ e = Params[1] * Params[4] + Params[2];
+ if (e < 0)
+ disc = 0;
+ else
+ disc = pow(e, Params[0]);
- if (R >= disc) {
+ if (R >= disc) {
- Val = (pow(R, 1.0/Params[0]) - Params[2]) / Params[1];
- }
- else {
- Val = R / Params[3];
+ Val = (pow(R, 1.0 / Params[0]) - Params[2]) / Params[1];
+ }
+ else {
+ Val = R / Params[3];
+ }
}
- break;
+ }
+ break;
// Y = (aX + b)^Gamma + e | X >= d
@@ -501,20 +556,29 @@ cmsFloat64Number DefaultEvalParametricFn(cmsInt32Number Type, const cmsFloat64Nu
// X=((Y-e)1/g-b)/a | Y >=(ad+b)^g+e), cd+f
// X=(Y-f)/c | else
case -5:
-
- disc = Params[3] * Params[4] + Params[6];
- if (R >= disc) {
-
- e = R - Params[5];
- if (e < 0)
- Val = 0;
- else
- Val = (pow(e, 1.0/Params[0]) - Params[2]) / Params[1];
+ {
+ if (fabs(Params[1]) < MATRIX_DET_TOLERANCE ||
+ fabs(Params[3]) < MATRIX_DET_TOLERANCE)
+ {
+ Val = 0;
}
- else {
- Val = (R - Params[6]) / Params[3];
+ else
+ {
+ disc = Params[3] * Params[4] + Params[6];
+ if (R >= disc) {
+
+ e = R - Params[5];
+ if (e < 0)
+ Val = 0;
+ else
+ Val = (pow(e, 1.0 / Params[0]) - Params[2]) / Params[1];
+ }
+ else {
+ Val = (R - Params[6]) / Params[3];
+ }
}
- break;
+ }
+ break;
// Types 6,7,8 comes from segmented curves as described in ICCSpecRevision_02_11_06_Float.pdf
@@ -532,12 +596,21 @@ cmsFloat64Number DefaultEvalParametricFn(cmsInt32Number Type, const cmsFloat64Nu
// ((Y - c) ^1/Gamma - b) / a
case -6:
- e = R - Params[3];
- if (e < 0)
+ {
+ if (fabs(Params[1]) < MATRIX_DET_TOLERANCE)
+ {
Val = 0;
+ }
else
- Val = (pow(e, 1.0/Params[0]) - Params[2]) / Params[1];
- break;
+ {
+ e = R - Params[3];
+ if (e < 0)
+ Val = 0;
+ else
+ Val = (pow(e, 1.0 / Params[0]) - Params[2]) / Params[1];
+ }
+ }
+ break;
// Y = a * log (b * X^Gamma + c) + d
@@ -554,8 +627,19 @@ cmsFloat64Number DefaultEvalParametricFn(cmsInt32Number Type, const cmsFloat64Nu
// pow(10, (Y-d) / a) = b * X ^Gamma + c
// pow((pow(10, (Y-d) / a) - c) / b, 1/g) = X
case -7:
- Val = pow((pow(10.0, (R-Params[4]) / Params[1]) - Params[3]) / Params[2], 1.0 / Params[0]);
- break;
+ {
+ if (fabs(Params[0]) < MATRIX_DET_TOLERANCE ||
+ fabs(Params[1]) < MATRIX_DET_TOLERANCE ||
+ fabs(Params[2]) < MATRIX_DET_TOLERANCE)
+ {
+ Val = 0;
+ }
+ else
+ {
+ Val = pow((pow(10.0, (R - Params[4]) / Params[1]) - Params[3]) / Params[2], 1.0 / Params[0]);
+ }
+ }
+ break;
//Y = a * b^(c*X+d) + e
@@ -571,12 +655,25 @@ cmsFloat64Number DefaultEvalParametricFn(cmsInt32Number Type, const cmsFloat64Nu
disc = R - Params[4];
if (disc < 0) Val = 0;
else
- Val = (log(disc / Params[0]) / log(Params[1]) - Params[3]) / Params[2];
+ {
+ if (fabs(Params[0]) < MATRIX_DET_TOLERANCE ||
+ fabs(Params[2]) < MATRIX_DET_TOLERANCE)
+ {
+ Val = 0;
+ }
+ else
+ {
+ Val = (log(disc / Params[0]) / log(Params[1]) - Params[3]) / Params[2];
+ }
+ }
break;
// S-Shaped: (1 - (1-x)^1/g)^1/g
case 108:
- Val = pow(1.0 - pow(1 - R, 1/Params[0]), 1/Params[0]);
+ if (fabs(Params[0]) < MATRIX_DET_TOLERANCE)
+ Val = 0;
+ else
+ Val = pow(1.0 - pow(1 - R, 1/Params[0]), 1/Params[0]);
break;
// y = (1 - (1-x)^1/g)^1/g
@@ -596,33 +693,45 @@ cmsFloat64Number DefaultEvalParametricFn(cmsInt32Number Type, const cmsFloat64Nu
return Val;
}
-// Evaluate a segmented function for a single value. Return -1 if no valid segment found .
+// Evaluate a segmented function for a single value. Return -Inf if no valid segment found .
// If fn type is 0, perform an interpolation on the table
static
cmsFloat64Number EvalSegmentedFn(const cmsToneCurve *g, cmsFloat64Number R)
{
int i;
+ cmsFloat32Number Out32;
+ cmsFloat64Number Out;
- for (i = g ->nSegments-1; i >= 0 ; --i) {
+ for (i = (int) g->nSegments - 1; i >= 0; --i) {
// Check for domain
- if ((R > g ->Segments[i].x0) && (R <= g ->Segments[i].x1)) {
+ if ((R > g->Segments[i].x0) && (R <= g->Segments[i].x1)) {
// Type == 0 means segment is sampled
- if (g ->Segments[i].Type == 0) {
+ if (g->Segments[i].Type == 0) {
- cmsFloat32Number R1 = (cmsFloat32Number) (R - g ->Segments[i].x0) / (g ->Segments[i].x1 - g ->Segments[i].x0);
- cmsFloat32Number Out;
+ cmsFloat32Number R1 = (cmsFloat32Number)(R - g->Segments[i].x0) / (g->Segments[i].x1 - g->Segments[i].x0);
// Setup the table (TODO: clean that)
- g ->SegInterp[i]-> Table = g ->Segments[i].SampledPoints;
+ g->SegInterp[i]->Table = g->Segments[i].SampledPoints;
- g ->SegInterp[i] -> Interpolation.LerpFloat(&R1, &Out, g ->SegInterp[i]);
+ g->SegInterp[i]->Interpolation.LerpFloat(&R1, &Out32, g->SegInterp[i]);
+ Out = (cmsFloat64Number) Out32;
- return Out;
}
+ else {
+ Out = g->Evals[i](g->Segments[i].Type, g->Segments[i].Params, R);
+ }
+
+ if (isinf(Out))
+ return PLUS_INF;
else
- return g ->Evals[i](g->Segments[i].Type, g ->Segments[i].Params, R);
+ {
+ if (isinf(-Out))
+ return MINUS_INF;
+ }
+
+ return Out;
}
}
@@ -645,13 +754,13 @@ const cmsUInt16Number* CMSEXPORT cmsGetToneCurveEstimatedTable(const cmsToneCurv
// Create an empty gamma curve, by using tables. This specifies only the limited-precision part, and leaves the
// floating point description empty.
-cmsToneCurve* CMSEXPORT cmsBuildTabulatedToneCurve16(cmsContext ContextID, cmsInt32Number nEntries, const cmsUInt16Number Values[])
+cmsToneCurve* CMSEXPORT cmsBuildTabulatedToneCurve16(cmsContext ContextID, cmsUInt32Number nEntries, const cmsUInt16Number Values[])
{
return AllocateToneCurveStruct(ContextID, nEntries, 0, NULL, Values);
}
static
-int EntriesByGamma(cmsFloat64Number Gamma)
+cmsUInt32Number EntriesByGamma(cmsFloat64Number Gamma)
{
if (fabs(Gamma - 1.0) < 0.001) return 2;
return 4096;
@@ -660,12 +769,12 @@ int EntriesByGamma(cmsFloat64Number Gamma)
// Create a segmented gamma, fill the table
cmsToneCurve* CMSEXPORT cmsBuildSegmentedToneCurve(cmsContext ContextID,
- cmsInt32Number nSegments, const cmsCurveSegment Segments[])
+ cmsUInt32Number nSegments, const cmsCurveSegment Segments[])
{
- int i;
+ cmsUInt32Number i;
cmsFloat64Number R, Val;
cmsToneCurve* g;
- int nGridPoints = 4096;
+ cmsUInt32Number nGridPoints = 4096;
_cmsAssert(Segments != NULL);
@@ -680,7 +789,7 @@ cmsToneCurve* CMSEXPORT cmsBuildSegmentedToneCurve(cmsContext ContextID,
// Once we have the floating point version, we can approximate a 16 bit table of 4096 entries
// for performance reasons. This table would normally not be used except on 8/16 bits transforms.
- for (i=0; i < nGridPoints; i++) {
+ for (i = 0; i < nGridPoints; i++) {
R = (cmsFloat64Number) i / (nGridPoints-1);
@@ -893,7 +1002,7 @@ int GetInterval(cmsFloat64Number In, const cmsUInt16Number LutTable[], const str
if (LutTable[0] < LutTable[p ->Domain[0]]) {
// Table is overall ascending
- for (i=p->Domain[0]-1; i >=0; --i) {
+ for (i = (int) p->Domain[0] - 1; i >= 0; --i) {
y0 = LutTable[i];
y1 = LutTable[i+1];
@@ -928,7 +1037,7 @@ int GetInterval(cmsFloat64Number In, const cmsUInt16Number LutTable[], const str
}
// Reverse a gamma table
-cmsToneCurve* CMSEXPORT cmsReverseToneCurveEx(cmsInt32Number nResultSamples, const cmsToneCurve* InCurve)
+cmsToneCurve* CMSEXPORT cmsReverseToneCurveEx(cmsUInt32Number nResultSamples, const cmsToneCurve* InCurve)
{
cmsToneCurve *out;
cmsFloat64Number a = 0, b = 0, y, x1, y1, x2, y2;
@@ -957,7 +1066,7 @@ cmsToneCurve* CMSEXPORT cmsReverseToneCurveEx(cmsInt32Number nResultSamples, con
Ascending = !cmsIsToneCurveDescending(InCurve);
// Iterate across Y axis
- for (i=0; i < nResultSamples; i++) {
+ for (i=0; i < (int) nResultSamples; i++) {
y = (cmsFloat64Number) i * 65535.0 / (nResultSamples - 1);
@@ -1012,7 +1121,8 @@ cmsToneCurve* CMSEXPORT cmsReverseToneCurve(const cmsToneCurve* InGamma)
// Output: smoothed vector (z): vector from 1 to m.
static
-cmsBool smooth2(cmsContext ContextID, cmsFloat32Number w[], cmsFloat32Number y[], cmsFloat32Number z[], cmsFloat32Number lambda, int m)
+cmsBool smooth2(cmsContext ContextID, cmsFloat32Number w[], cmsFloat32Number y[],
+ cmsFloat32Number z[], cmsFloat32Number lambda, int m)
{
int i, i1, i2;
cmsFloat32Number *c, *d, *e;
@@ -1071,73 +1181,121 @@ cmsBool smooth2(cmsContext ContextID, cmsFloat32Number w[], cmsFloat32Number y[]
// Smooths a curve sampled at regular intervals.
cmsBool CMSEXPORT cmsSmoothToneCurve(cmsToneCurve* Tab, cmsFloat64Number lambda)
{
- cmsFloat32Number w[MAX_NODES_IN_CURVE], y[MAX_NODES_IN_CURVE], z[MAX_NODES_IN_CURVE];
- int i, nItems, Zeros, Poles;
+ cmsBool SuccessStatus = TRUE;
+ cmsFloat32Number *w, *y, *z;
+ cmsUInt32Number i, nItems, Zeros, Poles;
- if (Tab == NULL) return FALSE;
-
- if (cmsIsToneCurveLinear(Tab)) return TRUE; // Nothing to do
-
- nItems = Tab -> nEntries;
-
- if (nItems >= MAX_NODES_IN_CURVE) {
- cmsSignalError(Tab ->InterpParams->ContextID, cmsERROR_RANGE, "cmsSmoothToneCurve: too many points.");
- return FALSE;
- }
-
- memset(w, 0, nItems * sizeof(cmsFloat32Number));
- memset(y, 0, nItems * sizeof(cmsFloat32Number));
- memset(z, 0, nItems * sizeof(cmsFloat32Number));
-
- for (i=0; i < nItems; i++)
+ if (Tab != NULL && Tab->InterpParams != NULL)
{
- y[i+1] = (cmsFloat32Number) Tab -> Table16[i];
- w[i+1] = 1.0;
- }
+ cmsContext ContextID = Tab->InterpParams->ContextID;
+
+ if (!cmsIsToneCurveLinear(Tab)) // Only non-linear curves need smoothing
+ {
+ nItems = Tab->nEntries;
+ if (nItems < MAX_NODES_IN_CURVE)
+ {
+ // Allocate one more item than needed
+ w = (cmsFloat32Number *)_cmsCalloc(ContextID, nItems + 1, sizeof(cmsFloat32Number));
+ y = (cmsFloat32Number *)_cmsCalloc(ContextID, nItems + 1, sizeof(cmsFloat32Number));
+ z = (cmsFloat32Number *)_cmsCalloc(ContextID, nItems + 1, sizeof(cmsFloat32Number));
+
+ if (w != NULL && y != NULL && z != NULL) // Ensure no memory allocation failure
+ {
+ memset(w, 0, (nItems + 1) * sizeof(cmsFloat32Number));
+ memset(y, 0, (nItems + 1) * sizeof(cmsFloat32Number));
+ memset(z, 0, (nItems + 1) * sizeof(cmsFloat32Number));
+
+ for (i = 0; i < nItems; i++)
+ {
+ y[i + 1] = (cmsFloat32Number)Tab->Table16[i];
+ w[i + 1] = 1.0;
+ }
+
+ if (smooth2(ContextID, w, y, z, (cmsFloat32Number)lambda, (int)nItems))
+ {
+ // Do some reality - checking...
+
+ Zeros = Poles = 0;
+ for (i = nItems; i > 1; --i)
+ {
+ if (z[i] == 0.) Zeros++;
+ if (z[i] >= 65535.) Poles++;
+ if (z[i] < z[i - 1])
+ {
+ cmsSignalError(ContextID, cmsERROR_RANGE, "cmsSmoothToneCurve: Non-Monotonic.");
+ SuccessStatus = FALSE;
+ break;
+ }
+ }
+
+ if (SuccessStatus && Zeros > (nItems / 3))
+ {
+ cmsSignalError(ContextID, cmsERROR_RANGE, "cmsSmoothToneCurve: Degenerated, mostly zeros.");
+ SuccessStatus = FALSE;
+ }
+
+ if (SuccessStatus && Poles > (nItems / 3))
+ {
+ cmsSignalError(ContextID, cmsERROR_RANGE, "cmsSmoothToneCurve: Degenerated, mostly poles.");
+ SuccessStatus = FALSE;
+ }
+
+ if (SuccessStatus) // Seems ok
+ {
+ for (i = 0; i < nItems; i++)
+ {
+ // Clamp to cmsUInt16Number
+ Tab->Table16[i] = _cmsQuickSaturateWord(z[i + 1]);
+ }
+ }
+ }
+ else // Could not smooth
+ {
+ cmsSignalError(ContextID, cmsERROR_RANGE, "cmsSmoothToneCurve: Function smooth2 failed.");
+ SuccessStatus = FALSE;
+ }
+ }
+ else // One or more buffers could not be allocated
+ {
+ cmsSignalError(ContextID, cmsERROR_RANGE, "cmsSmoothToneCurve: Could not allocate memory.");
+ SuccessStatus = FALSE;
+ }
- if (!smooth2(Tab ->InterpParams->ContextID, w, y, z, (cmsFloat32Number) lambda, nItems)) return FALSE;
+ if (z != NULL)
+ _cmsFree(ContextID, z);
- // Do some reality - checking...
- Zeros = Poles = 0;
- for (i=nItems; i > 1; --i) {
+ if (y != NULL)
+ _cmsFree(ContextID, y);
- if (z[i] == 0.) Zeros++;
- if (z[i] >= 65535.) Poles++;
- if (z[i] < z[i-1]) {
- cmsSignalError(Tab ->InterpParams->ContextID, cmsERROR_RANGE, "cmsSmoothToneCurve: Non-Monotonic.");
- return FALSE;
+ if (w != NULL)
+ _cmsFree(ContextID, w);
+ }
+ else // too many items in the table
+ {
+ cmsSignalError(ContextID, cmsERROR_RANGE, "cmsSmoothToneCurve: Too many points.");
+ SuccessStatus = FALSE;
+ }
}
}
-
- if (Zeros > (nItems / 3)) {
- cmsSignalError(Tab ->InterpParams->ContextID, cmsERROR_RANGE, "cmsSmoothToneCurve: Degenerated, mostly zeros.");
- return FALSE;
- }
- if (Poles > (nItems / 3)) {
- cmsSignalError(Tab ->InterpParams->ContextID, cmsERROR_RANGE, "cmsSmoothToneCurve: Degenerated, mostly poles.");
- return FALSE;
- }
-
- // Seems ok
- for (i=0; i < nItems; i++) {
-
- // Clamp to cmsUInt16Number
- Tab -> Table16[i] = _cmsQuickSaturateWord(z[i+1]);
+ else // Tab parameter or Tab->InterpParams is NULL
+ {
+ // Can't signal an error here since the ContextID is not known at this point
+ SuccessStatus = FALSE;
}
- return TRUE;
+ return SuccessStatus;
}
// Is a table linear? Do not use parametric since we cannot guarantee some weird parameters resulting
// in a linear table. This way assures it is linear in 12 bits, which should be enought in most cases.
cmsBool CMSEXPORT cmsIsToneCurveLinear(const cmsToneCurve* Curve)
{
- cmsUInt32Number i;
+ int i;
int diff;
_cmsAssert(Curve != NULL);
- for (i=0; i < Curve ->nEntries; i++) {
+ for (i=0; i < (int) Curve ->nEntries; i++) {
diff = abs((int) Curve->Table16[i] - (int) _cmsQuantizeVal(i, Curve ->nEntries));
if (diff > 0x0f)
@@ -1150,7 +1308,7 @@ cmsBool CMSEXPORT cmsIsToneCurveLinear(const cmsToneCurve* Curve)
// Same, but for monotonicity
cmsBool CMSEXPORT cmsIsToneCurveMonotonic(const cmsToneCurve* t)
{
- int n;
+ cmsUInt32Number n;
int i, last;
cmsBool lDescending;
@@ -1167,7 +1325,7 @@ cmsBool CMSEXPORT cmsIsToneCurveMonotonic(const cmsToneCurve* t)
last = t ->Table16[0];
- for (i = 1; i < n; i++) {
+ for (i = 1; i < (int) n; i++) {
if (t ->Table16[i] - last > 2) // We allow some ripple
return FALSE;
@@ -1180,7 +1338,7 @@ cmsBool CMSEXPORT cmsIsToneCurveMonotonic(const cmsToneCurve* t)
last = t ->Table16[n-1];
- for (i = n-2; i >= 0; --i) {
+ for (i = (int) n - 2; i >= 0; --i) {
if (t ->Table16[i] - last > 2)
return FALSE;
diff --git a/src/java.desktop/share/native/liblcms/cmsgmt.c b/src/java.desktop/share/native/liblcms/cmsgmt.c
index 81254c2ad9b..1b464af0fa8 100644
--- a/src/java.desktop/share/native/liblcms/cmsgmt.c
+++ b/src/java.desktop/share/native/liblcms/cmsgmt.c
@@ -30,7 +30,7 @@
//---------------------------------------------------------------------------------
//
// Little Color Management System
-// Copyright (c) 1998-2016 Marti Maria Saguer
+// Copyright (c) 1998-2017 Marti Maria Saguer
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
@@ -326,7 +326,7 @@ cmsPipeline* _cmsCreateGamutCheckPipeline(cmsContext ContextID,
cmsStage* CLUT;
cmsUInt32Number dwFormat;
GAMUTCHAIN Chain;
- int nChannels, nGridpoints;
+ cmsUInt32Number nChannels, nGridpoints;
cmsColorSpaceSignature ColorSpace;
cmsUInt32Number i;
cmsHPROFILE ProfileList[256];
diff --git a/src/java.desktop/share/native/liblcms/cmshalf.c b/src/java.desktop/share/native/liblcms/cmshalf.c
index ddcaf48b8b4..287fcb5e5f1 100644
--- a/src/java.desktop/share/native/liblcms/cmshalf.c
+++ b/src/java.desktop/share/native/liblcms/cmshalf.c
@@ -30,7 +30,7 @@
//---------------------------------------------------------------------------------
//
// Little Color Management System
-// Copyright (c) 1998-2016 Marti Maria Saguer
+// Copyright (c) 1998-2017 Marti Maria Saguer
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
@@ -532,7 +532,7 @@ static cmsUInt8Number Shift[512] = {
0x18, 0x18, 0x18, 0x18, 0x0d
};
-cmsFloat32Number _cmsHalf2Float(cmsUInt16Number h)
+cmsFloat32Number CMSEXPORT _cmsHalf2Float(cmsUInt16Number h)
{
union {
cmsFloat32Number flt;
@@ -545,7 +545,7 @@ cmsFloat32Number _cmsHalf2Float(cmsUInt16Number h)
return out.flt;
}
-cmsUInt16Number _cmsFloat2Half(cmsFloat32Number flt)
+cmsUInt16Number CMSEXPORT _cmsFloat2Half(cmsFloat32Number flt)
{
union {
cmsFloat32Number flt;
diff --git a/src/java.desktop/share/native/liblcms/cmsintrp.c b/src/java.desktop/share/native/liblcms/cmsintrp.c
index aa96cbb440b..6a3c7f85a7c 100644
--- a/src/java.desktop/share/native/liblcms/cmsintrp.c
+++ b/src/java.desktop/share/native/liblcms/cmsintrp.c
@@ -30,7 +30,7 @@
//---------------------------------------------------------------------------------
//
// Little Color Management System
-// Copyright (c) 1998-2016 Marti Maria Saguer
+// Copyright (c) 1998-2017 Marti Maria Saguer
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
@@ -58,6 +58,13 @@
// This module incorporates several interpolation routines, for 1 to 8 channels on input and
// up to 65535 channels on output. The user may change those by using the interpolation plug-in
+// Some people may want to compile as C++ with all warnings on, in this case make compiler silent
+#ifdef _MSC_VER
+# if (_MSC_VER >= 1400)
+# pragma warning( disable : 4365 )
+# endif
+#endif
+
// Interpolation routines by default
static cmsInterpFunction DefaultInterpolatorsFactory(cmsUInt32Number nInputChannels, cmsUInt32Number nOutputChannels, cmsUInt32Number dwFlags);
@@ -131,12 +138,12 @@ cmsBool _cmsSetInterpolationRoutine(cmsContext ContextID, cmsInterpParams* p)
// This function precalculates as many parameters as possible to speed up the interpolation.
cmsInterpParams* _cmsComputeInterpParamsEx(cmsContext ContextID,
const cmsUInt32Number nSamples[],
- int InputChan, int OutputChan,
+ cmsUInt32Number InputChan, cmsUInt32Number OutputChan,
const void *Table,
cmsUInt32Number dwFlags)
{
cmsInterpParams* p;
- int i;
+ cmsUInt32Number i;
// Check for maximum inputs
if (InputChan > MAX_INPUT_DIMENSIONS) {
@@ -180,7 +187,8 @@ cmsInterpParams* _cmsComputeInterpParamsEx(cmsContext ContextID,
// This one is a wrapper on the anterior, but assuming all directions have same number of nodes
-cmsInterpParams* _cmsComputeInterpParams(cmsContext ContextID, int nSamples, int InputChan, int OutputChan, const void* Table, cmsUInt32Number dwFlags)
+cmsInterpParams* CMSEXPORT _cmsComputeInterpParams(cmsContext ContextID, cmsUInt32Number nSamples,
+ cmsUInt32Number InputChan, cmsUInt32Number OutputChan, const void* Table, cmsUInt32Number dwFlags)
{
int i;
cmsUInt32Number Samples[MAX_INPUT_DIMENSIONS];
@@ -195,7 +203,7 @@ cmsInterpParams* _cmsComputeInterpParams(cmsContext ContextID, int nSamples, int
// Free all associated memory
-void _cmsFreeInterpParams(cmsInterpParams* p)
+void CMSEXPORT _cmsFreeInterpParams(cmsInterpParams* p)
{
if (p != NULL) _cmsFree(p ->ContextID, p);
}
@@ -244,7 +252,7 @@ void LinLerp1D(register const cmsUInt16Number Value[],
// To prevent out of bounds indexing
cmsINLINE cmsFloat32Number fclamp(cmsFloat32Number v)
{
- return v < 0.0f || v != v ? 0.0f : (v > 1.0f ? 1.0f : v);
+ return ((v < 1.0e-9f) || isnan(v)) ? 0.0f : (v > 1.0f ? 1.0f : v);
}
// Floating-point version of 1D interpolation
@@ -381,10 +389,10 @@ void BilinearInterpFloat(const cmsFloat32Number Input[],
y0 = (int) _cmsQuickFloor(py); fy = py - (cmsFloat32Number) y0;
X0 = p -> opta[1] * x0;
- X1 = X0 + (Input[0] >= 1.0 ? 0 : p->opta[1]);
+ X1 = X0 + (fclamp(Input[0]) >= 1.0 ? 0 : p->opta[1]);
Y0 = p -> opta[0] * y0;
- Y1 = Y0 + (Input[1] >= 1.0 ? 0 : p->opta[0]);
+ Y1 = Y0 + (fclamp(Input[1]) >= 1.0 ? 0 : p->opta[0]);
for (OutChan = 0; OutChan < TotalOut; OutChan++) {
@@ -493,18 +501,18 @@ void TrilinearInterpFloat(const cmsFloat32Number Input[],
py = fclamp(Input[1]) * p->Domain[1];
pz = fclamp(Input[2]) * p->Domain[2];
- x0 = (int) _cmsQuickFloor(px); fx = px - (cmsFloat32Number) x0;
- y0 = (int) _cmsQuickFloor(py); fy = py - (cmsFloat32Number) y0;
- z0 = (int) _cmsQuickFloor(pz); fz = pz - (cmsFloat32Number) z0;
+ x0 = (int) floor(px); fx = px - (cmsFloat32Number) x0; // We need full floor funcionality here
+ y0 = (int) floor(py); fy = py - (cmsFloat32Number) y0;
+ z0 = (int) floor(pz); fz = pz - (cmsFloat32Number) z0;
X0 = p -> opta[2] * x0;
- X1 = X0 + (Input[0] >= 1.0 ? 0 : p->opta[2]);
+ X1 = X0 + (fclamp(Input[0]) >= 1.0 ? 0 : p->opta[2]);
Y0 = p -> opta[1] * y0;
- Y1 = Y0 + (Input[1] >= 1.0 ? 0 : p->opta[1]);
+ Y1 = Y0 + (fclamp(Input[1]) >= 1.0 ? 0 : p->opta[1]);
Z0 = p -> opta[0] * z0;
- Z1 = Z0 + (Input[2] >= 1.0 ? 0 : p->opta[0]);
+ Z1 = Z0 + (fclamp(Input[2]) >= 1.0 ? 0 : p->opta[0]);
for (OutChan = 0; OutChan < TotalOut; OutChan++) {
@@ -637,19 +645,19 @@ void TetrahedralInterpFloat(const cmsFloat32Number Input[],
py = fclamp(Input[1]) * p->Domain[1];
pz = fclamp(Input[2]) * p->Domain[2];
- x0 = (int) _cmsQuickFloor(px); rx = (px - (cmsFloat32Number) x0);
- y0 = (int) _cmsQuickFloor(py); ry = (py - (cmsFloat32Number) y0);
- z0 = (int) _cmsQuickFloor(pz); rz = (pz - (cmsFloat32Number) z0);
+ x0 = (int) floor(px); rx = (px - (cmsFloat32Number) x0); // We need full floor functionality here
+ y0 = (int) floor(py); ry = (py - (cmsFloat32Number) y0);
+ z0 = (int) floor(pz); rz = (pz - (cmsFloat32Number) z0);
X0 = p -> opta[2] * x0;
- X1 = X0 + (Input[0] >= 1.0 ? 0 : p->opta[2]);
+ X1 = X0 + (fclamp(Input[0]) >= 1.0 ? 0 : p->opta[2]);
Y0 = p -> opta[1] * y0;
- Y1 = Y0 + (Input[1] >= 1.0 ? 0 : p->opta[1]);
+ Y1 = Y0 + (fclamp(Input[1]) >= 1.0 ? 0 : p->opta[1]);
Z0 = p -> opta[0] * z0;
- Z1 = Z0 + (Input[2] >= 1.0 ? 0 : p->opta[0]);
+ Z1 = Z0 + (fclamp(Input[2]) >= 1.0 ? 0 : p->opta[0]);
for (OutChan=0; OutChan < TotalOut; OutChan++) {
@@ -952,13 +960,13 @@ void Eval4Inputs(register const cmsUInt16Number Input[],
c3 = DENS(X0, Y0, Z1) - c0;
}
- else {
+ else {
c1 = c2 = c3 = 0;
}
Rest = c1 * rx + c2 * ry + c3 * rz;
- Tmp1[OutChan] = (cmsUInt16Number) ( c0 + ROUND_FIXED_TO_INT(_cmsToFixedDomain(Rest)));
+ Tmp1[OutChan] = (cmsUInt16Number)(c0 + ROUND_FIXED_TO_INT(_cmsToFixedDomain(Rest)));
}
@@ -1057,7 +1065,7 @@ void Eval4InputsFloat(const cmsFloat32Number Input[],
rest = pk - (cmsFloat32Number) k0;
K0 = p -> opta[3] * k0;
- K1 = K0 + (Input[0] >= 1.0 ? 0 : p->opta[3]);
+ K1 = K0 + (fclamp(Input[0]) >= 1.0 ? 0 : p->opta[3]);
p1 = *p;
memmove(&p1.Domain[0], &p ->Domain[1], 3*sizeof(cmsUInt32Number));
@@ -1144,7 +1152,7 @@ void Eval5InputsFloat(const cmsFloat32Number Input[],
rest = pk - (cmsFloat32Number) k0;
K0 = p -> opta[4] * k0;
- K1 = K0 + (Input[0] >= 1.0 ? 0 : p->opta[4]);
+ K1 = K0 + (fclamp(Input[0]) >= 1.0 ? 0 : p->opta[4]);
p1 = *p;
memmove(&p1.Domain[0], &p ->Domain[1], 4*sizeof(cmsUInt32Number));
@@ -1231,7 +1239,7 @@ void Eval6InputsFloat(const cmsFloat32Number Input[],
rest = pk - (cmsFloat32Number) k0;
K0 = p -> opta[5] * k0;
- K1 = K0 + (Input[0] >= 1.0 ? 0 : p->opta[5]);
+ K1 = K0 + (fclamp(Input[0]) >= 1.0 ? 0 : p->opta[5]);
p1 = *p;
memmove(&p1.Domain[0], &p ->Domain[1], 5*sizeof(cmsUInt32Number));
@@ -1316,7 +1324,7 @@ void Eval7InputsFloat(const cmsFloat32Number Input[],
rest = pk - (cmsFloat32Number) k0;
K0 = p -> opta[6] * k0;
- K1 = K0 + (Input[0] >= 1.0 ? 0 : p->opta[6]);
+ K1 = K0 + (fclamp(Input[0]) >= 1.0 ? 0 : p->opta[6]);
p1 = *p;
memmove(&p1.Domain[0], &p ->Domain[1], 6*sizeof(cmsUInt32Number));
@@ -1401,7 +1409,7 @@ void Eval8InputsFloat(const cmsFloat32Number Input[],
rest = pk - (cmsFloat32Number) k0;
K0 = p -> opta[7] * k0;
- K1 = K0 + (Input[0] >= 1.0 ? 0 : p->opta[7]);
+ K1 = K0 + (fclamp(Input[0]) >= 1.0 ? 0 : p->opta[7]);
p1 = *p;
memmove(&p1.Domain[0], &p ->Domain[1], 7*sizeof(cmsUInt32Number));
diff --git a/src/java.desktop/share/native/liblcms/cmsio0.c b/src/java.desktop/share/native/liblcms/cmsio0.c
index f86f2e738d8..3dbfcb37ebf 100644
--- a/src/java.desktop/share/native/liblcms/cmsio0.c
+++ b/src/java.desktop/share/native/liblcms/cmsio0.c
@@ -30,7 +30,7 @@
//---------------------------------------------------------------------------------
//
// Little Color Management System
-// Copyright (c) 1998-2016 Marti Maria Saguer
+// Copyright (c) 1998-2017 Marti Maria Saguer
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
@@ -366,21 +366,27 @@ cmsBool FileSeek(cmsIOHANDLER* iohandler, cmsUInt32Number offset)
return TRUE;
}
-// Returns file pointer position
+// Returns file pointer position or 0 on error, which is also a valid position.
static
cmsUInt32Number FileTell(cmsIOHANDLER* iohandler)
{
- return (cmsUInt32Number) ftell((FILE*)iohandler ->stream);
+ long t = ftell((FILE*)iohandler ->stream);
+ if (t == -1L) {
+ cmsSignalError(iohandler->ContextID, cmsERROR_FILE, "Tell error; probably corrupted file");
+ return 0;
+ }
+
+ return (cmsUInt32Number)t;
}
// Writes data to stream, also keeps used space for further reference. Returns TRUE on success, FALSE on error
static
cmsBool FileWrite(cmsIOHANDLER* iohandler, cmsUInt32Number size, const void* Buffer)
{
- if (size == 0) return TRUE; // We allow to write 0 bytes, but nothing is written
+ if (size == 0) return TRUE; // We allow to write 0 bytes, but nothing is written
- iohandler->UsedSpace += size;
- return (fwrite(Buffer, size, 1, (FILE*) iohandler->stream) == 1);
+ iohandler->UsedSpace += size;
+ return (fwrite(Buffer, size, 1, (FILE*)iohandler->stream) == 1);
}
// Closes the file
@@ -548,7 +554,7 @@ cmsInt32Number CMSEXPORT cmsGetTagCount(cmsHPROFILE hProfile)
_cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
if (Icc == NULL) return -1;
- return Icc->TagCount;
+ return (cmsInt32Number) Icc->TagCount;
}
// Return the tag signature of a given tag number
@@ -566,9 +572,9 @@ cmsTagSignature CMSEXPORT cmsGetTagSignature(cmsHPROFILE hProfile, cmsUInt32Numb
static
int SearchOneTag(_cmsICCPROFILE* Profile, cmsTagSignature sig)
{
- cmsUInt32Number i;
+ int i;
- for (i=0; i < Profile -> TagCount; i++) {
+ for (i=0; i < (int) Profile -> TagCount; i++) {
if (sig == Profile -> TagNames[i])
return i;
@@ -662,7 +668,7 @@ cmsBool _cmsNewTag(_cmsICCPROFILE* Icc, cmsTagSignature sig, int* NewPos)
return FALSE;
}
- *NewPos = Icc ->TagCount;
+ *NewPos = (int) Icc ->TagCount;
Icc -> TagCount++;
}
@@ -693,10 +699,10 @@ cmsUInt32Number _validatedVersion(cmsUInt32Number DWord)
cmsUInt8Number temp2;
if (*pByte > 0x09) *pByte = (cmsUInt8Number) 0x09;
- temp1 = *(pByte+1) & 0xf0;
- temp2 = *(pByte+1) & 0x0f;
- if (temp1 > 0x90) temp1 = 0x90;
- if (temp2 > 0x09) temp2 = 0x09;
+ temp1 = (cmsUInt8Number) (*(pByte+1) & 0xf0);
+ temp2 = (cmsUInt8Number) (*(pByte+1) & 0x0f);
+ if (temp1 > 0x90U) temp1 = 0x90U;
+ if (temp2 > 0x09U) temp2 = 0x09U;
*(pByte+1) = (cmsUInt8Number)(temp1 | temp2);
*(pByte+2) = (cmsUInt8Number)0;
*(pByte+3) = (cmsUInt8Number)0;
@@ -804,7 +810,7 @@ cmsBool _cmsWriteHeader(_cmsICCPROFILE* Icc, cmsUInt32Number UsedSpace)
cmsICCHeader Header;
cmsUInt32Number i;
cmsTagEntry Tag;
- cmsInt32Number Count = 0;
+ cmsUInt32Number Count;
Header.size = _cmsAdjustEndianess32(UsedSpace);
Header.cmmId = _cmsAdjustEndianess32(lcmsSignature);
@@ -835,9 +841,9 @@ cmsBool _cmsWriteHeader(_cmsICCPROFILE* Icc, cmsUInt32Number UsedSpace)
Header.renderingIntent = _cmsAdjustEndianess32(Icc -> RenderingIntent);
// Illuminant is always D50
- Header.illuminant.X = _cmsAdjustEndianess32(_cmsDoubleTo15Fixed16(cmsD50_XYZ()->X));
- Header.illuminant.Y = _cmsAdjustEndianess32(_cmsDoubleTo15Fixed16(cmsD50_XYZ()->Y));
- Header.illuminant.Z = _cmsAdjustEndianess32(_cmsDoubleTo15Fixed16(cmsD50_XYZ()->Z));
+ Header.illuminant.X = (cmsS15Fixed16Number) _cmsAdjustEndianess32((cmsUInt32Number) _cmsDoubleTo15Fixed16(cmsD50_XYZ()->X));
+ Header.illuminant.Y = (cmsS15Fixed16Number) _cmsAdjustEndianess32((cmsUInt32Number) _cmsDoubleTo15Fixed16(cmsD50_XYZ()->Y));
+ Header.illuminant.Z = (cmsS15Fixed16Number) _cmsAdjustEndianess32((cmsUInt32Number) _cmsDoubleTo15Fixed16(cmsD50_XYZ()->Z));
// Created by LittleCMS (that's me!)
Header.creator = _cmsAdjustEndianess32(lcmsSignature);
@@ -853,6 +859,7 @@ cmsBool _cmsWriteHeader(_cmsICCPROFILE* Icc, cmsUInt32Number UsedSpace)
// Saves Tag directory
// Get true count
+ Count = 0;
for (i=0; i < Icc -> TagCount; i++) {
if (Icc ->TagNames[i] != (cmsTagSignature) 0)
Count++;
@@ -865,9 +872,9 @@ cmsBool _cmsWriteHeader(_cmsICCPROFILE* Icc, cmsUInt32Number UsedSpace)
if (Icc ->TagNames[i] == (cmsTagSignature) 0) continue; // It is just a placeholder
- Tag.sig = (cmsTagSignature) _cmsAdjustEndianess32((cmsInt32Number) Icc -> TagNames[i]);
- Tag.offset = _cmsAdjustEndianess32((cmsInt32Number) Icc -> TagOffsets[i]);
- Tag.size = _cmsAdjustEndianess32((cmsInt32Number) Icc -> TagSizes[i]);
+ Tag.sig = (cmsTagSignature) _cmsAdjustEndianess32((cmsUInt32Number) Icc -> TagNames[i]);
+ Tag.offset = _cmsAdjustEndianess32((cmsUInt32Number) Icc -> TagOffsets[i]);
+ Tag.size = _cmsAdjustEndianess32((cmsUInt32Number) Icc -> TagSizes[i]);
if (!Icc ->IOhandler -> Write(Icc-> IOhandler, sizeof(cmsTagEntry), &Tag)) return FALSE;
}
@@ -1176,7 +1183,7 @@ cmsHPROFILE CMSEXPORT cmsOpenProfileFromMemTHR(cmsContext ContextID, const void*
NewIcc = (_cmsICCPROFILE*) hEmpty;
// Ok, in this case const void* is casted to void* just because open IO handler
- // shares read and writting modes. Don't abuse this feature!
+ // shares read and writing modes. Don't abuse this feature!
NewIcc ->IOhandler = cmsOpenIOhandlerFromMem(ContextID, (void*) MemPtr, dwSize, "r");
if (NewIcc ->IOhandler == NULL) goto Error;
@@ -1466,7 +1473,7 @@ cmsBool CMSEXPORT cmsCloseProfile(cmsHPROFILE hProfile)
// Was open in write mode?
if (Icc ->IsWrite) {
- Icc ->IsWrite = FALSE; // Assure no further writting
+ Icc ->IsWrite = FALSE; // Assure no further writing
rc &= cmsSaveProfileToFile(hProfile, Icc ->IOhandler->PhysicalFile);
}
@@ -1543,11 +1550,15 @@ void* CMSEXPORT cmsReadTag(cmsHPROFILE hProfile, cmsTagSignature sig)
// If the element is already in memory, return the pointer
if (Icc -> TagPtrs[n]) {
- if (Icc -> TagTypeHandlers[n] == NULL) goto Error;
- BaseType = Icc -> TagTypeHandlers[n]->Signature;
+ if (Icc->TagTypeHandlers[n] == NULL) goto Error;
+
+ // Sanity check
+ BaseType = Icc->TagTypeHandlers[n]->Signature;
if (BaseType == 0) goto Error;
- TagDescriptor = _cmsGetTagDescriptor(Icc-> ContextID, sig);
+
+ TagDescriptor = _cmsGetTagDescriptor(Icc->ContextID, sig);
if (TagDescriptor == NULL) goto Error;
+
if (!IsTypeSupported(TagDescriptor, BaseType)) goto Error;
if (Icc ->TagSaveAsRaw[n]) goto Error; // We don't support read raw tags as cooked
@@ -1560,6 +1571,8 @@ void* CMSEXPORT cmsReadTag(cmsHPROFILE hProfile, cmsTagSignature sig)
Offset = Icc -> TagOffsets[n];
TagSize = Icc -> TagSizes[n];
+ if (TagSize < 8) goto Error;
+
// Seek to its location
if (!io -> Seek(io, Offset))
goto Error;
@@ -1583,7 +1596,7 @@ void* CMSEXPORT cmsReadTag(cmsHPROFILE hProfile, cmsTagSignature sig)
if (!IsTypeSupported(TagDescriptor, BaseType)) goto Error;
- TagSize -= 8; // Alredy read by the type base logic
+ TagSize -= 8; // Alredy read by the type base logic
// Get type handler
TypeHandler = _cmsGetTagTypeHandler(Icc ->ContextID, BaseType);
@@ -1772,7 +1785,7 @@ cmsBool CMSEXPORT cmsWriteTag(cmsHPROFILE hProfile, cmsTagSignature sig, const v
// raw data written does not exactly correspond with the raw data proposed to cmsWriteRaw data, but this approach allows
// to write a tag as raw data and the read it as handled.
-cmsInt32Number CMSEXPORT cmsReadRawTag(cmsHPROFILE hProfile, cmsTagSignature sig, void* data, cmsUInt32Number BufferSize)
+cmsUInt32Number CMSEXPORT cmsReadRawTag(cmsHPROFILE hProfile, cmsTagSignature sig, void* data, cmsUInt32Number BufferSize)
{
_cmsICCPROFILE* Icc = (_cmsICCPROFILE*) hProfile;
void *Object;
@@ -1890,7 +1903,7 @@ cmsInt32Number CMSEXPORT cmsReadRawTag(cmsHPROFILE hProfile, cmsTagSignature sig
}
// Similar to the anterior. This function allows to write directly to the ICC profile any data, without
-// checking anything. As a rule, mixing Raw with cooked doesn't work, so writting a tag as raw and then reading
+// checking anything. As a rule, mixing Raw with cooked doesn't work, so writing a tag as raw and then reading
// it as cooked without serializing does result into an error. If that is what you want, you will need to dump
// the profile to memry or disk and then reopen it.
cmsBool CMSEXPORT cmsWriteRawTag(cmsHPROFILE hProfile, cmsTagSignature sig, const void* data, cmsUInt32Number Size)
diff --git a/src/java.desktop/share/native/liblcms/cmsio1.c b/src/java.desktop/share/native/liblcms/cmsio1.c
index c478b2ec75e..efac5abbba8 100644
--- a/src/java.desktop/share/native/liblcms/cmsio1.c
+++ b/src/java.desktop/share/native/liblcms/cmsio1.c
@@ -30,7 +30,7 @@
//---------------------------------------------------------------------------------
//
// Little Color Management System
-// Copyright (c) 1998-2016 Marti Maria Saguer
+// Copyright (c) 1998-2017 Marti Maria Saguer
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
@@ -335,8 +335,8 @@ cmsPipeline* _cmsReadFloatInputTag(cmsHPROFILE hProfile, cmsTagSignature tagFloa
// Read and create a BRAND NEW MPE LUT from a given profile. All stuff dependent of version, etc
// is adjusted here in order to create a LUT that takes care of all those details.
-// We add intent = -1 as a way to read matrix shaper always, no matter of other LUT
-cmsPipeline* _cmsReadInputLUT(cmsHPROFILE hProfile, int Intent)
+// We add intent = 0xffffffff as a way to read matrix shaper always, no matter of other LUT
+cmsPipeline* CMSEXPORT _cmsReadInputLUT(cmsHPROFILE hProfile, cmsUInt32Number Intent)
{
cmsTagTypeSignature OriginalType;
cmsTagSignature tag16;
@@ -366,8 +366,8 @@ cmsPipeline* _cmsReadInputLUT(cmsHPROFILE hProfile, int Intent)
}
// This is an attempt to reuse this function to retrieve the matrix-shaper as pipeline no
- // matter other LUT are present and have precedence. Intent = -1 means just this.
- if (Intent >= INTENT_PERCEPTUAL && Intent <= INTENT_ABSOLUTE_COLORIMETRIC) {
+ // matter other LUT are present and have precedence. Intent = 0xffffffff can be used for that.
+ if (Intent <= INTENT_ABSOLUTE_COLORIMETRIC) {
tag16 = Device2PCS16[Intent];
tagFloat = Device2PCSFloat[Intent];
@@ -611,7 +611,7 @@ cmsPipeline* _cmsReadFloatOutputTag(cmsHPROFILE hProfile, cmsTagSignature tagFlo
}
// Create an output MPE LUT from agiven profile. Version mismatches are handled here
-cmsPipeline* _cmsReadOutputLUT(cmsHPROFILE hProfile, int Intent)
+cmsPipeline* CMSEXPORT _cmsReadOutputLUT(cmsHPROFILE hProfile, cmsUInt32Number Intent)
{
cmsTagTypeSignature OriginalType;
cmsTagSignature tag16;
@@ -619,7 +619,7 @@ cmsPipeline* _cmsReadOutputLUT(cmsHPROFILE hProfile, int Intent)
cmsContext ContextID = cmsGetProfileContextID(hProfile);
- if (Intent >= INTENT_PERCEPTUAL && Intent <= INTENT_ABSOLUTE_COLORIMETRIC) {
+ if (Intent <= INTENT_ABSOLUTE_COLORIMETRIC) {
tag16 = PCS2Device16[Intent];
tagFloat = PCS2DeviceFloat[Intent];
@@ -695,8 +695,8 @@ cmsPipeline* _cmsReadOutputLUT(cmsHPROFILE hProfile, int Intent)
static
cmsPipeline* _cmsReadFloatDevicelinkTag(cmsHPROFILE hProfile, cmsTagSignature tagFloat)
{
- cmsContext ContextID = cmsGetProfileContextID(hProfile);
- cmsPipeline* Lut = cmsPipelineDup((cmsPipeline*) cmsReadTag(hProfile, tagFloat));
+ cmsContext ContextID = cmsGetProfileContextID(hProfile);
+ cmsPipeline* Lut = cmsPipelineDup((cmsPipeline*)cmsReadTag(hProfile, tagFloat));
cmsColorSpaceSignature PCS = cmsGetPCS(hProfile);
cmsColorSpaceSignature spc = cmsGetColorSpace(hProfile);
@@ -714,17 +714,17 @@ cmsPipeline* _cmsReadFloatDevicelinkTag(cmsHPROFILE hProfile, cmsTagSignature ta
goto Error;
}
- if (PCS == cmsSigLabData)
+ if (PCS == cmsSigLabData)
+ {
+ if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageNormalizeFromLabFloat(ContextID)))
+ goto Error;
+ }
+ else
+ if (PCS == cmsSigXYZData)
{
- if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageNormalizeFromLabFloat(ContextID)))
+ if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageNormalizeFromXyzFloat(ContextID)))
goto Error;
}
- else
- if (PCS == cmsSigXYZData)
- {
- if (!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageNormalizeFromXyzFloat(ContextID)))
- goto Error;
- }
return Lut;
Error:
@@ -734,7 +734,7 @@ cmsPipeline* _cmsReadFloatDevicelinkTag(cmsHPROFILE hProfile, cmsTagSignature ta
// This one includes abstract profiles as well. Matrix-shaper cannot be obtained on that device class. The
// tag name here may default to AToB0
-cmsPipeline* _cmsReadDevicelinkLUT(cmsHPROFILE hProfile, int Intent)
+cmsPipeline* CMSEXPORT _cmsReadDevicelinkLUT(cmsHPROFILE hProfile, cmsUInt32Number Intent)
{
cmsPipeline* Lut;
cmsTagTypeSignature OriginalType;
@@ -743,7 +743,7 @@ cmsPipeline* _cmsReadDevicelinkLUT(cmsHPROFILE hProfile, int Intent)
cmsContext ContextID = cmsGetProfileContextID(hProfile);
- if (Intent < INTENT_PERCEPTUAL || Intent > INTENT_ABSOLUTE_COLORIMETRIC)
+ if (Intent > INTENT_ABSOLUTE_COLORIMETRIC)
return NULL;
tag16 = Device2PCS16[Intent];
diff --git a/src/java.desktop/share/native/liblcms/cmslut.c b/src/java.desktop/share/native/liblcms/cmslut.c
index 6c4b8ce4b40..495f3ef9283 100644
--- a/src/java.desktop/share/native/liblcms/cmslut.c
+++ b/src/java.desktop/share/native/liblcms/cmslut.c
@@ -30,7 +30,7 @@
//---------------------------------------------------------------------------------
//
// Little Color Management System
-// Copyright (c) 1998-2016 Marti Maria Saguer
+// Copyright (c) 1998-2017 Marti Maria Saguer
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
@@ -153,8 +153,8 @@ cmsBool CMSEXPORT cmsPipelineCheckAndRetreiveStages(const cmsPipeline* Lut, cms
mpe = Lut ->Elements;
for (i=0; i < n; i++) {
- // Get asked type
- Type = (cmsStageSignature)va_arg(args, cmsStageSignature);
+ // Get asked type. cmsStageSignature is promoted to int by compiler
+ Type = (cmsStageSignature)va_arg(args, int);
if (mpe ->Type != Type) {
va_end(args); // Mismatch. We are done.
@@ -321,7 +321,7 @@ cmsStage* CMSEXPORT cmsStageAllocToneCurves(cmsContext ContextID, cmsUInt32Numbe
// Create a bunch of identity curves
-cmsStage* _cmsStageAllocIdentityCurves(cmsContext ContextID, int nChannels)
+cmsStage* CMSEXPORT _cmsStageAllocIdentityCurves(cmsContext ContextID, cmsUInt32Number nChannels)
{
cmsStage* mpe = cmsStageAllocToneCurves(ContextID, nChannels, NULL);
@@ -443,13 +443,13 @@ cmsStage* CMSEXPORT cmsStageAllocMatrix(cmsContext ContextID, cmsUInt32Number R
if (Offset != NULL) {
- NewElem ->Offset = (cmsFloat64Number*) _cmsCalloc(ContextID, Cols, sizeof(cmsFloat64Number));
+ NewElem ->Offset = (cmsFloat64Number*) _cmsCalloc(ContextID, Rows, sizeof(cmsFloat64Number));
if (NewElem->Offset == NULL) {
MatrixElemTypeFree(NewMPE);
return NULL;
}
- for (i=0; i < Cols; i++) {
+ for (i=0; i < Rows; i++) {
NewElem ->Offset[i] = Offset[i];
}
@@ -741,7 +741,7 @@ int IdentitySampler(register const cmsUInt16Number In[], register cmsUInt16Numbe
}
// Creates an MPE that just copies input to output
-cmsStage* _cmsStageAllocIdentityCLut(cmsContext ContextID, int nChan)
+cmsStage* CMSEXPORT _cmsStageAllocIdentityCLut(cmsContext ContextID, cmsUInt32Number nChan)
{
cmsUInt32Number Dimensions[MAX_INPUT_DIMENSIONS];
cmsStage* mpe ;
@@ -765,7 +765,7 @@ cmsStage* _cmsStageAllocIdentityCLut(cmsContext ContextID, int nChan)
// Quantize a value 0 <= i < MaxSamples to 0..0xffff
-cmsUInt16Number _cmsQuantizeVal(cmsFloat64Number i, int MaxSamples)
+cmsUInt16Number CMSEXPORT _cmsQuantizeVal(cmsFloat64Number i, cmsUInt32Number MaxSamples)
{
cmsFloat64Number x;
@@ -778,8 +778,9 @@ cmsUInt16Number _cmsQuantizeVal(cmsFloat64Number i, int MaxSamples)
// function on knots. returns TRUE if all ok, FALSE otherwise.
cmsBool CMSEXPORT cmsStageSampleCLut16bit(cmsStage* mpe, cmsSAMPLER16 Sampler, void * Cargo, cmsUInt32Number dwFlags)
{
- int i, t, nTotalPoints, index, rest;
- int nInputs, nOutputs;
+ int i, t, index, rest;
+ cmsUInt32Number nTotalPoints;
+ cmsUInt32Number nInputs, nOutputs;
cmsUInt32Number* nSamples;
cmsUInt16Number In[MAX_INPUT_DIMENSIONS+1], Out[MAX_STAGE_CHANNELS];
_cmsStageCLutData* clut;
@@ -799,14 +800,17 @@ cmsBool CMSEXPORT cmsStageSampleCLut16bit(cmsStage* mpe, cmsSAMPLER16 Sampler, v
if (nInputs > MAX_INPUT_DIMENSIONS) return FALSE;
if (nOutputs >= MAX_STAGE_CHANNELS) return FALSE;
+ memset(In, 0, sizeof(In));
+ memset(Out, 0, sizeof(Out));
+
nTotalPoints = CubeSize(nSamples, nInputs);
if (nTotalPoints == 0) return FALSE;
index = 0;
- for (i = 0; i < nTotalPoints; i++) {
+ for (i = 0; i < (int) nTotalPoints; i++) {
rest = i;
- for (t = nInputs-1; t >=0; --t) {
+ for (t = (int)nInputs - 1; t >= 0; --t) {
cmsUInt32Number Colorant = rest % nSamples[t];
@@ -816,7 +820,7 @@ cmsBool CMSEXPORT cmsStageSampleCLut16bit(cmsStage* mpe, cmsSAMPLER16 Sampler, v
}
if (clut ->Tab.T != NULL) {
- for (t=0; t < nOutputs; t++)
+ for (t = 0; t < (int)nOutputs; t++)
Out[t] = clut->Tab.T[index + t];
}
@@ -826,7 +830,7 @@ cmsBool CMSEXPORT cmsStageSampleCLut16bit(cmsStage* mpe, cmsSAMPLER16 Sampler, v
if (!(dwFlags & SAMPLER_INSPECT)) {
if (clut ->Tab.T != NULL) {
- for (t=0; t < nOutputs; t++)
+ for (t=0; t < (int) nOutputs; t++)
clut->Tab.T[index + t] = Out[t];
}
}
@@ -837,11 +841,12 @@ cmsBool CMSEXPORT cmsStageSampleCLut16bit(cmsStage* mpe, cmsSAMPLER16 Sampler, v
return TRUE;
}
-// Same as anterior, but for floting point
+// Same as anterior, but for floating point
cmsBool CMSEXPORT cmsStageSampleCLutFloat(cmsStage* mpe, cmsSAMPLERFLOAT Sampler, void * Cargo, cmsUInt32Number dwFlags)
{
- int i, t, nTotalPoints, index, rest;
- int nInputs, nOutputs;
+ int i, t, index, rest;
+ cmsUInt32Number nTotalPoints;
+ cmsUInt32Number nInputs, nOutputs;
cmsUInt32Number* nSamples;
cmsFloat32Number In[MAX_INPUT_DIMENSIONS+1], Out[MAX_STAGE_CHANNELS];
_cmsStageCLutData* clut = (_cmsStageCLutData*) mpe->Data;
@@ -859,10 +864,10 @@ cmsBool CMSEXPORT cmsStageSampleCLutFloat(cmsStage* mpe, cmsSAMPLERFLOAT Sampler
if (nTotalPoints == 0) return FALSE;
index = 0;
- for (i = 0; i < nTotalPoints; i++) {
+ for (i = 0; i < (int)nTotalPoints; i++) {
rest = i;
- for (t = nInputs-1; t >=0; --t) {
+ for (t = (int) nInputs-1; t >=0; --t) {
cmsUInt32Number Colorant = rest % nSamples[t];
@@ -872,7 +877,7 @@ cmsBool CMSEXPORT cmsStageSampleCLutFloat(cmsStage* mpe, cmsSAMPLERFLOAT Sampler
}
if (clut ->Tab.TFloat != NULL) {
- for (t=0; t < nOutputs; t++)
+ for (t=0; t < (int) nOutputs; t++)
Out[t] = clut->Tab.TFloat[index + t];
}
@@ -882,7 +887,7 @@ cmsBool CMSEXPORT cmsStageSampleCLutFloat(cmsStage* mpe, cmsSAMPLERFLOAT Sampler
if (!(dwFlags & SAMPLER_INSPECT)) {
if (clut ->Tab.TFloat != NULL) {
- for (t=0; t < nOutputs; t++)
+ for (t=0; t < (int) nOutputs; t++)
clut->Tab.TFloat[index + t] = Out[t];
}
}
@@ -900,7 +905,8 @@ cmsBool CMSEXPORT cmsStageSampleCLutFloat(cmsStage* mpe, cmsSAMPLERFLOAT Sampler
cmsBool CMSEXPORT cmsSliceSpace16(cmsUInt32Number nInputs, const cmsUInt32Number clutPoints[],
cmsSAMPLER16 Sampler, void * Cargo)
{
- int i, t, nTotalPoints, rest;
+ int i, t, rest;
+ cmsUInt32Number nTotalPoints;
cmsUInt16Number In[cmsMAXCHANNELS];
if (nInputs >= cmsMAXCHANNELS) return FALSE;
@@ -908,10 +914,10 @@ cmsBool CMSEXPORT cmsSliceSpace16(cmsUInt32Number nInputs, const cmsUInt32Number
nTotalPoints = CubeSize(clutPoints, nInputs);
if (nTotalPoints == 0) return FALSE;
- for (i = 0; i < nTotalPoints; i++) {
+ for (i = 0; i < (int) nTotalPoints; i++) {
rest = i;
- for (t = nInputs-1; t >=0; --t) {
+ for (t = (int) nInputs-1; t >=0; --t) {
cmsUInt32Number Colorant = rest % clutPoints[t];
@@ -930,7 +936,8 @@ cmsBool CMSEXPORT cmsSliceSpace16(cmsUInt32Number nInputs, const cmsUInt32Number
cmsInt32Number CMSEXPORT cmsSliceSpaceFloat(cmsUInt32Number nInputs, const cmsUInt32Number clutPoints[],
cmsSAMPLERFLOAT Sampler, void * Cargo)
{
- int i, t, nTotalPoints, rest;
+ int i, t, rest;
+ cmsUInt32Number nTotalPoints;
cmsFloat32Number In[cmsMAXCHANNELS];
if (nInputs >= cmsMAXCHANNELS) return FALSE;
@@ -938,10 +945,10 @@ cmsInt32Number CMSEXPORT cmsSliceSpaceFloat(cmsUInt32Number nInputs, const cmsUI
nTotalPoints = CubeSize(clutPoints, nInputs);
if (nTotalPoints == 0) return FALSE;
- for (i = 0; i < nTotalPoints; i++) {
+ for (i = 0; i < (int) nTotalPoints; i++) {
rest = i;
- for (t = nInputs-1; t >=0; --t) {
+ for (t = (int) nInputs-1; t >=0; --t) {
cmsUInt32Number Colorant = rest % clutPoints[t];
@@ -991,7 +998,7 @@ void EvaluateLab2XYZ(const cmsFloat32Number In[],
// No dup or free routines needed, as the structure has no pointers in it.
-cmsStage* _cmsStageAllocLab2XYZ(cmsContext ContextID)
+cmsStage* CMSEXPORT _cmsStageAllocLab2XYZ(cmsContext ContextID)
{
return _cmsStageAllocPlaceholder(ContextID, cmsSigLab2XYZElemType, 3, 3, EvaluateLab2XYZ, NULL, NULL, NULL);
}
@@ -1021,7 +1028,7 @@ cmsStage* _cmsStageAllocLabV2ToV4curves(cmsContext ContextID)
return NULL;
}
- // We need to map * (0xffff / 0xff00), thats same as (257 / 256)
+ // We need to map * (0xffff / 0xff00), that's same as (257 / 256)
// So we can use 258-entry tables to do the trick (i / 257) * (255 * 257) * (257 / 256);
for (i=0; i < 257; i++) {
@@ -1042,7 +1049,7 @@ cmsStage* _cmsStageAllocLabV2ToV4curves(cmsContext ContextID)
// ********************************************************************************
// Matrix-based conversion, which is more accurate, but slower and cannot properly be saved in devicelink profiles
-cmsStage* _cmsStageAllocLabV2ToV4(cmsContext ContextID)
+cmsStage* CMSEXPORT _cmsStageAllocLabV2ToV4(cmsContext ContextID)
{
static const cmsFloat64Number V2ToV4[] = { 65535.0/65280.0, 0, 0,
0, 65535.0/65280.0, 0,
@@ -1058,7 +1065,7 @@ cmsStage* _cmsStageAllocLabV2ToV4(cmsContext ContextID)
// Reverse direction
-cmsStage* _cmsStageAllocLabV4ToV2(cmsContext ContextID)
+cmsStage* CMSEXPORT _cmsStageAllocLabV4ToV2(cmsContext ContextID)
{
static const cmsFloat64Number V4ToV2[] = { 65280.0/65535.0, 0, 0,
0, 65280.0/65535.0, 0,
@@ -1166,7 +1173,7 @@ void Clipper(const cmsFloat32Number In[], cmsFloat32Number Out[], const cmsStage
}
}
-cmsStage* _cmsStageClipNegatives(cmsContext ContextID, int nChannels)
+cmsStage* _cmsStageClipNegatives(cmsContext ContextID, cmsUInt32Number nChannels)
{
return _cmsStageAllocPlaceholder(ContextID, cmsSigClipNegativesElemType,
nChannels, nChannels, Clipper, NULL, NULL, NULL);
@@ -1201,7 +1208,7 @@ void EvaluateXYZ2Lab(const cmsFloat32Number In[], cmsFloat32Number Out[], const
cmsUNUSED_PARAMETER(mpe);
}
-cmsStage* _cmsStageAllocXYZ2Lab(cmsContext ContextID)
+cmsStage* CMSEXPORT _cmsStageAllocXYZ2Lab(cmsContext ContextID)
{
return _cmsStageAllocPlaceholder(ContextID, cmsSigXYZ2LabElemType, 3, 3, EvaluateXYZ2Lab, NULL, NULL, NULL);
@@ -1300,23 +1307,42 @@ cmsStage* CMSEXPORT cmsStageDup(cmsStage* mpe)
// ***********************************************************************************************************
// This function sets up the channel count
-
static
-void BlessLUT(cmsPipeline* lut)
+cmsBool BlessLUT(cmsPipeline* lut)
{
- // We can set the input/ouput channels only if we have elements.
+ // We can set the input/output channels only if we have elements.
if (lut ->Elements != NULL) {
- cmsStage *First, *Last;
+ cmsStage* prev;
+ cmsStage* next;
+ cmsStage* First;
+ cmsStage* Last;
First = cmsPipelineGetPtrToFirstStage(lut);
Last = cmsPipelineGetPtrToLastStage(lut);
- if (First != NULL)lut ->InputChannels = First ->InputChannels;
- if (Last != NULL) lut ->OutputChannels = Last ->OutputChannels;
+ if (First == NULL || Last == NULL) return FALSE;
+
+ lut->InputChannels = First->InputChannels;
+ lut->OutputChannels = Last->OutputChannels;
+
+ // Check chain consistency
+ prev = First;
+ next = prev->Next;
+
+ while (next != NULL)
+ {
+ if (next->InputChannels != prev->OutputChannels)
+ return FALSE;
+
+ next = next->Next;
+ prev = prev->Next;
}
}
+ return TRUE;
+}
+
// Default to evaluate the LUT on 16 bit-basis. Precision is retained.
static
@@ -1368,21 +1394,18 @@ void _LUTevalFloat(register const cmsFloat32Number In[], register cmsFloat32Numb
}
-
-
// LUT Creation & Destruction
-
cmsPipeline* CMSEXPORT cmsPipelineAlloc(cmsContext ContextID, cmsUInt32Number InputChannels, cmsUInt32Number OutputChannels)
{
cmsPipeline* NewLUT;
+ // A value of zero in channels is allowed as placeholder
if (InputChannels >= cmsMAXCHANNELS ||
OutputChannels >= cmsMAXCHANNELS) return NULL;
NewLUT = (cmsPipeline*) _cmsMallocZero(ContextID, sizeof(cmsPipeline));
if (NewLUT == NULL) return NULL;
-
NewLUT -> InputChannels = InputChannels;
NewLUT -> OutputChannels = OutputChannels;
@@ -1393,7 +1416,11 @@ cmsPipeline* CMSEXPORT cmsPipelineAlloc(cmsContext ContextID, cmsUInt32Number In
NewLUT ->Data = NewLUT;
NewLUT ->ContextID = ContextID;
- BlessLUT(NewLUT);
+ if (!BlessLUT(NewLUT))
+ {
+ _cmsFree(ContextID, NewLUT);
+ return NULL;
+ }
return NewLUT;
}
@@ -1500,7 +1527,12 @@ cmsPipeline* CMSEXPORT cmsPipelineDup(const cmsPipeline* lut)
NewLUT ->SaveAs8Bits = lut ->SaveAs8Bits;
- BlessLUT(NewLUT);
+ if (!BlessLUT(NewLUT))
+ {
+ _cmsFree(lut->ContextID, NewLUT);
+ return NULL;
+ }
+
return NewLUT;
}
@@ -1537,8 +1569,7 @@ int CMSEXPORT cmsPipelineInsertStage(cmsPipeline* lut, cmsStageLoc loc, cmsStage
return FALSE;
}
- BlessLUT(lut);
- return TRUE;
+ return BlessLUT(lut);
}
// Unlink an element and return the pointer to it
@@ -1593,6 +1624,7 @@ void CMSEXPORT cmsPipelineUnlinkStage(cmsPipeline* lut, cmsStageLoc loc, cmsStag
else
cmsStageFree(Unlinked);
+ // May fail, but we ignore it
BlessLUT(lut);
}
@@ -1619,8 +1651,7 @@ cmsBool CMSEXPORT cmsPipelineCat(cmsPipeline* l1, const cmsPipeline* l2)
return FALSE;
}
- BlessLUT(l1);
- return TRUE;
+ return BlessLUT(l1);
}
diff --git a/src/java.desktop/share/native/liblcms/cmsmd5.c b/src/java.desktop/share/native/liblcms/cmsmd5.c
index 619c94edf4c..d86c9822ec8 100644
--- a/src/java.desktop/share/native/liblcms/cmsmd5.c
+++ b/src/java.desktop/share/native/liblcms/cmsmd5.c
@@ -30,7 +30,7 @@
//---------------------------------------------------------------------------------
//
// Little Color Management System
-// Copyright (c) 1998-2016 Marti Maria Saguer
+// Copyright (c) 1998-2017 Marti Maria Saguer
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
diff --git a/src/java.desktop/share/native/liblcms/cmsmtrx.c b/src/java.desktop/share/native/liblcms/cmsmtrx.c
index 2bc6a497775..916a2926810 100644
--- a/src/java.desktop/share/native/liblcms/cmsmtrx.c
+++ b/src/java.desktop/share/native/liblcms/cmsmtrx.c
@@ -30,7 +30,7 @@
//---------------------------------------------------------------------------------
//
// Little Color Management System
-// Copyright (c) 1998-2016 Marti Maria Saguer
+// Copyright (c) 1998-2017 Marti Maria Saguer
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
diff --git a/src/java.desktop/share/native/liblcms/cmsnamed.c b/src/java.desktop/share/native/liblcms/cmsnamed.c
index d1edeb4ce12..177ed799465 100644
--- a/src/java.desktop/share/native/liblcms/cmsnamed.c
+++ b/src/java.desktop/share/native/liblcms/cmsnamed.c
@@ -30,7 +30,7 @@
//---------------------------------------------------------------------------------
//
// Little Color Management System
-// Copyright (c) 1998-2016 Marti Maria Saguer
+// Copyright (c) 1998-2017 Marti Maria Saguer
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
@@ -156,7 +156,7 @@ int SearchMLUEntry(cmsMLU* mlu, cmsUInt16Number LanguageCode, cmsUInt16Number Co
for (i=0; i < mlu ->UsedEntries; i++) {
if (mlu ->Entries[i].Country == CountryCode &&
- mlu ->Entries[i].Language == LanguageCode) return i;
+ mlu ->Entries[i].Language == LanguageCode) return (int) i;
}
// Not found
@@ -207,31 +207,24 @@ cmsBool AddMLUBlock(cmsMLU* mlu, cmsUInt32Number size, const wchar_t *Block,
return TRUE;
}
-// Convert from a 3-char code to a cmsUInt16Number. It is done inthis way because some
+// Convert from a 3-char code to a cmsUInt16Number. It is done in this way because some
// compilers don't properly align beginning of strings
static
cmsUInt16Number strTo16(const char str[3])
{
- cmsUInt16Number n = ((cmsUInt16Number) str[0] << 8) | str[1];
+ const cmsUInt8Number* ptr8 = (const cmsUInt8Number*)str;
+ cmsUInt16Number n = (cmsUInt16Number)(((cmsUInt16Number)ptr8[0] << 8) | ptr8[1]);
- return n; // Always big endian in this case
+ return n;
}
static
void strFrom16(char str[3], cmsUInt16Number n)
{
- // Assiming this would be aligned
- union {
-
- cmsUInt16Number n;
- char str[2];
-
- } c;
-
- c.n = n; // Always big endian in this case
-
- str[0] = c.str[0]; str[1] = c.str[1]; str[2] = 0;
+ str[0] = (char)(n >> 8);
+ str[1] = (char)n;
+ str[2] = (char)0;
}
@@ -354,7 +347,7 @@ const wchar_t* _cmsMLUgetWide(const cmsMLU* mlu,
cmsUInt16Number* UsedLanguageCode, cmsUInt16Number* UsedCountryCode)
{
cmsUInt32Number i;
- cmsInt32Number Best = -1;
+ int Best = -1;
_cmsMLUentry* v;
if (mlu == NULL) return NULL;
@@ -367,7 +360,7 @@ const wchar_t* _cmsMLUgetWide(const cmsMLU* mlu,
if (v -> Language == LanguageCode) {
- if (Best == -1) Best = i;
+ if (Best == -1) Best = (int) i;
if (v -> Country == CountryCode) {
@@ -633,10 +626,10 @@ cmsBool CMSEXPORT cmsAppendNamedColor(cmsNAMEDCOLORLIST* NamedColorList,
}
for (i=0; i < NamedColorList ->ColorantCount; i++)
- NamedColorList ->List[NamedColorList ->nColors].DeviceColorant[i] = Colorant == NULL? 0 : Colorant[i];
+ NamedColorList ->List[NamedColorList ->nColors].DeviceColorant[i] = Colorant == NULL ? (cmsUInt16Number)0 : Colorant[i];
for (i=0; i < 3; i++)
- NamedColorList ->List[NamedColorList ->nColors].PCS[i] = PCS == NULL ? 0 : PCS[i];
+ NamedColorList ->List[NamedColorList ->nColors].PCS[i] = PCS == NULL ? (cmsUInt16Number) 0 : PCS[i];
if (Name != NULL) {
@@ -671,6 +664,7 @@ cmsBool CMSEXPORT cmsNamedColorInfo(const cmsNAMEDCOLORLIST* NamedColorList, cm
if (nColor >= cmsNamedColorCount(NamedColorList)) return FALSE;
+ // strcpy instead of strncpy because many apps are using small buffers
if (Name) strcpy(Name, NamedColorList->List[nColor].Name);
if (Prefix) strcpy(Prefix, NamedColorList->Prefix);
if (Suffix) strcpy(Suffix, NamedColorList->Suffix);
@@ -688,13 +682,14 @@ cmsBool CMSEXPORT cmsNamedColorInfo(const cmsNAMEDCOLORLIST* NamedColorList, cm
// Search for a given color name (no prefix or suffix)
cmsInt32Number CMSEXPORT cmsNamedColorIndex(const cmsNAMEDCOLORLIST* NamedColorList, const char* Name)
{
- int i, n;
+ cmsUInt32Number i;
+ cmsUInt32Number n;
if (NamedColorList == NULL) return -1;
n = cmsNamedColorCount(NamedColorList);
for (i=0; i < n; i++) {
if (cmsstrcasecmp(Name, NamedColorList->List[i].Name) == 0)
- return i;
+ return (cmsInt32Number) i;
}
return -1;
@@ -723,7 +718,8 @@ void EvalNamedColorPCS(const cmsFloat32Number In[], cmsFloat32Number Out[], cons
cmsUInt16Number index = (cmsUInt16Number) _cmsQuickSaturateWord(In[0] * 65535.0);
if (index >= NamedColorList-> nColors) {
- cmsSignalError(NamedColorList ->ContextID, cmsERROR_RANGE, "Color %d out of range; ignored", index);
+ cmsSignalError(NamedColorList ->ContextID, cmsERROR_RANGE, "Color %d out of range", index);
+ Out[0] = Out[1] = Out[2] = 0.0f;
}
else {
@@ -742,7 +738,10 @@ void EvalNamedColor(const cmsFloat32Number In[], cmsFloat32Number Out[], const c
cmsUInt32Number j;
if (index >= NamedColorList-> nColors) {
- cmsSignalError(NamedColorList ->ContextID, cmsERROR_RANGE, "Color %d out of range; ignored", index);
+ cmsSignalError(NamedColorList ->ContextID, cmsERROR_RANGE, "Color %d out of range", index);
+ for (j = 0; j < NamedColorList->ColorantCount; j++)
+ Out[j] = 0.0f;
+
}
else {
for (j=0; j < NamedColorList ->ColorantCount; j++)
@@ -752,7 +751,7 @@ void EvalNamedColor(const cmsFloat32Number In[], cmsFloat32Number Out[], const c
// Named color lookup element
-cmsStage* _cmsStageAllocNamedColor(cmsNAMEDCOLORLIST* NamedColorList, cmsBool UsePCS)
+cmsStage* CMSEXPORT _cmsStageAllocNamedColor(cmsNAMEDCOLORLIST* NamedColorList, cmsBool UsePCS)
{
return _cmsStageAllocPlaceholder(NamedColorList ->ContextID,
cmsSigNamedColorElemType,
diff --git a/src/java.desktop/share/native/liblcms/cmsopt.c b/src/java.desktop/share/native/liblcms/cmsopt.c
index a3ff2fc10e3..395ececad79 100644
--- a/src/java.desktop/share/native/liblcms/cmsopt.c
+++ b/src/java.desktop/share/native/liblcms/cmsopt.c
@@ -30,7 +30,7 @@
//---------------------------------------------------------------------------------
//
// Little Color Management System
-// Copyright (c) 1998-2016 Marti Maria Saguer
+// Copyright (c) 1998-2017 Marti Maria Saguer
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
@@ -78,8 +78,8 @@ typedef struct {
cmsContext ContextID;
// Number of channels
- int nInputs;
- int nOutputs;
+ cmsUInt32Number nInputs;
+ cmsUInt32Number nOutputs;
_cmsInterpFn16 EvalCurveIn16[MAX_INPUT_DIMENSIONS]; // The maximum number of input channels is known in advance
cmsInterpParams* ParamsCurveIn16[MAX_INPUT_DIMENSIONS];
@@ -123,8 +123,8 @@ typedef struct {
cmsContext ContextID;
- int nCurves; // Number of curves
- int nElements; // Elements in curves
+ cmsUInt32Number nCurves; // Number of curves
+ cmsUInt32Number nElements; // Elements in curves
cmsUInt16Number** Curves; // Points to a dynamically allocated array
} Curves16Data;
@@ -245,7 +245,7 @@ cmsBool _MultiplyMatrix(cmsPipeline* Lut)
// Multiply both matrices to get the result
_cmsMAT3per(&res, (cmsMAT3*)m2->Double, (cmsMAT3*)m1->Double);
- // Get the next in chain afer the matrices
+ // Get the next in chain after the matrices
chain = (*pt2)->Next;
// Remove both matrices
@@ -334,7 +334,7 @@ void PrelinEval16(register const cmsUInt16Number Input[],
Prelin16Data* p16 = (Prelin16Data*) D;
cmsUInt16Number StageABC[MAX_INPUT_DIMENSIONS];
cmsUInt16Number StageDEF[cmsMAXCHANNELS];
- int i;
+ cmsUInt32Number i;
for (i=0; i < p16 ->nInputs; i++) {
@@ -379,15 +379,15 @@ void* Prelin16dup(cmsContext ContextID, const void* ptr)
static
Prelin16Data* PrelinOpt16alloc(cmsContext ContextID,
const cmsInterpParams* ColorMap,
- int nInputs, cmsToneCurve** In,
- int nOutputs, cmsToneCurve** Out )
+ cmsUInt32Number nInputs, cmsToneCurve** In,
+ cmsUInt32Number nOutputs, cmsToneCurve** Out )
{
- int i;
+ cmsUInt32Number i;
Prelin16Data* p16 = (Prelin16Data*)_cmsMallocZero(ContextID, sizeof(Prelin16Data));
if (p16 == NULL) return NULL;
p16 ->nInputs = nInputs;
- p16 -> nOutputs = nOutputs;
+ p16 ->nOutputs = nOutputs;
for (i=0; i < nInputs; i++) {
@@ -435,7 +435,7 @@ Prelin16Data* PrelinOpt16alloc(cmsContext ContextID,
// Sampler implemented by another LUT. This is a clean way to precalculate the devicelink 3D CLUT for
// almost any transform. We use floating point precision and then convert from floating point to 16 bits.
static
-int XFormSampler16(register const cmsUInt16Number In[], register cmsUInt16Number Out[], register void* Cargo)
+cmsInt32Number XFormSampler16(register const cmsUInt16Number In[], register cmsUInt16Number Out[], register void* Cargo)
{
cmsPipeline* Lut = (cmsPipeline*) Cargo;
cmsFloat32Number InFloat[cmsMAXCHANNELS], OutFloat[cmsMAXCHANNELS];
@@ -482,7 +482,7 @@ cmsBool AllCurvesAreLinear(cmsStage* mpe)
// is to fix scum dot on broken profiles/transforms. Works on 1, 3 and 4 channels
static
cmsBool PatchLUT(cmsStage* CLUT, cmsUInt16Number At[], cmsUInt16Number Value[],
- int nChannelsOut, int nChannelsIn)
+ cmsUInt32Number nChannelsOut, cmsUInt32Number nChannelsIn)
{
_cmsStageCLutData* Grid = (_cmsStageCLutData*) CLUT ->Data;
cmsInterpParams* p16 = Grid ->Params;
@@ -512,10 +512,10 @@ cmsBool PatchLUT(cmsStage* CLUT, cmsUInt16Number At[], cmsUInt16Number Value[],
((pz - z0) != 0) ||
((pw - w0) != 0)) return FALSE; // Not on exact node
- index = p16 -> opta[3] * x0 +
- p16 -> opta[2] * y0 +
- p16 -> opta[1] * z0 +
- p16 -> opta[0] * w0;
+ index = (int) p16 -> opta[3] * x0 +
+ (int) p16 -> opta[2] * y0 +
+ (int) p16 -> opta[1] * z0 +
+ (int) p16 -> opta[0] * w0;
}
else
if (nChannelsIn == 3) {
@@ -532,9 +532,9 @@ cmsBool PatchLUT(cmsStage* CLUT, cmsUInt16Number At[], cmsUInt16Number Value[],
((py - y0) != 0) ||
((pz - z0) != 0)) return FALSE; // Not on exact node
- index = p16 -> opta[2] * x0 +
- p16 -> opta[1] * y0 +
- p16 -> opta[0] * z0;
+ index = (int) p16 -> opta[2] * x0 +
+ (int) p16 -> opta[1] * y0 +
+ (int) p16 -> opta[0] * z0;
}
else
if (nChannelsIn == 1) {
@@ -545,24 +545,24 @@ cmsBool PatchLUT(cmsStage* CLUT, cmsUInt16Number At[], cmsUInt16Number Value[],
if (((px - x0) != 0)) return FALSE; // Not on exact node
- index = p16 -> opta[0] * x0;
+ index = (int) p16 -> opta[0] * x0;
}
else {
cmsSignalError(CLUT->ContextID, cmsERROR_INTERNAL, "(internal) %d Channels are not supported on PatchLUT", nChannelsIn);
return FALSE;
}
- for (i=0; i < nChannelsOut; i++)
- Grid -> Tab.T[index + i] = Value[i];
+ for (i = 0; i < (int) nChannelsOut; i++)
+ Grid->Tab.T[index + i] = Value[i];
return TRUE;
}
// Auxiliary, to see if two values are equal or very different
static
-cmsBool WhitesAreEqual(int n, cmsUInt16Number White1[], cmsUInt16Number White2[] )
+cmsBool WhitesAreEqual(cmsUInt32Number n, cmsUInt16Number White1[], cmsUInt16Number White2[] )
{
- int i;
+ cmsUInt32Number i;
for (i=0; i < n; i++) {
@@ -664,7 +664,7 @@ cmsBool OptimizeByResampling(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3
cmsStage* mpe;
cmsStage* CLUT;
cmsStage *KeepPreLin = NULL, *KeepPostLin = NULL;
- int nGridPoints;
+ cmsUInt32Number nGridPoints;
cmsColorSpaceSignature ColorSpace, OutputColorSpace;
cmsStage *NewPreLin = NULL;
cmsStage *NewPostLin = NULL;
@@ -676,8 +676,13 @@ cmsBool OptimizeByResampling(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3
// This is a loosy optimization! does not apply in floating-point cases
if (_cmsFormatterIsFloat(*InputFormat) || _cmsFormatterIsFloat(*OutputFormat)) return FALSE;
- ColorSpace = _cmsICCcolorSpace(T_COLORSPACE(*InputFormat));
- OutputColorSpace = _cmsICCcolorSpace(T_COLORSPACE(*OutputFormat));
+ ColorSpace = _cmsICCcolorSpace((int) T_COLORSPACE(*InputFormat));
+ OutputColorSpace = _cmsICCcolorSpace((int) T_COLORSPACE(*OutputFormat));
+
+ // Color space must be specified
+ if (ColorSpace == (cmsColorSpaceSignature)0 ||
+ OutputColorSpace == (cmsColorSpaceSignature)0) return FALSE;
+
nGridPoints = _cmsReasonableGridpointsByColorspace(ColorSpace, *dwFlags);
// For empty LUTs, 2 points are enough
@@ -715,7 +720,7 @@ cmsBool OptimizeByResampling(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3
goto Error;
// Remove prelinearization. Since we have duplicated the curve
- // in destination LUT, the sampling shoud be applied after this stage.
+ // in destination LUT, the sampling should be applied after this stage.
cmsPipelineUnlinkStage(Src, cmsAT_BEGIN, &KeepPreLin);
}
}
@@ -723,7 +728,7 @@ cmsBool OptimizeByResampling(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3
// Allocate the CLUT
CLUT = cmsStageAllocCLut16bit(Src ->ContextID, nGridPoints, Src ->InputChannels, Src->OutputChannels, NULL);
- if (CLUT == NULL) return FALSE;
+ if (CLUT == NULL) goto Error;
// Add the CLUT to the destination LUT
if (!cmsPipelineInsertStage(Dest, cmsAT_END, CLUT)) {
@@ -747,14 +752,14 @@ cmsBool OptimizeByResampling(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3
if (!cmsPipelineInsertStage(Dest, cmsAT_END, NewPostLin))
goto Error;
- // In destination LUT, the sampling shoud be applied after this stage.
+ // In destination LUT, the sampling should be applied after this stage.
cmsPipelineUnlinkStage(Src, cmsAT_END, &KeepPostLin);
}
}
}
// Now its time to do the sampling. We have to ignore pre/post linearization
- // The source LUT whithout pre/post curves is passed as parameter.
+ // The source LUT without pre/post curves is passed as parameter.
if (!cmsStageSampleCLut16bit(CLUT, XFormSampler16, (void*) Src, 0)) {
Error:
// Ops, something went wrong, Restore stages
@@ -834,7 +839,7 @@ void SlopeLimiting(cmsToneCurve* g)
{
int BeginVal, EndVal;
int AtBegin = (int) floor((cmsFloat64Number) g ->nEntries * 0.02 + 0.5); // Cutoff at 2%
- int AtEnd = g ->nEntries - AtBegin - 1; // And 98%
+ int AtEnd = (int) g ->nEntries - AtBegin - 1; // And 98%
cmsFloat64Number Val, Slope, beta;
int i;
@@ -895,9 +900,9 @@ Prelin8Data* PrelinOpt8alloc(cmsContext ContextID, const cmsInterpParams* p, cms
// Move to 0..1.0 in fixed domain
- v1 = _cmsToFixedDomain(Input[0] * p -> Domain[0]);
- v2 = _cmsToFixedDomain(Input[1] * p -> Domain[1]);
- v3 = _cmsToFixedDomain(Input[2] * p -> Domain[2]);
+ v1 = _cmsToFixedDomain((int) (Input[0] * p -> Domain[0]));
+ v2 = _cmsToFixedDomain((int) (Input[1] * p -> Domain[1]));
+ v3 = _cmsToFixedDomain((int) (Input[2] * p -> Domain[2]));
// Store the precalculated table of nodes
p8 ->X0[i] = (p->opta[2] * FIXED_TO_INT(v1));
@@ -942,27 +947,27 @@ void PrelinEval8(register const cmsUInt16Number Input[],
cmsS15Fixed16Number rx, ry, rz;
cmsS15Fixed16Number c0, c1, c2, c3, Rest;
int OutChan;
- register cmsS15Fixed16Number X0, X1, Y0, Y1, Z0, Z1;
+ register cmsS15Fixed16Number X0, X1, Y0, Y1, Z0, Z1;
Prelin8Data* p8 = (Prelin8Data*) D;
register const cmsInterpParams* p = p8 ->p;
- int TotalOut = p -> nOutputs;
+ int TotalOut = (int) p -> nOutputs;
const cmsUInt16Number* LutTable = (const cmsUInt16Number*) p->Table;
- r = Input[0] >> 8;
- g = Input[1] >> 8;
- b = Input[2] >> 8;
+ r = (cmsUInt8Number) (Input[0] >> 8);
+ g = (cmsUInt8Number) (Input[1] >> 8);
+ b = (cmsUInt8Number) (Input[2] >> 8);
- X0 = X1 = p8->X0[r];
- Y0 = Y1 = p8->Y0[g];
- Z0 = Z1 = p8->Z0[b];
+ X0 = X1 = (cmsS15Fixed16Number) p8->X0[r];
+ Y0 = Y1 = (cmsS15Fixed16Number) p8->Y0[g];
+ Z0 = Z1 = (cmsS15Fixed16Number) p8->Z0[b];
rx = p8 ->rx[r];
ry = p8 ->ry[g];
rz = p8 ->rz[b];
- X1 = X0 + ((rx == 0) ? 0 : p ->opta[2]);
- Y1 = Y0 + ((ry == 0) ? 0 : p ->opta[1]);
- Z1 = Z0 + ((rz == 0) ? 0 : p ->opta[0]);
+ X1 = X0 + (cmsS15Fixed16Number)((rx == 0) ? 0 : p ->opta[2]);
+ Y1 = Y0 + (cmsS15Fixed16Number)((ry == 0) ? 0 : p ->opta[1]);
+ Z1 = Z0 + (cmsS15Fixed16Number)((rz == 0) ? 0 : p ->opta[0]);
// These are the 6 Tetrahedral
@@ -1015,9 +1020,8 @@ void PrelinEval8(register const cmsUInt16Number Input[],
c1 = c2 = c3 = 0;
}
-
Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001;
- Output[OutChan] = (cmsUInt16Number)c0 + ((Rest + (Rest>>16))>>16);
+ Output[OutChan] = (cmsUInt16Number) (c0 + ((Rest + (Rest >> 16)) >> 16));
}
}
@@ -1029,8 +1033,8 @@ void PrelinEval8(register const cmsUInt16Number Input[],
static
cmsBool IsDegenerated(const cmsToneCurve* g)
{
- int i, Zeros = 0, Poles = 0;
- int nEntries = g ->nEntries;
+ cmsUInt32Number i, Zeros = 0, Poles = 0;
+ cmsUInt32Number nEntries = g ->nEntries;
for (i=0; i < nEntries; i++) {
@@ -1052,7 +1056,7 @@ static
cmsBool OptimizeByComputingLinearization(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt32Number* InputFormat, cmsUInt32Number* OutputFormat, cmsUInt32Number* dwFlags)
{
cmsPipeline* OriginalLut;
- int nGridPoints;
+ cmsUInt32Number nGridPoints;
cmsToneCurve *Trans[cmsMAXCHANNELS], *TransReverse[cmsMAXCHANNELS];
cmsUInt32Number t, i;
cmsFloat32Number v, In[cmsMAXCHANNELS], Out[cmsMAXCHANNELS];
@@ -1090,8 +1094,13 @@ cmsBool OptimizeByComputingLinearization(cmsPipeline** Lut, cmsUInt32Number Inte
if (cmsStageType(mpe) == cmsSigNamedColorElemType) return FALSE;
}
- ColorSpace = _cmsICCcolorSpace(T_COLORSPACE(*InputFormat));
- OutputColorSpace = _cmsICCcolorSpace(T_COLORSPACE(*OutputFormat));
+ ColorSpace = _cmsICCcolorSpace((int) T_COLORSPACE(*InputFormat));
+ OutputColorSpace = _cmsICCcolorSpace((int) T_COLORSPACE(*OutputFormat));
+
+ // Color space must be specified
+ if (ColorSpace == (cmsColorSpaceSignature)0 ||
+ OutputColorSpace == (cmsColorSpaceSignature)0) return FALSE;
+
nGridPoints = _cmsReasonableGridpointsByColorspace(ColorSpace, *dwFlags);
// Empty gamma containers
@@ -1212,7 +1221,10 @@ cmsBool OptimizeByComputingLinearization(cmsPipeline** Lut, cmsUInt32Number Inte
Prelin8Data* p8 = PrelinOpt8alloc(OptimizedLUT ->ContextID,
OptimizedPrelinCLUT ->Params,
OptimizedPrelinCurves);
- if (p8 == NULL) return FALSE;
+ if (p8 == NULL) {
+ cmsPipelineFree(OptimizedLUT);
+ return FALSE;
+ }
_cmsPipelineSetOptimizationParameters(OptimizedLUT, PrelinEval8, (void*) p8, Prelin8free, Prelin8dup);
@@ -1222,7 +1234,10 @@ cmsBool OptimizeByComputingLinearization(cmsPipeline** Lut, cmsUInt32Number Inte
Prelin16Data* p16 = PrelinOpt16alloc(OptimizedLUT ->ContextID,
OptimizedPrelinCLUT ->Params,
3, OptimizedPrelinCurves, 3, NULL);
- if (p16 == NULL) return FALSE;
+ if (p16 == NULL) {
+ cmsPipelineFree(OptimizedLUT);
+ return FALSE;
+ }
_cmsPipelineSetOptimizationParameters(OptimizedLUT, PrelinEval16, (void*) p16, PrelinOpt16free, Prelin16dup);
@@ -1260,6 +1275,7 @@ cmsBool OptimizeByComputingLinearization(cmsPipeline** Lut, cmsUInt32Number Inte
return FALSE;
cmsUNUSED_PARAMETER(Intent);
+ cmsUNUSED_PARAMETER(lIsLinear);
}
@@ -1269,7 +1285,7 @@ static
void CurvesFree(cmsContext ContextID, void* ptr)
{
Curves16Data* Data = (Curves16Data*) ptr;
- int i;
+ cmsUInt32Number i;
for (i=0; i < Data -> nCurves; i++) {
@@ -1284,7 +1300,7 @@ static
void* CurvesDup(cmsContext ContextID, const void* ptr)
{
Curves16Data* Data = (Curves16Data*)_cmsDupMem(ContextID, ptr, sizeof(Curves16Data));
- int i;
+ cmsUInt32Number i;
if (Data == NULL) return NULL;
@@ -1299,9 +1315,9 @@ void* CurvesDup(cmsContext ContextID, const void* ptr)
// Precomputes tables for 8-bit on input devicelink.
static
-Curves16Data* CurvesAlloc(cmsContext ContextID, int nCurves, int nElements, cmsToneCurve** G)
+Curves16Data* CurvesAlloc(cmsContext ContextID, cmsUInt32Number nCurves, cmsUInt32Number nElements, cmsToneCurve** G)
{
- int i, j;
+ cmsUInt32Number i, j;
Curves16Data* c16;
c16 = (Curves16Data*)_cmsMallocZero(ContextID, sizeof(Curves16Data));
@@ -1311,7 +1327,10 @@ Curves16Data* CurvesAlloc(cmsContext ContextID, int nCurves, int nElements, cmsT
c16 ->nElements = nElements;
c16->Curves = (cmsUInt16Number**) _cmsCalloc(ContextID, nCurves, sizeof(cmsUInt16Number*));
- if (c16 ->Curves == NULL) return NULL;
+ if (c16->Curves == NULL) {
+ _cmsFree(ContextID, c16);
+ return NULL;
+ }
for (i=0; i < nCurves; i++) {
@@ -1327,7 +1346,7 @@ Curves16Data* CurvesAlloc(cmsContext ContextID, int nCurves, int nElements, cmsT
return NULL;
}
- if (nElements == 256) {
+ if (nElements == 256U) {
for (j=0; j < nElements; j++) {
@@ -1351,8 +1370,8 @@ void FastEvaluateCurves8(register const cmsUInt16Number In[],
register const void* D)
{
Curves16Data* Data = (Curves16Data*) D;
- cmsUInt8Number x;
- int i;
+ int x;
+ cmsUInt32Number i;
for (i=0; i < Data ->nCurves; i++) {
@@ -1368,7 +1387,7 @@ void FastEvaluateCurves16(register const cmsUInt16Number In[],
register const void* D)
{
Curves16Data* Data = (Curves16Data*) D;
- int i;
+ cmsUInt32Number i;
for (i=0; i < Data ->nCurves; i++) {
Out[i] = Data -> Curves[i][In[i]];
@@ -1548,9 +1567,9 @@ void MatShaperEval16(register const cmsUInt16Number In[],
// In this case (and only in this case!) we can use this simplification since
// In[] is assured to come from a 8 bit number. (a << 8 | a)
- ri = In[0] & 0xFF;
- gi = In[1] & 0xFF;
- bi = In[2] & 0xFF;
+ ri = In[0] & 0xFFU;
+ gi = In[1] & 0xFFU;
+ bi = In[2] & 0xFFU;
// Across first shaper, which also converts to 1.14 fixed point
r = p->Shaper1R[ri];
@@ -1563,9 +1582,9 @@ void MatShaperEval16(register const cmsUInt16Number In[],
l3 = (p->Mat[2][0] * r + p->Mat[2][1] * g + p->Mat[2][2] * b + p->Off[2] + 0x2000) >> 14;
// Now we have to clip to 0..1.0 range
- ri = (l1 < 0) ? 0 : ((l1 > 16384) ? 16384 : l1);
- gi = (l2 < 0) ? 0 : ((l2 > 16384) ? 16384 : l2);
- bi = (l3 < 0) ? 0 : ((l3 > 16384) ? 16384 : l3);
+ ri = (l1 < 0) ? 0 : ((l1 > 16384) ? 16384U : (cmsUInt32Number) l1);
+ gi = (l2 < 0) ? 0 : ((l2 > 16384) ? 16384U : (cmsUInt32Number) l2);
+ bi = (l3 < 0) ? 0 : ((l3 > 16384) ? 16384U : (cmsUInt32Number) l3);
// And across second shaper,
Out[0] = p->Shaper2R[ri];
@@ -1586,7 +1605,10 @@ void FillFirstShaper(cmsS1Fixed14Number* Table, cmsToneCurve* Curve)
R = (cmsFloat32Number) (i / 255.0);
y = cmsEvalToneCurveFloat(Curve, R);
- Table[i] = DOUBLE_TO_1FIXED14(y);
+ if (y < 131072.0)
+ Table[i] = DOUBLE_TO_1FIXED14(y);
+ else
+ Table[i] = 0x7fffffff;
}
}
@@ -1602,6 +1624,12 @@ void FillSecondShaper(cmsUInt16Number* Table, cmsToneCurve* Curve, cmsBool Is8Bi
R = (cmsFloat32Number) (i / 16384.0);
Val = cmsEvalToneCurveFloat(Curve, R); // Val comes 0..1.0
+ if (Val < 0)
+ Val = 0;
+
+ if (Val > 1.0)
+ Val = 1.0;
+
if (Is8BitsOutput) {
// If 8 bits output, we can optimize further by computing the / 257 part.
@@ -1640,7 +1668,7 @@ cmsBool SetMatShaper(cmsPipeline* Dest, cmsToneCurve* Curve1[3], cmsMAT3* Mat, c
FillSecondShaper(p ->Shaper2G, Curve2[1], Is8Bits);
FillSecondShaper(p ->Shaper2B, Curve2[2], Is8Bits);
- // Convert matrix to nFixed14. Note that those values may take more than 16 bits as
+ // Convert matrix to nFixed14. Note that those values may take more than 16 bits
for (i=0; i < 3; i++) {
for (j=0; j < 3; j++) {
p ->Mat[i][j] = DOUBLE_TO_1FIXED14(Mat->v[i].n[j]);
@@ -1902,7 +1930,7 @@ cmsBool _cmsRegisterOptimizationPlugin(cmsContext ContextID, cmsPluginBase* Dat
// The entry point for LUT optimization
cmsBool _cmsOptimizePipeline(cmsContext ContextID,
cmsPipeline** PtrLut,
- int Intent,
+ cmsUInt32Number Intent,
cmsUInt32Number* InputFormat,
cmsUInt32Number* OutputFormat,
cmsUInt32Number* dwFlags)
diff --git a/src/java.desktop/share/native/liblcms/cmspack.c b/src/java.desktop/share/native/liblcms/cmspack.c
index a9087f6fc8a..7aabcc244ed 100644
--- a/src/java.desktop/share/native/liblcms/cmspack.c
+++ b/src/java.desktop/share/native/liblcms/cmspack.c
@@ -30,7 +30,7 @@
//---------------------------------------------------------------------------------
//
// Little Color Management System
-// Copyright (c) 1998-2016 Marti Maria Saguer
+// Copyright (c) 1998-2017 Marti Maria Saguer
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
@@ -126,21 +126,21 @@ cmsUInt8Number* UnrollChunkyBytes(register _cmsTRANSFORM* info,
register cmsUInt8Number* accum,
register cmsUInt32Number Stride)
{
- int nChan = T_CHANNELS(info -> InputFormat);
- int DoSwap = T_DOSWAP(info ->InputFormat);
- int Reverse = T_FLAVOR(info ->InputFormat);
- int SwapFirst = T_SWAPFIRST(info -> InputFormat);
- int Extra = T_EXTRA(info -> InputFormat);
- int ExtraFirst = DoSwap ^ SwapFirst;
+ cmsUInt32Number nChan = T_CHANNELS(info -> InputFormat);
+ cmsUInt32Number DoSwap = T_DOSWAP(info ->InputFormat);
+ cmsUInt32Number Reverse = T_FLAVOR(info ->InputFormat);
+ cmsUInt32Number SwapFirst = T_SWAPFIRST(info -> InputFormat);
+ cmsUInt32Number Extra = T_EXTRA(info -> InputFormat);
+ cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst;
cmsUInt16Number v;
- int i;
+ cmsUInt32Number i;
if (ExtraFirst) {
accum += Extra;
}
for (i=0; i < nChan; i++) {
- int index = DoSwap ? (nChan - i - 1) : i;
+ cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i;
v = FROM_8_TO_16(*accum);
v = Reverse ? REVERSE_FLAVOR_16(v) : v;
@@ -173,11 +173,11 @@ cmsUInt8Number* UnrollPlanarBytes(register _cmsTRANSFORM* info,
register cmsUInt8Number* accum,
register cmsUInt32Number Stride)
{
- int nChan = T_CHANNELS(info -> InputFormat);
- int DoSwap = T_DOSWAP(info ->InputFormat);
- int SwapFirst = T_SWAPFIRST(info ->InputFormat);
- int Reverse = T_FLAVOR(info ->InputFormat);
- int i;
+ cmsUInt32Number nChan = T_CHANNELS(info -> InputFormat);
+ cmsUInt32Number DoSwap = T_DOSWAP(info ->InputFormat);
+ cmsUInt32Number SwapFirst = T_SWAPFIRST(info ->InputFormat);
+ cmsUInt32Number Reverse = T_FLAVOR(info ->InputFormat);
+ cmsUInt32Number i;
cmsUInt8Number* Init = accum;
if (DoSwap ^ SwapFirst) {
@@ -186,7 +186,7 @@ cmsUInt8Number* UnrollPlanarBytes(register _cmsTRANSFORM* info,
for (i=0; i < nChan; i++) {
- int index = DoSwap ? (nChan - i - 1) : i;
+ cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i;
cmsUInt16Number v = FROM_8_TO_16(*accum);
wIn[index] = Reverse ? REVERSE_FLAVOR_16(v) : v;
@@ -503,14 +503,14 @@ cmsUInt8Number* UnrollAnyWords(register _cmsTRANSFORM* info,
register cmsUInt8Number* accum,
register cmsUInt32Number Stride)
{
- int nChan = T_CHANNELS(info -> InputFormat);
- int SwapEndian = T_ENDIAN16(info -> InputFormat);
- int DoSwap = T_DOSWAP(info ->InputFormat);
- int Reverse = T_FLAVOR(info ->InputFormat);
- int SwapFirst = T_SWAPFIRST(info -> InputFormat);
- int Extra = T_EXTRA(info -> InputFormat);
- int ExtraFirst = DoSwap ^ SwapFirst;
- int i;
+ cmsUInt32Number nChan = T_CHANNELS(info -> InputFormat);
+ cmsUInt32Number SwapEndian = T_ENDIAN16(info -> InputFormat);
+ cmsUInt32Number DoSwap = T_DOSWAP(info ->InputFormat);
+ cmsUInt32Number Reverse = T_FLAVOR(info ->InputFormat);
+ cmsUInt32Number SwapFirst = T_SWAPFIRST(info -> InputFormat);
+ cmsUInt32Number Extra = T_EXTRA(info -> InputFormat);
+ cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst;
+ cmsUInt32Number i;
if (ExtraFirst) {
accum += Extra * sizeof(cmsUInt16Number);
@@ -518,7 +518,7 @@ cmsUInt8Number* UnrollAnyWords(register _cmsTRANSFORM* info,
for (i=0; i < nChan; i++) {
- int index = DoSwap ? (nChan - i - 1) : i;
+ cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i;
cmsUInt16Number v = *(cmsUInt16Number*) accum;
if (SwapEndian)
@@ -552,20 +552,20 @@ cmsUInt8Number* UnrollPlanarWords(register _cmsTRANSFORM* info,
register cmsUInt8Number* accum,
register cmsUInt32Number Stride)
{
- int nChan = T_CHANNELS(info -> InputFormat);
- int DoSwap= T_DOSWAP(info ->InputFormat);
- int Reverse= T_FLAVOR(info ->InputFormat);
- int SwapEndian = T_ENDIAN16(info -> InputFormat);
- int i;
+ cmsUInt32Number nChan = T_CHANNELS(info -> InputFormat);
+ cmsUInt32Number DoSwap= T_DOSWAP(info ->InputFormat);
+ cmsUInt32Number Reverse= T_FLAVOR(info ->InputFormat);
+ cmsUInt32Number SwapEndian = T_ENDIAN16(info -> InputFormat);
+ cmsUInt32Number i;
cmsUInt8Number* Init = accum;
if (DoSwap) {
- accum += T_EXTRA(info -> InputFormat) * Stride * sizeof(cmsUInt16Number);
+ accum += T_EXTRA(info -> InputFormat) * Stride;
}
for (i=0; i < nChan; i++) {
- int index = DoSwap ? (nChan - i - 1) : i;
+ cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i;
cmsUInt16Number v = *(cmsUInt16Number*) accum;
if (SwapEndian)
@@ -573,7 +573,7 @@ cmsUInt8Number* UnrollPlanarWords(register _cmsTRANSFORM* info,
wIn[index] = Reverse ? REVERSE_FLAVOR_16(v) : v;
- accum += Stride * sizeof(cmsUInt16Number);
+ accum += Stride;
}
return (Init + sizeof(cmsUInt16Number));
@@ -801,13 +801,18 @@ cmsUInt8Number* UnrollLabDoubleTo16(register _cmsTRANSFORM* info,
{
if (T_PLANAR(info -> InputFormat)) {
- cmsFloat64Number* Pt = (cmsFloat64Number*) accum;
-
cmsCIELab Lab;
+ cmsUInt8Number* pos_L;
+ cmsUInt8Number* pos_a;
+ cmsUInt8Number* pos_b;
+
+ pos_L = accum;
+ pos_a = accum + Stride;
+ pos_b = accum + Stride * 2;
- Lab.L = Pt[0];
- Lab.a = Pt[Stride];
- Lab.b = Pt[Stride*2];
+ Lab.L = *(cmsFloat64Number*) pos_L;
+ Lab.a = *(cmsFloat64Number*) pos_a;
+ Lab.b = *(cmsFloat64Number*) pos_b;
cmsFloat2LabEncoded(wIn, &Lab);
return accum + sizeof(cmsFloat64Number);
@@ -832,12 +837,17 @@ cmsUInt8Number* UnrollLabFloatTo16(register _cmsTRANSFORM* info,
if (T_PLANAR(info -> InputFormat)) {
- cmsFloat32Number* Pt = (cmsFloat32Number*) accum;
+ cmsUInt8Number* pos_L;
+ cmsUInt8Number* pos_a;
+ cmsUInt8Number* pos_b;
+ pos_L = accum;
+ pos_a = accum + Stride;
+ pos_b = accum + Stride * 2;
- Lab.L = Pt[0];
- Lab.a = Pt[Stride];
- Lab.b = Pt[Stride*2];
+ Lab.L = *(cmsFloat32Number*)pos_L;
+ Lab.a = *(cmsFloat32Number*)pos_a;
+ Lab.b = *(cmsFloat32Number*)pos_b;
cmsFloat2LabEncoded(wIn, &Lab);
return accum + sizeof(cmsFloat32Number);
@@ -863,12 +873,19 @@ cmsUInt8Number* UnrollXYZDoubleTo16(register _cmsTRANSFORM* info,
{
if (T_PLANAR(info -> InputFormat)) {
- cmsFloat64Number* Pt = (cmsFloat64Number*) accum;
cmsCIEXYZ XYZ;
+ cmsUInt8Number* pos_X;
+ cmsUInt8Number* pos_Y;
+ cmsUInt8Number* pos_Z;
+
+ pos_X = accum;
+ pos_Y = accum + Stride;
+ pos_Z = accum + Stride * 2;
+
+ XYZ.X = *(cmsFloat64Number*)pos_X;
+ XYZ.Y = *(cmsFloat64Number*)pos_Y;
+ XYZ.Z = *(cmsFloat64Number*)pos_Z;
- XYZ.X = Pt[0];
- XYZ.Y = Pt[Stride];
- XYZ.Z = Pt[Stride*2];
cmsFloat2XYZEncoded(wIn, &XYZ);
return accum + sizeof(cmsFloat64Number);
@@ -892,12 +909,19 @@ cmsUInt8Number* UnrollXYZFloatTo16(register _cmsTRANSFORM* info,
{
if (T_PLANAR(info -> InputFormat)) {
- cmsFloat32Number* Pt = (cmsFloat32Number*) accum;
cmsCIEXYZ XYZ;
+ cmsUInt8Number* pos_X;
+ cmsUInt8Number* pos_Y;
+ cmsUInt8Number* pos_Z;
+
+ pos_X = accum;
+ pos_Y = accum + Stride;
+ pos_Z = accum + Stride * 2;
+
+ XYZ.X = *(cmsFloat32Number*)pos_X;
+ XYZ.Y = *(cmsFloat32Number*)pos_Y;
+ XYZ.Z = *(cmsFloat32Number*)pos_Z;
- XYZ.X = Pt[0];
- XYZ.Y = Pt[Stride];
- XYZ.Z = Pt[Stride*2];
cmsFloat2XYZEncoded(wIn, &XYZ);
return accum + sizeof(cmsFloat32Number);
@@ -942,6 +966,20 @@ cmsINLINE cmsBool IsInkSpace(cmsUInt32Number Type)
}
}
+// Return the size in bytes of a given formatter
+static
+cmsUInt32Number PixelSize(cmsUInt32Number Format)
+{
+ cmsUInt32Number fmt_bytes = T_BYTES(Format);
+
+ // For double, the T_BYTES field is zero
+ if (fmt_bytes == 0)
+ return sizeof(cmsUInt64Number);
+
+ // Otherwise, it is already correct for all formats
+ return fmt_bytes;
+}
+
// Inks does come in percentage, remaining cases are between 0..1.0, again to 16 bits
static
cmsUInt8Number* UnrollDoubleTo16(register _cmsTRANSFORM* info,
@@ -950,25 +988,27 @@ cmsUInt8Number* UnrollDoubleTo16(register _cmsTRANSFORM* info,
register cmsUInt32Number Stride)
{
- int nChan = T_CHANNELS(info -> InputFormat);
- int DoSwap = T_DOSWAP(info ->InputFormat);
- int Reverse = T_FLAVOR(info ->InputFormat);
- int SwapFirst = T_SWAPFIRST(info -> InputFormat);
- int Extra = T_EXTRA(info -> InputFormat);
- int ExtraFirst = DoSwap ^ SwapFirst;
- int Planar = T_PLANAR(info -> InputFormat);
+ cmsUInt32Number nChan = T_CHANNELS(info -> InputFormat);
+ cmsUInt32Number DoSwap = T_DOSWAP(info ->InputFormat);
+ cmsUInt32Number Reverse = T_FLAVOR(info ->InputFormat);
+ cmsUInt32Number SwapFirst = T_SWAPFIRST(info -> InputFormat);
+ cmsUInt32Number Extra = T_EXTRA(info -> InputFormat);
+ cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst;
+ cmsUInt32Number Planar = T_PLANAR(info -> InputFormat);
cmsFloat64Number v;
cmsUInt16Number vi;
- int i, start = 0;
- cmsFloat64Number maximum = IsInkSpace(info ->InputFormat) ? 655.35 : 65535.0;
+ cmsUInt32Number i, start = 0;
+ cmsFloat64Number maximum = IsInkSpace(info ->InputFormat) ? 655.35 : 65535.0;
+
+ Stride /= PixelSize(info->InputFormat);
if (ExtraFirst)
start = Extra;
for (i=0; i < nChan; i++) {
- int index = DoSwap ? (nChan - i - 1) : i;
+ cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i;
if (Planar)
v = (cmsFloat32Number) ((cmsFloat64Number*) accum)[(i + start) * Stride];
@@ -1006,25 +1046,26 @@ cmsUInt8Number* UnrollFloatTo16(register _cmsTRANSFORM* info,
register cmsUInt32Number Stride)
{
- int nChan = T_CHANNELS(info -> InputFormat);
- int DoSwap = T_DOSWAP(info ->InputFormat);
- int Reverse = T_FLAVOR(info ->InputFormat);
- int SwapFirst = T_SWAPFIRST(info -> InputFormat);
- int Extra = T_EXTRA(info -> InputFormat);
- int ExtraFirst = DoSwap ^ SwapFirst;
- int Planar = T_PLANAR(info -> InputFormat);
+ cmsUInt32Number nChan = T_CHANNELS(info -> InputFormat);
+ cmsUInt32Number DoSwap = T_DOSWAP(info ->InputFormat);
+ cmsUInt32Number Reverse = T_FLAVOR(info ->InputFormat);
+ cmsUInt32Number SwapFirst = T_SWAPFIRST(info -> InputFormat);
+ cmsUInt32Number Extra = T_EXTRA(info -> InputFormat);
+ cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst;
+ cmsUInt32Number Planar = T_PLANAR(info -> InputFormat);
cmsFloat32Number v;
cmsUInt16Number vi;
- int i, start = 0;
- cmsFloat64Number maximum = IsInkSpace(info ->InputFormat) ? 655.35 : 65535.0;
+ cmsUInt32Number i, start = 0;
+ cmsFloat64Number maximum = IsInkSpace(info ->InputFormat) ? 655.35 : 65535.0;
+ Stride /= PixelSize(info->InputFormat);
if (ExtraFirst)
start = Extra;
for (i=0; i < nChan; i++) {
- int index = DoSwap ? (nChan - i - 1) : i;
+ cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i;
if (Planar)
v = (cmsFloat32Number) ((cmsFloat32Number*) accum)[(i + start) * Stride];
@@ -1083,24 +1124,25 @@ cmsUInt8Number* UnrollFloatsToFloat(_cmsTRANSFORM* info,
cmsUInt32Number Stride)
{
- int nChan = T_CHANNELS(info -> InputFormat);
- int DoSwap = T_DOSWAP(info ->InputFormat);
- int Reverse = T_FLAVOR(info ->InputFormat);
- int SwapFirst = T_SWAPFIRST(info -> InputFormat);
- int Extra = T_EXTRA(info -> InputFormat);
- int ExtraFirst = DoSwap ^ SwapFirst;
- int Planar = T_PLANAR(info -> InputFormat);
+ cmsUInt32Number nChan = T_CHANNELS(info -> InputFormat);
+ cmsUInt32Number DoSwap = T_DOSWAP(info ->InputFormat);
+ cmsUInt32Number Reverse = T_FLAVOR(info ->InputFormat);
+ cmsUInt32Number SwapFirst = T_SWAPFIRST(info -> InputFormat);
+ cmsUInt32Number Extra = T_EXTRA(info -> InputFormat);
+ cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst;
+ cmsUInt32Number Planar = T_PLANAR(info -> InputFormat);
cmsFloat32Number v;
- int i, start = 0;
+ cmsUInt32Number i, start = 0;
cmsFloat32Number maximum = IsInkSpace(info ->InputFormat) ? 100.0F : 1.0F;
+ Stride /= PixelSize(info->InputFormat);
if (ExtraFirst)
start = Extra;
for (i=0; i < nChan; i++) {
- int index = DoSwap ? (nChan - i - 1) : i;
+ cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i;
if (Planar)
v = (cmsFloat32Number) ((cmsFloat32Number*) accum)[(i + start) * Stride];
@@ -1135,24 +1177,25 @@ cmsUInt8Number* UnrollDoublesToFloat(_cmsTRANSFORM* info,
cmsUInt32Number Stride)
{
- int nChan = T_CHANNELS(info -> InputFormat);
- int DoSwap = T_DOSWAP(info ->InputFormat);
- int Reverse = T_FLAVOR(info ->InputFormat);
- int SwapFirst = T_SWAPFIRST(info -> InputFormat);
- int Extra = T_EXTRA(info -> InputFormat);
- int ExtraFirst = DoSwap ^ SwapFirst;
- int Planar = T_PLANAR(info -> InputFormat);
+ cmsUInt32Number nChan = T_CHANNELS(info -> InputFormat);
+ cmsUInt32Number DoSwap = T_DOSWAP(info ->InputFormat);
+ cmsUInt32Number Reverse = T_FLAVOR(info ->InputFormat);
+ cmsUInt32Number SwapFirst = T_SWAPFIRST(info -> InputFormat);
+ cmsUInt32Number Extra = T_EXTRA(info -> InputFormat);
+ cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst;
+ cmsUInt32Number Planar = T_PLANAR(info -> InputFormat);
cmsFloat64Number v;
- int i, start = 0;
+ cmsUInt32Number i, start = 0;
cmsFloat64Number maximum = IsInkSpace(info ->InputFormat) ? 100.0 : 1.0;
+ Stride /= PixelSize(info->InputFormat);
if (ExtraFirst)
start = Extra;
for (i=0; i < nChan; i++) {
- int index = DoSwap ? (nChan - i - 1) : i;
+ cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i;
if (Planar)
v = (cmsFloat64Number) ((cmsFloat64Number*) accum)[(i + start) * Stride];
@@ -1191,7 +1234,9 @@ cmsUInt8Number* UnrollLabDoubleToFloat(_cmsTRANSFORM* info,
if (T_PLANAR(info -> InputFormat)) {
- wIn[0] = (cmsFloat32Number) (Pt[0] / 100.0); // from 0..100 to 0..1
+ Stride /= PixelSize(info->InputFormat);
+
+ wIn[0] = (cmsFloat32Number) (Pt[0] / 100.0); // from 0..100 to 0..1
wIn[1] = (cmsFloat32Number) ((Pt[Stride] + 128) / 255.0); // form -128..+127 to 0..1
wIn[2] = (cmsFloat32Number) ((Pt[Stride*2] + 128) / 255.0);
@@ -1219,6 +1264,8 @@ cmsUInt8Number* UnrollLabFloatToFloat(_cmsTRANSFORM* info,
if (T_PLANAR(info -> InputFormat)) {
+ Stride /= PixelSize(info->InputFormat);
+
wIn[0] = (cmsFloat32Number) (Pt[0] / 100.0); // from 0..100 to 0..1
wIn[1] = (cmsFloat32Number) ((Pt[Stride] + 128) / 255.0); // form -128..+127 to 0..1
wIn[2] = (cmsFloat32Number) ((Pt[Stride*2] + 128) / 255.0);
@@ -1249,6 +1296,8 @@ cmsUInt8Number* UnrollXYZDoubleToFloat(_cmsTRANSFORM* info,
if (T_PLANAR(info -> InputFormat)) {
+ Stride /= PixelSize(info->InputFormat);
+
wIn[0] = (cmsFloat32Number) (Pt[0] / MAX_ENCODEABLE_XYZ);
wIn[1] = (cmsFloat32Number) (Pt[Stride] / MAX_ENCODEABLE_XYZ);
wIn[2] = (cmsFloat32Number) (Pt[Stride*2] / MAX_ENCODEABLE_XYZ);
@@ -1276,6 +1325,8 @@ cmsUInt8Number* UnrollXYZFloatToFloat(_cmsTRANSFORM* info,
if (T_PLANAR(info -> InputFormat)) {
+ Stride /= PixelSize(info->InputFormat);
+
wIn[0] = (cmsFloat32Number) (Pt[0] / MAX_ENCODEABLE_XYZ);
wIn[1] = (cmsFloat32Number) (Pt[Stride] / MAX_ENCODEABLE_XYZ);
wIn[2] = (cmsFloat32Number) (Pt[Stride*2] / MAX_ENCODEABLE_XYZ);
@@ -1306,15 +1357,15 @@ cmsUInt8Number* PackAnyBytes(register _cmsTRANSFORM* info,
register cmsUInt8Number* output,
register cmsUInt32Number Stride)
{
- int nChan = T_CHANNELS(info -> OutputFormat);
- int DoSwap = T_DOSWAP(info ->OutputFormat);
- int Reverse = T_FLAVOR(info ->OutputFormat);
- int Extra = T_EXTRA(info -> OutputFormat);
- int SwapFirst = T_SWAPFIRST(info -> OutputFormat);
- int ExtraFirst = DoSwap ^ SwapFirst;
+ cmsUInt32Number nChan = T_CHANNELS(info -> OutputFormat);
+ cmsUInt32Number DoSwap = T_DOSWAP(info ->OutputFormat);
+ cmsUInt32Number Reverse = T_FLAVOR(info ->OutputFormat);
+ cmsUInt32Number Extra = T_EXTRA(info -> OutputFormat);
+ cmsUInt32Number SwapFirst = T_SWAPFIRST(info -> OutputFormat);
+ cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst;
cmsUInt8Number* swap1;
cmsUInt8Number v = 0;
- int i;
+ cmsUInt32Number i;
swap1 = output;
@@ -1324,7 +1375,7 @@ cmsUInt8Number* PackAnyBytes(register _cmsTRANSFORM* info,
for (i=0; i < nChan; i++) {
- int index = DoSwap ? (nChan - i - 1) : i;
+ cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i;
v = FROM_16_TO_8(wOut[index]);
@@ -1358,16 +1409,16 @@ cmsUInt8Number* PackAnyWords(register _cmsTRANSFORM* info,
register cmsUInt8Number* output,
register cmsUInt32Number Stride)
{
- int nChan = T_CHANNELS(info -> OutputFormat);
- int SwapEndian = T_ENDIAN16(info -> InputFormat);
- int DoSwap = T_DOSWAP(info ->OutputFormat);
- int Reverse = T_FLAVOR(info ->OutputFormat);
- int Extra = T_EXTRA(info -> OutputFormat);
- int SwapFirst = T_SWAPFIRST(info -> OutputFormat);
- int ExtraFirst = DoSwap ^ SwapFirst;
+ cmsUInt32Number nChan = T_CHANNELS(info -> OutputFormat);
+ cmsUInt32Number SwapEndian = T_ENDIAN16(info -> OutputFormat);
+ cmsUInt32Number DoSwap = T_DOSWAP(info ->OutputFormat);
+ cmsUInt32Number Reverse = T_FLAVOR(info ->OutputFormat);
+ cmsUInt32Number Extra = T_EXTRA(info -> OutputFormat);
+ cmsUInt32Number SwapFirst = T_SWAPFIRST(info -> OutputFormat);
+ cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst;
cmsUInt16Number* swap1;
cmsUInt16Number v = 0;
- int i;
+ cmsUInt32Number i;
swap1 = (cmsUInt16Number*) output;
@@ -1377,7 +1428,7 @@ cmsUInt8Number* PackAnyWords(register _cmsTRANSFORM* info,
for (i=0; i < nChan; i++) {
- int index = DoSwap ? (nChan - i - 1) : i;
+ cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i;
v = wOut[index];
@@ -1415,11 +1466,11 @@ cmsUInt8Number* PackPlanarBytes(register _cmsTRANSFORM* info,
register cmsUInt8Number* output,
register cmsUInt32Number Stride)
{
- int nChan = T_CHANNELS(info -> OutputFormat);
- int DoSwap = T_DOSWAP(info ->OutputFormat);
- int SwapFirst = T_SWAPFIRST(info ->OutputFormat);
- int Reverse = T_FLAVOR(info ->OutputFormat);
- int i;
+ cmsUInt32Number nChan = T_CHANNELS(info -> OutputFormat);
+ cmsUInt32Number DoSwap = T_DOSWAP(info ->OutputFormat);
+ cmsUInt32Number SwapFirst = T_SWAPFIRST(info ->OutputFormat);
+ cmsUInt32Number Reverse = T_FLAVOR(info ->OutputFormat);
+ cmsUInt32Number i;
cmsUInt8Number* Init = output;
@@ -1430,7 +1481,7 @@ cmsUInt8Number* PackPlanarBytes(register _cmsTRANSFORM* info,
for (i=0; i < nChan; i++) {
- int index = DoSwap ? (nChan - i - 1) : i;
+ cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i;
cmsUInt8Number v = FROM_16_TO_8(wOut[index]);
*(cmsUInt8Number*) output = (cmsUInt8Number) (Reverse ? REVERSE_FLAVOR_8(v) : v);
@@ -1449,21 +1500,21 @@ cmsUInt8Number* PackPlanarWords(register _cmsTRANSFORM* info,
register cmsUInt8Number* output,
register cmsUInt32Number Stride)
{
- int nChan = T_CHANNELS(info -> OutputFormat);
- int DoSwap = T_DOSWAP(info ->OutputFormat);
- int Reverse= T_FLAVOR(info ->OutputFormat);
- int SwapEndian = T_ENDIAN16(info -> OutputFormat);
- int i;
+ cmsUInt32Number nChan = T_CHANNELS(info -> OutputFormat);
+ cmsUInt32Number DoSwap = T_DOSWAP(info ->OutputFormat);
+ cmsUInt32Number Reverse = T_FLAVOR(info ->OutputFormat);
+ cmsUInt32Number SwapEndian = T_ENDIAN16(info -> OutputFormat);
+ cmsUInt32Number i;
cmsUInt8Number* Init = output;
cmsUInt16Number v;
if (DoSwap) {
- output += T_EXTRA(info -> OutputFormat) * Stride * sizeof(cmsUInt16Number);
+ output += T_EXTRA(info -> OutputFormat) * Stride;
}
for (i=0; i < nChan; i++) {
- int index = DoSwap ? (nChan - i - 1) : i;
+ cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i;
v = wOut[index];
@@ -1474,7 +1525,7 @@ cmsUInt8Number* PackPlanarWords(register _cmsTRANSFORM* info,
v = REVERSE_FLAVOR_16(v);
*(cmsUInt16Number*) output = v;
- output += (Stride * sizeof(cmsUInt16Number));
+ output += Stride;
}
return (Init + sizeof(cmsUInt16Number));
@@ -1823,9 +1874,9 @@ cmsUInt8Number* Pack3BytesOptimized(register _cmsTRANSFORM* info,
register cmsUInt8Number* output,
register cmsUInt32Number Stride)
{
- *output++ = (wOut[0] & 0xFF);
- *output++ = (wOut[1] & 0xFF);
- *output++ = (wOut[2] & 0xFF);
+ *output++ = (wOut[0] & 0xFFU);
+ *output++ = (wOut[1] & 0xFFU);
+ *output++ = (wOut[2] & 0xFFU);
return output;
@@ -1855,9 +1906,9 @@ cmsUInt8Number* Pack3BytesSwapOptimized(register _cmsTRANSFORM* info,
register cmsUInt8Number* output,
register cmsUInt32Number Stride)
{
- *output++ = (wOut[2] & 0xFF);
- *output++ = (wOut[1] & 0xFF);
- *output++ = (wOut[0] & 0xFF);
+ *output++ = (wOut[2] & 0xFFU);
+ *output++ = (wOut[1] & 0xFFU);
+ *output++ = (wOut[0] & 0xFFU);
return output;
@@ -1946,9 +1997,9 @@ cmsUInt8Number* Pack3BytesAndSkip1Optimized(register _cmsTRANSFORM* info,
register cmsUInt8Number* output,
register cmsUInt32Number Stride)
{
- *output++ = (wOut[0] & 0xFF);
- *output++ = (wOut[1] & 0xFF);
- *output++ = (wOut[2] & 0xFF);
+ *output++ = (wOut[0] & 0xFFU);
+ *output++ = (wOut[1] & 0xFFU);
+ *output++ = (wOut[2] & 0xFFU);
output++;
return output;
@@ -1982,9 +2033,9 @@ cmsUInt8Number* Pack3BytesAndSkip1SwapFirstOptimized(register _cmsTRANSFORM* inf
register cmsUInt32Number Stride)
{
output++;
- *output++ = (wOut[0] & 0xFF);
- *output++ = (wOut[1] & 0xFF);
- *output++ = (wOut[2] & 0xFF);
+ *output++ = (wOut[0] & 0xFFU);
+ *output++ = (wOut[1] & 0xFFU);
+ *output++ = (wOut[2] & 0xFFU);
return output;
@@ -2016,9 +2067,9 @@ cmsUInt8Number* Pack3BytesAndSkip1SwapOptimized(register _cmsTRANSFORM* info,
register cmsUInt32Number Stride)
{
output++;
- *output++ = (wOut[2] & 0xFF);
- *output++ = (wOut[1] & 0xFF);
- *output++ = (wOut[0] & 0xFF);
+ *output++ = (wOut[2] & 0xFFU);
+ *output++ = (wOut[1] & 0xFFU);
+ *output++ = (wOut[0] & 0xFFU);
return output;
@@ -2050,9 +2101,9 @@ cmsUInt8Number* Pack3BytesAndSkip1SwapSwapFirstOptimized(register _cmsTRANSFORM*
register cmsUInt8Number* output,
register cmsUInt32Number Stride)
{
- *output++ = (wOut[2] & 0xFF);
- *output++ = (wOut[1] & 0xFF);
- *output++ = (wOut[0] & 0xFF);
+ *output++ = (wOut[2] & 0xFFU);
+ *output++ = (wOut[1] & 0xFFU);
+ *output++ = (wOut[0] & 0xFFU);
output++;
return output;
@@ -2326,6 +2377,8 @@ cmsUInt8Number* PackLabFloatFrom16(register _cmsTRANSFORM* info,
cmsFloat32Number* Out = (cmsFloat32Number*) output;
+ Stride /= PixelSize(info->OutputFormat);
+
Out[0] = (cmsFloat32Number)Lab.L;
Out[Stride] = (cmsFloat32Number)Lab.a;
Out[Stride*2] = (cmsFloat32Number)Lab.b;
@@ -2354,6 +2407,8 @@ cmsUInt8Number* PackXYZDoubleFrom16(register _cmsTRANSFORM* Info,
cmsFloat64Number* Out = (cmsFloat64Number*) output;
cmsXYZEncoded2Float(&XYZ, wOut);
+ Stride /= PixelSize(Info->OutputFormat);
+
Out[0] = XYZ.X;
Out[Stride] = XYZ.Y;
Out[Stride*2] = XYZ.Z;
@@ -2381,6 +2436,8 @@ cmsUInt8Number* PackXYZFloatFrom16(register _cmsTRANSFORM* Info,
cmsFloat32Number* Out = (cmsFloat32Number*) output;
cmsXYZEncoded2Float(&XYZ, wOut);
+ Stride /= PixelSize(Info->OutputFormat);
+
Out[0] = (cmsFloat32Number) XYZ.X;
Out[Stride] = (cmsFloat32Number) XYZ.Y;
Out[Stride*2] = (cmsFloat32Number) XYZ.Z;
@@ -2408,24 +2465,26 @@ cmsUInt8Number* PackDoubleFrom16(register _cmsTRANSFORM* info,
register cmsUInt8Number* output,
register cmsUInt32Number Stride)
{
- int nChan = T_CHANNELS(info -> OutputFormat);
- int DoSwap = T_DOSWAP(info ->OutputFormat);
- int Reverse = T_FLAVOR(info ->OutputFormat);
- int Extra = T_EXTRA(info -> OutputFormat);
- int SwapFirst = T_SWAPFIRST(info -> OutputFormat);
- int Planar = T_PLANAR(info -> OutputFormat);
- int ExtraFirst = DoSwap ^ SwapFirst;
+ cmsUInt32Number nChan = T_CHANNELS(info -> OutputFormat);
+ cmsUInt32Number DoSwap = T_DOSWAP(info ->OutputFormat);
+ cmsUInt32Number Reverse = T_FLAVOR(info ->OutputFormat);
+ cmsUInt32Number Extra = T_EXTRA(info -> OutputFormat);
+ cmsUInt32Number SwapFirst = T_SWAPFIRST(info -> OutputFormat);
+ cmsUInt32Number Planar = T_PLANAR(info -> OutputFormat);
+ cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst;
cmsFloat64Number maximum = IsInkSpace(info ->OutputFormat) ? 655.35 : 65535.0;
cmsFloat64Number v = 0;
cmsFloat64Number* swap1 = (cmsFloat64Number*) output;
- int i, start = 0;
+ cmsUInt32Number i, start = 0;
+
+ Stride /= PixelSize(info->OutputFormat);
if (ExtraFirst)
start = Extra;
for (i=0; i < nChan; i++) {
- int index = DoSwap ? (nChan - i - 1) : i;
+ cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i;
v = (cmsFloat64Number) wOut[index] / maximum;
@@ -2459,24 +2518,26 @@ cmsUInt8Number* PackFloatFrom16(register _cmsTRANSFORM* info,
register cmsUInt8Number* output,
register cmsUInt32Number Stride)
{
- int nChan = T_CHANNELS(info->OutputFormat);
- int DoSwap = T_DOSWAP(info->OutputFormat);
- int Reverse = T_FLAVOR(info->OutputFormat);
- int Extra = T_EXTRA(info->OutputFormat);
- int SwapFirst = T_SWAPFIRST(info->OutputFormat);
- int Planar = T_PLANAR(info->OutputFormat);
- int ExtraFirst = DoSwap ^ SwapFirst;
+ cmsUInt32Number nChan = T_CHANNELS(info->OutputFormat);
+ cmsUInt32Number DoSwap = T_DOSWAP(info->OutputFormat);
+ cmsUInt32Number Reverse = T_FLAVOR(info->OutputFormat);
+ cmsUInt32Number Extra = T_EXTRA(info->OutputFormat);
+ cmsUInt32Number SwapFirst = T_SWAPFIRST(info->OutputFormat);
+ cmsUInt32Number Planar = T_PLANAR(info->OutputFormat);
+ cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst;
cmsFloat64Number maximum = IsInkSpace(info->OutputFormat) ? 655.35 : 65535.0;
cmsFloat64Number v = 0;
cmsFloat32Number* swap1 = (cmsFloat32Number*)output;
- int i, start = 0;
+ cmsUInt32Number i, start = 0;
+
+ Stride /= PixelSize(info->OutputFormat);
if (ExtraFirst)
start = Extra;
for (i = 0; i < nChan; i++) {
- int index = DoSwap ? (nChan - i - 1) : i;
+ cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i;
v = (cmsFloat64Number)wOut[index] / maximum;
@@ -2512,24 +2573,26 @@ cmsUInt8Number* PackFloatsFromFloat(_cmsTRANSFORM* info,
cmsUInt8Number* output,
cmsUInt32Number Stride)
{
- int nChan = T_CHANNELS(info->OutputFormat);
- int DoSwap = T_DOSWAP(info->OutputFormat);
- int Reverse = T_FLAVOR(info->OutputFormat);
- int Extra = T_EXTRA(info->OutputFormat);
- int SwapFirst = T_SWAPFIRST(info->OutputFormat);
- int Planar = T_PLANAR(info->OutputFormat);
- int ExtraFirst = DoSwap ^ SwapFirst;
+ cmsUInt32Number nChan = T_CHANNELS(info->OutputFormat);
+ cmsUInt32Number DoSwap = T_DOSWAP(info->OutputFormat);
+ cmsUInt32Number Reverse = T_FLAVOR(info->OutputFormat);
+ cmsUInt32Number Extra = T_EXTRA(info->OutputFormat);
+ cmsUInt32Number SwapFirst = T_SWAPFIRST(info->OutputFormat);
+ cmsUInt32Number Planar = T_PLANAR(info->OutputFormat);
+ cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst;
cmsFloat64Number maximum = IsInkSpace(info->OutputFormat) ? 100.0 : 1.0;
cmsFloat32Number* swap1 = (cmsFloat32Number*)output;
cmsFloat64Number v = 0;
- int i, start = 0;
+ cmsUInt32Number i, start = 0;
+
+ Stride /= PixelSize(info->OutputFormat);
if (ExtraFirst)
start = Extra;
for (i = 0; i < nChan; i++) {
- int index = DoSwap ? (nChan - i - 1) : i;
+ cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i;
v = wOut[index] * maximum;
@@ -2561,24 +2624,26 @@ cmsUInt8Number* PackDoublesFromFloat(_cmsTRANSFORM* info,
cmsUInt8Number* output,
cmsUInt32Number Stride)
{
- int nChan = T_CHANNELS(info->OutputFormat);
- int DoSwap = T_DOSWAP(info->OutputFormat);
- int Reverse = T_FLAVOR(info->OutputFormat);
- int Extra = T_EXTRA(info->OutputFormat);
- int SwapFirst = T_SWAPFIRST(info->OutputFormat);
- int Planar = T_PLANAR(info->OutputFormat);
- int ExtraFirst = DoSwap ^ SwapFirst;
+ cmsUInt32Number nChan = T_CHANNELS(info->OutputFormat);
+ cmsUInt32Number DoSwap = T_DOSWAP(info->OutputFormat);
+ cmsUInt32Number Reverse = T_FLAVOR(info->OutputFormat);
+ cmsUInt32Number Extra = T_EXTRA(info->OutputFormat);
+ cmsUInt32Number SwapFirst = T_SWAPFIRST(info->OutputFormat);
+ cmsUInt32Number Planar = T_PLANAR(info->OutputFormat);
+ cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst;
cmsFloat64Number maximum = IsInkSpace(info->OutputFormat) ? 100.0 : 1.0;
cmsFloat64Number v = 0;
cmsFloat64Number* swap1 = (cmsFloat64Number*)output;
- int i, start = 0;
+ cmsUInt32Number i, start = 0;
+
+ Stride /= PixelSize(info->OutputFormat);
if (ExtraFirst)
start = Extra;
for (i = 0; i < nChan; i++) {
- int index = DoSwap ? (nChan - i - 1) : i;
+ cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i;
v = wOut[index] * maximum;
@@ -2619,6 +2684,8 @@ cmsUInt8Number* PackLabFloatFromFloat(_cmsTRANSFORM* Info,
if (T_PLANAR(Info -> OutputFormat)) {
+ Stride /= PixelSize(Info->OutputFormat);
+
Out[0] = (cmsFloat32Number) (wOut[0] * 100.0);
Out[Stride] = (cmsFloat32Number) (wOut[1] * 255.0 - 128.0);
Out[Stride*2] = (cmsFloat32Number) (wOut[2] * 255.0 - 128.0);
@@ -2647,6 +2714,8 @@ cmsUInt8Number* PackLabDoubleFromFloat(_cmsTRANSFORM* Info,
if (T_PLANAR(Info -> OutputFormat)) {
+ Stride /= PixelSize(Info->OutputFormat);
+
Out[0] = (cmsFloat64Number) (wOut[0] * 100.0);
Out[Stride] = (cmsFloat64Number) (wOut[1] * 255.0 - 128.0);
Out[Stride*2] = (cmsFloat64Number) (wOut[2] * 255.0 - 128.0);
@@ -2676,6 +2745,8 @@ cmsUInt8Number* PackXYZFloatFromFloat(_cmsTRANSFORM* Info,
if (T_PLANAR(Info -> OutputFormat)) {
+ Stride /= PixelSize(Info->OutputFormat);
+
Out[0] = (cmsFloat32Number) (wOut[0] * MAX_ENCODEABLE_XYZ);
Out[Stride] = (cmsFloat32Number) (wOut[1] * MAX_ENCODEABLE_XYZ);
Out[Stride*2] = (cmsFloat32Number) (wOut[2] * MAX_ENCODEABLE_XYZ);
@@ -2704,6 +2775,8 @@ cmsUInt8Number* PackXYZDoubleFromFloat(_cmsTRANSFORM* Info,
if (T_PLANAR(Info -> OutputFormat)) {
+ Stride /= PixelSize(Info->OutputFormat);
+
Out[0] = (cmsFloat64Number) (wOut[0] * MAX_ENCODEABLE_XYZ);
Out[Stride] = (cmsFloat64Number) (wOut[1] * MAX_ENCODEABLE_XYZ);
Out[Stride*2] = (cmsFloat64Number) (wOut[2] * MAX_ENCODEABLE_XYZ);
@@ -2735,24 +2808,26 @@ cmsUInt8Number* UnrollHalfTo16(register _cmsTRANSFORM* info,
register cmsUInt32Number Stride)
{
- int nChan = T_CHANNELS(info -> InputFormat);
- int DoSwap = T_DOSWAP(info ->InputFormat);
- int Reverse = T_FLAVOR(info ->InputFormat);
- int SwapFirst = T_SWAPFIRST(info -> InputFormat);
- int Extra = T_EXTRA(info -> InputFormat);
- int ExtraFirst = DoSwap ^ SwapFirst;
- int Planar = T_PLANAR(info -> InputFormat);
+ cmsUInt32Number nChan = T_CHANNELS(info -> InputFormat);
+ cmsUInt32Number DoSwap = T_DOSWAP(info ->InputFormat);
+ cmsUInt32Number Reverse = T_FLAVOR(info ->InputFormat);
+ cmsUInt32Number SwapFirst = T_SWAPFIRST(info -> InputFormat);
+ cmsUInt32Number Extra = T_EXTRA(info -> InputFormat);
+ cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst;
+ cmsUInt32Number Planar = T_PLANAR(info -> InputFormat);
cmsFloat32Number v;
- int i, start = 0;
+ cmsUInt32Number i, start = 0;
cmsFloat32Number maximum = IsInkSpace(info ->InputFormat) ? 655.35F : 65535.0F;
+ Stride /= PixelSize(info->OutputFormat);
+
if (ExtraFirst)
start = Extra;
for (i=0; i < nChan; i++) {
- int index = DoSwap ? (nChan - i - 1) : i;
+ cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i;
if (Planar)
v = _cmsHalf2Float ( ((cmsUInt16Number*) accum)[(i + start) * Stride] );
@@ -2787,24 +2862,25 @@ cmsUInt8Number* UnrollHalfToFloat(_cmsTRANSFORM* info,
cmsUInt32Number Stride)
{
- int nChan = T_CHANNELS(info -> InputFormat);
- int DoSwap = T_DOSWAP(info ->InputFormat);
- int Reverse = T_FLAVOR(info ->InputFormat);
- int SwapFirst = T_SWAPFIRST(info -> InputFormat);
- int Extra = T_EXTRA(info -> InputFormat);
- int ExtraFirst = DoSwap ^ SwapFirst;
- int Planar = T_PLANAR(info -> InputFormat);
+ cmsUInt32Number nChan = T_CHANNELS(info -> InputFormat);
+ cmsUInt32Number DoSwap = T_DOSWAP(info ->InputFormat);
+ cmsUInt32Number Reverse = T_FLAVOR(info ->InputFormat);
+ cmsUInt32Number SwapFirst = T_SWAPFIRST(info -> InputFormat);
+ cmsUInt32Number Extra = T_EXTRA(info -> InputFormat);
+ cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst;
+ cmsUInt32Number Planar = T_PLANAR(info -> InputFormat);
cmsFloat32Number v;
- int i, start = 0;
+ cmsUInt32Number i, start = 0;
cmsFloat32Number maximum = IsInkSpace(info ->InputFormat) ? 100.0F : 1.0F;
+ Stride /= PixelSize(info->OutputFormat);
if (ExtraFirst)
start = Extra;
for (i=0; i < nChan; i++) {
- int index = DoSwap ? (nChan - i - 1) : i;
+ cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i;
if (Planar)
v = _cmsHalf2Float ( ((cmsUInt16Number*) accum)[(i + start) * Stride] );
@@ -2837,24 +2913,26 @@ cmsUInt8Number* PackHalfFrom16(register _cmsTRANSFORM* info,
register cmsUInt8Number* output,
register cmsUInt32Number Stride)
{
- int nChan = T_CHANNELS(info->OutputFormat);
- int DoSwap = T_DOSWAP(info->OutputFormat);
- int Reverse = T_FLAVOR(info->OutputFormat);
- int Extra = T_EXTRA(info->OutputFormat);
- int SwapFirst = T_SWAPFIRST(info->OutputFormat);
- int Planar = T_PLANAR(info->OutputFormat);
- int ExtraFirst = DoSwap ^ SwapFirst;
+ cmsUInt32Number nChan = T_CHANNELS(info->OutputFormat);
+ cmsUInt32Number DoSwap = T_DOSWAP(info->OutputFormat);
+ cmsUInt32Number Reverse = T_FLAVOR(info->OutputFormat);
+ cmsUInt32Number Extra = T_EXTRA(info->OutputFormat);
+ cmsUInt32Number SwapFirst = T_SWAPFIRST(info->OutputFormat);
+ cmsUInt32Number Planar = T_PLANAR(info->OutputFormat);
+ cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst;
cmsFloat32Number maximum = IsInkSpace(info->OutputFormat) ? 655.35F : 65535.0F;
cmsFloat32Number v = 0;
cmsUInt16Number* swap1 = (cmsUInt16Number*)output;
- int i, start = 0;
+ cmsUInt32Number i, start = 0;
+
+ Stride /= PixelSize(info->OutputFormat);
if (ExtraFirst)
start = Extra;
for (i = 0; i < nChan; i++) {
- int index = DoSwap ? (nChan - i - 1) : i;
+ cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i;
v = (cmsFloat32Number)wOut[index] / maximum;
@@ -2888,24 +2966,26 @@ cmsUInt8Number* PackHalfFromFloat(_cmsTRANSFORM* info,
cmsUInt8Number* output,
cmsUInt32Number Stride)
{
- int nChan = T_CHANNELS(info->OutputFormat);
- int DoSwap = T_DOSWAP(info->OutputFormat);
- int Reverse = T_FLAVOR(info->OutputFormat);
- int Extra = T_EXTRA(info->OutputFormat);
- int SwapFirst = T_SWAPFIRST(info->OutputFormat);
- int Planar = T_PLANAR(info->OutputFormat);
- int ExtraFirst = DoSwap ^ SwapFirst;
+ cmsUInt32Number nChan = T_CHANNELS(info->OutputFormat);
+ cmsUInt32Number DoSwap = T_DOSWAP(info->OutputFormat);
+ cmsUInt32Number Reverse = T_FLAVOR(info->OutputFormat);
+ cmsUInt32Number Extra = T_EXTRA(info->OutputFormat);
+ cmsUInt32Number SwapFirst = T_SWAPFIRST(info->OutputFormat);
+ cmsUInt32Number Planar = T_PLANAR(info->OutputFormat);
+ cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst;
cmsFloat32Number maximum = IsInkSpace(info->OutputFormat) ? 100.0F : 1.0F;
cmsUInt16Number* swap1 = (cmsUInt16Number*)output;
cmsFloat32Number v = 0;
- int i, start = 0;
+ cmsUInt32Number i, start = 0;
+
+ Stride /= PixelSize(info->OutputFormat);
if (ExtraFirst)
start = Extra;
for (i = 0; i < nChan; i++) {
- int index = DoSwap ? (nChan - i - 1) : i;
+ cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i;
v = wOut[index] * maximum;
@@ -2936,7 +3016,7 @@ cmsUInt8Number* PackHalfFromFloat(_cmsTRANSFORM* info,
// ----------------------------------------------------------------------------------------------------------------
-static cmsFormatters16 InputFormatters16[] = {
+static const cmsFormatters16 InputFormatters16[] = {
// Type Mask Function
// ---------------------------- ------------------------------------ ----------------------------
@@ -3007,7 +3087,7 @@ static cmsFormatters16 InputFormatters16[] = {
-static cmsFormattersFloat InputFormattersFloat[] = {
+static const cmsFormattersFloat InputFormattersFloat[] = {
// Type Mask Function
// ---------------------------- ------------------------------------ ----------------------------
@@ -3040,7 +3120,7 @@ cmsFormatter _cmsGetStockInputFormatter(cmsUInt32Number dwInput, cmsUInt32Number
case CMS_PACK_FLAGS_16BITS: {
for (i=0; i < sizeof(InputFormatters16) / sizeof(cmsFormatters16); i++) {
- cmsFormatters16* f = InputFormatters16 + i;
+ const cmsFormatters16* f = InputFormatters16 + i;
if ((dwInput & ~f ->Mask) == f ->Type) {
fr.Fmt16 = f ->Frm;
@@ -3052,7 +3132,7 @@ cmsFormatter _cmsGetStockInputFormatter(cmsUInt32Number dwInput, cmsUInt32Number
case CMS_PACK_FLAGS_FLOAT: {
for (i=0; i < sizeof(InputFormattersFloat) / sizeof(cmsFormattersFloat); i++) {
- cmsFormattersFloat* f = InputFormattersFloat + i;
+ const cmsFormattersFloat* f = InputFormattersFloat + i;
if ((dwInput & ~f ->Mask) == f ->Type) {
fr.FmtFloat = f ->Frm;
@@ -3070,7 +3150,7 @@ cmsFormatter _cmsGetStockInputFormatter(cmsUInt32Number dwInput, cmsUInt32Number
return fr;
}
-static cmsFormatters16 OutputFormatters16[] = {
+static const cmsFormatters16 OutputFormatters16[] = {
// Type Mask Function
// ---------------------------- ------------------------------------ ----------------------------
@@ -3158,7 +3238,7 @@ static cmsFormatters16 OutputFormatters16[] = {
};
-static cmsFormattersFloat OutputFormattersFloat[] = {
+static const cmsFormattersFloat OutputFormattersFloat[] = {
// Type Mask Function
// ---------------------------- --------------------------------------------------- ----------------------------
{ TYPE_Lab_FLT, ANYPLANAR|ANYEXTRA, PackLabFloatFromFloat},
@@ -3176,8 +3256,6 @@ static cmsFormattersFloat OutputFormattersFloat[] = {
ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackHalfFromFloat },
#endif
-
-
};
@@ -3197,7 +3275,7 @@ cmsFormatter _cmsGetStockOutputFormatter(cmsUInt32Number dwInput, cmsUInt32Numbe
case CMS_PACK_FLAGS_16BITS: {
for (i=0; i < sizeof(OutputFormatters16) / sizeof(cmsFormatters16); i++) {
- cmsFormatters16* f = OutputFormatters16 + i;
+ const cmsFormatters16* f = OutputFormatters16 + i;
if ((dwInput & ~f ->Mask) == f ->Type) {
fr.Fmt16 = f ->Frm;
@@ -3210,7 +3288,7 @@ cmsFormatter _cmsGetStockOutputFormatter(cmsUInt32Number dwInput, cmsUInt32Numbe
case CMS_PACK_FLAGS_FLOAT: {
for (i=0; i < sizeof(OutputFormattersFloat) / sizeof(cmsFormattersFloat); i++) {
- cmsFormattersFloat* f = OutputFormattersFloat + i;
+ const cmsFormattersFloat* f = OutputFormattersFloat + i;
if ((dwInput & ~f ->Mask) == f ->Type) {
fr.FmtFloat = f ->Frm;
@@ -3319,10 +3397,10 @@ cmsBool _cmsRegisterFormattersPlugin(cmsContext ContextID, cmsPluginBase* Data)
return TRUE;
}
-cmsFormatter _cmsGetFormatter(cmsContext ContextID,
- cmsUInt32Number Type, // Specific type, i.e. TYPE_RGB_8
- cmsFormatterDirection Dir,
- cmsUInt32Number dwFlags)
+cmsFormatter CMSEXPORT _cmsGetFormatter(cmsContext ContextID,
+ cmsUInt32Number Type, // Specific type, i.e. TYPE_RGB_8
+ cmsFormatterDirection Dir,
+ cmsUInt32Number dwFlags)
{
_cmsFormattersPluginChunkType* ctx = ( _cmsFormattersPluginChunkType*) _cmsContextGetClientChunk(ContextID, FormattersPlugin);
cmsFormattersFactoryList* f;
@@ -3350,7 +3428,7 @@ cmsBool _cmsFormatterIsFloat(cmsUInt32Number Type)
// Return whatever given formatter refers to 8 bits
cmsBool _cmsFormatterIs8bit(cmsUInt32Number Type)
{
- int Bytes = T_BYTES(Type);
+ cmsUInt32Number Bytes = T_BYTES(Type);
return (Bytes == 1);
}
@@ -3360,9 +3438,9 @@ cmsUInt32Number CMSEXPORT cmsFormatterForColorspaceOfProfile(cmsHPROFILE hProfil
{
cmsColorSpaceSignature ColorSpace = cmsGetColorSpace(hProfile);
- cmsUInt32Number ColorSpaceBits = _cmsLCMScolorSpace(ColorSpace);
+ cmsUInt32Number ColorSpaceBits = (cmsUInt32Number) _cmsLCMScolorSpace(ColorSpace);
cmsUInt32Number nOutputChans = cmsChannelsOf(ColorSpace);
- cmsUInt32Number Float = lIsFloat ? 1 : 0;
+ cmsUInt32Number Float = lIsFloat ? 1U : 0;
// Create a fake formatter for result
return FLOAT_SH(Float) | COLORSPACE_SH(ColorSpaceBits) | BYTES_SH(nBytes) | CHANNELS_SH(nOutputChans);
@@ -3372,10 +3450,11 @@ cmsUInt32Number CMSEXPORT cmsFormatterForColorspaceOfProfile(cmsHPROFILE hProfil
cmsUInt32Number CMSEXPORT cmsFormatterForPCSOfProfile(cmsHPROFILE hProfile, cmsUInt32Number nBytes, cmsBool lIsFloat)
{
- cmsColorSpaceSignature ColorSpace = cmsGetPCS(hProfile);
- int ColorSpaceBits = _cmsLCMScolorSpace(ColorSpace);
- cmsUInt32Number nOutputChans = cmsChannelsOf(ColorSpace);
- cmsUInt32Number Float = lIsFloat ? 1 : 0;
+ cmsColorSpaceSignature ColorSpace = cmsGetPCS(hProfile);
+
+ cmsUInt32Number ColorSpaceBits = (cmsUInt32Number) _cmsLCMScolorSpace(ColorSpace);
+ cmsUInt32Number nOutputChans = cmsChannelsOf(ColorSpace);
+ cmsUInt32Number Float = lIsFloat ? 1U : 0;
// Create a fake formatter for result
return FLOAT_SH(Float) | COLORSPACE_SH(ColorSpaceBits) | BYTES_SH(nBytes) | CHANNELS_SH(nOutputChans);
diff --git a/src/java.desktop/share/native/liblcms/cmspcs.c b/src/java.desktop/share/native/liblcms/cmspcs.c
index f2ebf53bf96..6c6773620c5 100644
--- a/src/java.desktop/share/native/liblcms/cmspcs.c
+++ b/src/java.desktop/share/native/liblcms/cmspcs.c
@@ -30,7 +30,7 @@
//---------------------------------------------------------------------------------
//
// Little Color Management System
-// Copyright (c) 1998-2016 Marti Maria Saguer
+// Copyright (c) 1998-2017 Marti Maria Saguer
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
@@ -685,9 +685,9 @@ cmsFloat64Number CMSEXPORT cmsCIE2000DeltaE(const cmsCIELab* Lab1, const cmsCIEL
// This function returns a number of gridpoints to be used as LUT table. It assumes same number
// of gripdpoints in all dimensions. Flags may override the choice.
-int _cmsReasonableGridpointsByColorspace(cmsColorSpaceSignature Colorspace, cmsUInt32Number dwFlags)
+cmsUInt32Number _cmsReasonableGridpointsByColorspace(cmsColorSpaceSignature Colorspace, cmsUInt32Number dwFlags)
{
- int nChannels;
+ cmsUInt32Number nChannels;
// Already specified?
if (dwFlags & 0x00FF0000) {
@@ -831,7 +831,7 @@ cmsColorSpaceSignature CMSEXPORT _cmsICCcolorSpace(int OurNotation)
case PT_MCH14: return cmsSigMCHEData;
case PT_MCH15: return cmsSigMCHFData;
- default: return (cmsColorSpaceSignature) (-1);
+ default: return (cmsColorSpaceSignature) 0;
}
}
@@ -898,7 +898,7 @@ int CMSEXPORT _cmsLCMScolorSpace(cmsColorSpaceSignature ProfileSpace)
case cmsSigMCHFData:
case cmsSig15colorData:return PT_MCH15;
- default: return (cmsColorSpaceSignature) (-1);
+ default: return (cmsColorSpaceSignature) 0;
}
}
diff --git a/src/java.desktop/share/native/liblcms/cmsplugin.c b/src/java.desktop/share/native/liblcms/cmsplugin.c
index 683c8305980..e7100c8ea60 100644
--- a/src/java.desktop/share/native/liblcms/cmsplugin.c
+++ b/src/java.desktop/share/native/liblcms/cmsplugin.c
@@ -30,7 +30,7 @@
//---------------------------------------------------------------------------------
//
// Little Color Management System
-// Copyright (c) 1998-2016 Marti Maria Saguer
+// Copyright (c) 1998-2017 Marti Maria Saguer
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
@@ -201,14 +201,28 @@ cmsBool CMSEXPORT _cmsReadFloat32Number(cmsIOHANDLER* io, cmsFloat32Number* n)
_cmsAssert(io != NULL);
- if (io -> Read(io, &tmp, sizeof(cmsUInt32Number), 1) != 1)
- return FALSE;
+ if (io->Read(io, &tmp, sizeof(cmsUInt32Number), 1) != 1)
+ return FALSE;
if (n != NULL) {
tmp = _cmsAdjustEndianess32(tmp);
- *n = *(cmsFloat32Number*) (void*) &tmp;
+ *n = *(cmsFloat32Number*)(void*)&tmp;
+
+ // Safeguard which covers against absurd values
+ if (*n > 1E+20 || *n < -1E+20) return FALSE;
+
+ #if defined(_MSC_VER) && _MSC_VER < 1800
+ return TRUE;
+ #elif defined (__BORLANDC__)
+ return TRUE;
+ #else
+
+ // fpclassify() required by C99 (only provided by MSVC >= 1800, VS2013 onwards)
+ return ((fpclassify(*n) == FP_ZERO) || (fpclassify(*n) == FP_NORMAL));
+ #endif
}
+
return TRUE;
}
@@ -222,7 +236,11 @@ cmsBool CMSEXPORT _cmsReadUInt64Number(cmsIOHANDLER* io, cmsUInt64Number* n)
if (io -> Read(io, &tmp, sizeof(cmsUInt64Number), 1) != 1)
return FALSE;
- if (n != NULL) _cmsAdjustEndianess64(n, &tmp);
+ if (n != NULL) {
+
+ _cmsAdjustEndianess64(n, &tmp);
+ }
+
return TRUE;
}
@@ -237,7 +255,7 @@ cmsBool CMSEXPORT _cmsRead15Fixed16Number(cmsIOHANDLER* io, cmsFloat64Number* n
return FALSE;
if (n != NULL) {
- *n = _cms15Fixed16toDouble(_cmsAdjustEndianess32(tmp));
+ *n = _cms15Fixed16toDouble((cmsS15Fixed16Number) _cmsAdjustEndianess32(tmp));
}
return TRUE;
@@ -254,9 +272,9 @@ cmsBool CMSEXPORT _cmsReadXYZNumber(cmsIOHANDLER* io, cmsCIEXYZ* XYZ)
if (XYZ != NULL) {
- XYZ->X = _cms15Fixed16toDouble(_cmsAdjustEndianess32(xyz.X));
- XYZ->Y = _cms15Fixed16toDouble(_cmsAdjustEndianess32(xyz.Y));
- XYZ->Z = _cms15Fixed16toDouble(_cmsAdjustEndianess32(xyz.Z));
+ XYZ->X = _cms15Fixed16toDouble((cmsS15Fixed16Number) _cmsAdjustEndianess32((cmsUInt32Number) xyz.X));
+ XYZ->Y = _cms15Fixed16toDouble((cmsS15Fixed16Number) _cmsAdjustEndianess32((cmsUInt32Number) xyz.Y));
+ XYZ->Z = _cms15Fixed16toDouble((cmsS15Fixed16Number) _cmsAdjustEndianess32((cmsUInt32Number) xyz.Z));
}
return TRUE;
}
@@ -345,7 +363,7 @@ cmsBool CMSEXPORT _cmsWrite15Fixed16Number(cmsIOHANDLER* io, cmsFloat64Number n
_cmsAssert(io != NULL);
- tmp = _cmsAdjustEndianess32(_cmsDoubleTo15Fixed16(n));
+ tmp = _cmsAdjustEndianess32((cmsUInt32Number) _cmsDoubleTo15Fixed16(n));
if (io -> Write(io, sizeof(cmsUInt32Number), &tmp) != 1)
return FALSE;
@@ -359,9 +377,9 @@ cmsBool CMSEXPORT _cmsWriteXYZNumber(cmsIOHANDLER* io, const cmsCIEXYZ* XYZ)
_cmsAssert(io != NULL);
_cmsAssert(XYZ != NULL);
- xyz.X = _cmsAdjustEndianess32(_cmsDoubleTo15Fixed16(XYZ->X));
- xyz.Y = _cmsAdjustEndianess32(_cmsDoubleTo15Fixed16(XYZ->Y));
- xyz.Z = _cmsAdjustEndianess32(_cmsDoubleTo15Fixed16(XYZ->Z));
+ xyz.X = (cmsS15Fixed16Number) _cmsAdjustEndianess32((cmsUInt32Number) _cmsDoubleTo15Fixed16(XYZ->X));
+ xyz.Y = (cmsS15Fixed16Number) _cmsAdjustEndianess32((cmsUInt32Number) _cmsDoubleTo15Fixed16(XYZ->Y));
+ xyz.Z = (cmsS15Fixed16Number) _cmsAdjustEndianess32((cmsUInt32Number) _cmsDoubleTo15Fixed16(XYZ->Z));
return io -> Write(io, sizeof(cmsEncodedXYZNumber), &xyz);
}
@@ -519,7 +537,7 @@ cmsBool CMSEXPORT _cmsIOPrintf(cmsIOHANDLER* io, const char* frm, ...)
return FALSE; // Truncated, which is a fatal error for us
}
- rc = io ->Write(io, len, Buffer);
+ rc = io ->Write(io, (cmsUInt32Number) len, Buffer);
va_end(args);
@@ -779,6 +797,30 @@ cmsContext CMSEXPORT cmsCreateContext(void* Plugin, void* UserData)
struct _cmsContext_struct* ctx;
struct _cmsContext_struct fakeContext;
+ // See the comments regarding locking in lcms2_internal.h
+ // for an explanation of why we need the following code.
+#ifdef CMS_IS_WINDOWS_
+#ifndef CMS_RELY_ON_WINDOWS_STATIC_MUTEX_INIT
+ {
+ static HANDLE _cmsWindowsInitMutex = NULL;
+ static volatile HANDLE* mutex = &_cmsWindowsInitMutex;
+
+ if (*mutex == NULL)
+ {
+ HANDLE p = CreateMutex(NULL, FALSE, NULL);
+ if (p && InterlockedCompareExchangePointer((void **)mutex, (void*)p, NULL) != NULL)
+ CloseHandle(p);
+ }
+ if (*mutex == NULL || WaitForSingleObject(*mutex, INFINITE) == WAIT_FAILED)
+ return NULL;
+ if (((void **)&_cmsContextPoolHeadMutex)[0] == NULL)
+ InitializeCriticalSection(&_cmsContextPoolHeadMutex);
+ if (*mutex == NULL || !ReleaseMutex(*mutex))
+ return NULL;
+ }
+#endif
+#endif
+
_cmsInstallAllocFunctions(_cmsFindMemoryPlugin(Plugin), &fakeContext.DefaultMemoryManager);
fakeContext.chunks[UserPtr] = UserData;
@@ -805,7 +847,7 @@ cmsContext CMSEXPORT cmsCreateContext(void* Plugin, void* UserData)
ctx ->chunks[MemPlugin] = &ctx->DefaultMemoryManager;
// Now we can allocate the pool by using default memory manager
- ctx ->MemPool = _cmsCreateSubAlloc(ctx, 22 * sizeof(void*)); // default size about 32 pointers
+ ctx ->MemPool = _cmsCreateSubAlloc(ctx, 22 * sizeof(void*)); // default size about 22 pointers
if (ctx ->MemPool == NULL) {
cmsDeleteContext(ctx);
diff --git a/src/java.desktop/share/native/liblcms/cmsps2.c b/src/java.desktop/share/native/liblcms/cmsps2.c
index 03d476bc367..a3c7b49dbff 100644
--- a/src/java.desktop/share/native/liblcms/cmsps2.c
+++ b/src/java.desktop/share/native/liblcms/cmsps2.c
@@ -30,7 +30,7 @@
//---------------------------------------------------------------------------------
//
// Little Color Management System
-// Copyright (c) 1998-2016 Marti Maria Saguer
+// Copyright (c) 1998-2017 Marti Maria Saguer
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
@@ -429,7 +429,7 @@ void EmitRangeCheck(cmsIOHANDLER* m)
// Does write the intent
static
-void EmitIntent(cmsIOHANDLER* m, int RenderingIntent)
+void EmitIntent(cmsIOHANDLER* m, cmsUInt32Number RenderingIntent)
{
const char *intent;
@@ -563,7 +563,7 @@ void Emit1Gamma(cmsIOHANDLER* m, cmsToneCurve* Table)
// Compare gamma table
static
-cmsBool GammaTableEquals(cmsUInt16Number* g1, cmsUInt16Number* g2, int nEntries)
+cmsBool GammaTableEquals(cmsUInt16Number* g1, cmsUInt16Number* g2, cmsUInt32Number nEntries)
{
return memcmp(g1, g2, nEntries* sizeof(cmsUInt16Number)) == 0;
}
@@ -572,9 +572,9 @@ cmsBool GammaTableEquals(cmsUInt16Number* g1, cmsUInt16Number* g2, int nEntries)
// Does write a set of gamma curves
static
-void EmitNGamma(cmsIOHANDLER* m, int n, cmsToneCurve* g[])
+void EmitNGamma(cmsIOHANDLER* m, cmsUInt32Number n, cmsToneCurve* g[])
{
- int i;
+ cmsUInt32Number i;
for( i=0; i < n; i++ )
{
@@ -797,7 +797,7 @@ int EmitCIEBasedABC(cmsIOHANDLER* m, cmsFloat64Number* Matrix, cmsToneCurve** Cu
static
-int EmitCIEBasedDEF(cmsIOHANDLER* m, cmsPipeline* Pipeline, int Intent, cmsCIEXYZ* BlackPoint)
+int EmitCIEBasedDEF(cmsIOHANDLER* m, cmsPipeline* Pipeline, cmsUInt32Number Intent, cmsCIEXYZ* BlackPoint)
{
const char* PreMaj;
const char* PostMaj;
@@ -857,14 +857,14 @@ int EmitCIEBasedDEF(cmsIOHANDLER* m, cmsPipeline* Pipeline, int Intent, cmsCIEXY
// Generates a curve from a gray profile
static
- cmsToneCurve* ExtractGray2Y(cmsContext ContextID, cmsHPROFILE hProfile, int Intent)
+cmsToneCurve* ExtractGray2Y(cmsContext ContextID, cmsHPROFILE hProfile, cmsUInt32Number Intent)
{
cmsToneCurve* Out = cmsBuildTabulatedToneCurve16(ContextID, 256, NULL);
cmsHPROFILE hXYZ = cmsCreateXYZProfile();
cmsHTRANSFORM xform = cmsCreateTransformTHR(ContextID, hProfile, TYPE_GRAY_8, hXYZ, TYPE_XYZ_DBL, Intent, cmsFLAGS_NOOPTIMIZE);
int i;
- if (Out != NULL) {
+ if (Out != NULL && xform != NULL) {
for (i=0; i < 256; i++) {
cmsUInt8Number Gray = (cmsUInt8Number) i;
@@ -876,8 +876,8 @@ static
}
}
- cmsDeleteTransform(xform);
- cmsCloseProfile(hXYZ);
+ if (xform) cmsDeleteTransform(xform);
+ if (hXYZ) cmsCloseProfile(hXYZ);
return Out;
}
@@ -887,7 +887,7 @@ static
// a more perceptually uniform space... I do choose Lab.
static
-int WriteInputLUT(cmsIOHANDLER* m, cmsHPROFILE hProfile, int Intent, cmsUInt32Number dwFlags)
+int WriteInputLUT(cmsIOHANDLER* m, cmsHPROFILE hProfile, cmsUInt32Number Intent, cmsUInt32Number dwFlags)
{
cmsHPROFILE hLab;
cmsHTRANSFORM xform;
@@ -972,7 +972,6 @@ cmsFloat64Number* GetPtrToMatrix(const cmsStage* mpe)
// Does create CSA based on matrix-shaper. Allowed types are gray and RGB based
-
static
int WriteInputMatrixShaper(cmsIOHANDLER* m, cmsHPROFILE hProfile, cmsStage* Matrix, cmsStage* Shaper)
{
@@ -998,17 +997,17 @@ int WriteInputMatrixShaper(cmsIOHANDLER* m, cmsHPROFILE hProfile, cmsStage* Matr
memmove(&Mat, GetPtrToMatrix(Matrix), sizeof(Mat));
- for (i=0; i < 3; i++)
- for (j=0; j < 3; j++)
+ for (i = 0; i < 3; i++)
+ for (j = 0; j < 3; j++)
Mat.v[i].n[j] *= MAX_ENCODEABLE_XYZ;
- rc = EmitCIEBasedABC(m, (cmsFloat64Number *) &Mat,
- _cmsStageGetPtrToCurveSet(Shaper),
- &BlackPointAdaptedToD50);
+ rc = EmitCIEBasedABC(m, (cmsFloat64Number *)&Mat,
+ _cmsStageGetPtrToCurveSet(Shaper),
+ &BlackPointAdaptedToD50);
}
- else {
+ else {
- cmsSignalError(m ->ContextID, cmsERROR_COLORSPACE_CHECK, "Profile is not suitable for CSA. Unsupported colorspace.");
+ cmsSignalError(m->ContextID, cmsERROR_COLORSPACE_CHECK, "Profile is not suitable for CSA. Unsupported colorspace.");
return 0;
}
@@ -1021,12 +1020,12 @@ int WriteInputMatrixShaper(cmsIOHANDLER* m, cmsHPROFILE hProfile, cmsStage* Matr
// This is a HP extension, and it works in Lab instead of XYZ
static
-int WriteNamedColorCSA(cmsIOHANDLER* m, cmsHPROFILE hNamedColor, int Intent)
+int WriteNamedColorCSA(cmsIOHANDLER* m, cmsHPROFILE hNamedColor, cmsUInt32Number Intent)
{
cmsHTRANSFORM xform;
cmsHPROFILE hLab;
- int i, nColors;
- char ColorName[32];
+ cmsUInt32Number i, nColors;
+ char ColorName[cmsMAX_PATH];
cmsNAMEDCOLORLIST* NamedColorList;
hLab = cmsCreateLab4ProfileTHR(m ->ContextID, NULL);
@@ -1304,20 +1303,20 @@ void EmitXYZ2Lab(cmsIOHANDLER* m)
// 8 bits.
static
-int WriteOutputLUT(cmsIOHANDLER* m, cmsHPROFILE hProfile, int Intent, cmsUInt32Number dwFlags)
+int WriteOutputLUT(cmsIOHANDLER* m, cmsHPROFILE hProfile, cmsUInt32Number Intent, cmsUInt32Number dwFlags)
{
cmsHPROFILE hLab;
cmsHTRANSFORM xform;
- int i, nChannels;
+ cmsUInt32Number i, nChannels;
cmsUInt32Number OutputFormat;
_cmsTRANSFORM* v;
cmsPipeline* DeviceLink;
cmsHPROFILE Profiles[3];
cmsCIEXYZ BlackPointAdaptedToD50;
- cmsBool lDoBPC = (dwFlags & cmsFLAGS_BLACKPOINTCOMPENSATION);
- cmsBool lFixWhite = !(dwFlags & cmsFLAGS_NOWHITEONWHITEFIXUP);
+ cmsBool lDoBPC = (cmsBool) (dwFlags & cmsFLAGS_BLACKPOINTCOMPENSATION);
+ cmsBool lFixWhite = (cmsBool) !(dwFlags & cmsFLAGS_NOWHITEONWHITEFIXUP);
cmsUInt32Number InFrm = TYPE_Lab_16;
- int RelativeEncodingIntent;
+ cmsUInt32Number RelativeEncodingIntent;
cmsColorSpaceSignature ColorSpace;
@@ -1413,10 +1412,10 @@ int WriteOutputLUT(cmsIOHANDLER* m, cmsHPROFILE hProfile, int Intent, cmsUInt32N
// Builds a ASCII string containing colorant list in 0..1.0 range
static
-void BuildColorantList(char *Colorant, int nColorant, cmsUInt16Number Out[])
+void BuildColorantList(char *Colorant, cmsUInt32Number nColorant, cmsUInt16Number Out[])
{
char Buff[32];
- int j;
+ cmsUInt32Number j;
Colorant[0] = 0;
if (nColorant > cmsMAXCHANNELS)
@@ -1438,12 +1437,12 @@ void BuildColorantList(char *Colorant, int nColorant, cmsUInt16Number Out[])
// This is a HP extension.
static
-int WriteNamedColorCRD(cmsIOHANDLER* m, cmsHPROFILE hNamedColor, int Intent, cmsUInt32Number dwFlags)
+int WriteNamedColorCRD(cmsIOHANDLER* m, cmsHPROFILE hNamedColor, cmsUInt32Number Intent, cmsUInt32Number dwFlags)
{
cmsHTRANSFORM xform;
- int i, nColors, nColorant;
+ cmsUInt32Number i, nColors, nColorant;
cmsUInt32Number OutputFormat;
- char ColorName[32];
+ char ColorName[cmsMAX_PATH];
char Colorant[128];
cmsNAMEDCOLORLIST* NamedColorList;
diff --git a/src/java.desktop/share/native/liblcms/cmssamp.c b/src/java.desktop/share/native/liblcms/cmssamp.c
index b22c427323e..1e38e4f3188 100644
--- a/src/java.desktop/share/native/liblcms/cmssamp.c
+++ b/src/java.desktop/share/native/liblcms/cmssamp.c
@@ -30,7 +30,7 @@
//---------------------------------------------------------------------------------
//
// Little Color Management System
-// Copyright (c) 1998-2016 Marti Maria Saguer
+// Copyright (c) 1998-2017 Marti Maria Saguer
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
diff --git a/src/java.desktop/share/native/liblcms/cmssm.c b/src/java.desktop/share/native/liblcms/cmssm.c
index 1923a02841a..38e08fc9a4f 100644
--- a/src/java.desktop/share/native/liblcms/cmssm.c
+++ b/src/java.desktop/share/native/liblcms/cmssm.c
@@ -30,7 +30,7 @@
//---------------------------------------------------------------------------------
//
// Little Color Management System
-// Copyright (c) 1998-2016 Marti Maria Saguer
+// Copyright (c) 1998-2017 Marti Maria Saguer
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
diff --git a/src/java.desktop/share/native/liblcms/cmstypes.c b/src/java.desktop/share/native/liblcms/cmstypes.c
index ebf81c83b39..d0d4d24829e 100644
--- a/src/java.desktop/share/native/liblcms/cmstypes.c
+++ b/src/java.desktop/share/native/liblcms/cmstypes.c
@@ -30,7 +30,7 @@
//---------------------------------------------------------------------------------
//
// Little Color Management System
-// Copyright (c) 1998-2016 Marti Maria Saguer
+// Copyright (c) 1998-2017 Marti Maria Saguer
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
@@ -89,6 +89,11 @@ typedef struct _cmsTagTypeLinkedList_st {
// Helper macro to define a MPE handler. Callbacks do have a fixed naming convention
#define TYPE_MPE_HANDLER(t, x) { (t), READ_FN(x), WRITE_FN(x), GenericMPEdup, GenericMPEfree, NULL, 0 }
+// Infinites
+#define MINUS_INF (-1E22F)
+#define PLUS_INF (+1E22F)
+
+
// Register a new type handler. This routine is shared between normal types and MPE. LinkedList points to the optional list head
static
cmsBool RegisterTypesPlugin(cmsContext id, cmsPluginBase* Data, _cmsMemoryClient pos)
@@ -202,6 +207,13 @@ cmsBool ReadPositionTable(struct _cms_typehandler_struct* self,
{
cmsUInt32Number i;
cmsUInt32Number *ElementOffsets = NULL, *ElementSizes = NULL;
+ cmsUInt32Number currentPosition;
+
+ currentPosition = io->Tell(io);
+
+ // Verify there is enough space left to read at least two cmsUInt32Number items for Count items.
+ if (((io->ReportedSize - currentPosition) / (2 * sizeof(cmsUInt32Number))) < Count)
+ return FALSE;
// Let's take the offsets to each element
ElementOffsets = (cmsUInt32Number *) _cmsCalloc(io ->ContextID, Count, sizeof(cmsUInt32Number));
@@ -424,8 +436,8 @@ void *Type_Chromaticity_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER*
static
cmsBool SaveOneChromaticity(cmsFloat64Number x, cmsFloat64Number y, cmsIOHANDLER* io)
{
- if (!_cmsWriteUInt32Number(io, _cmsDoubleTo15Fixed16(x))) return FALSE;
- if (!_cmsWriteUInt32Number(io, _cmsDoubleTo15Fixed16(y))) return FALSE;
+ if (!_cmsWriteUInt32Number(io, (cmsUInt32Number) _cmsDoubleTo15Fixed16(x))) return FALSE;
+ if (!_cmsWriteUInt32Number(io, (cmsUInt32Number) _cmsDoubleTo15Fixed16(y))) return FALSE;
return TRUE;
}
@@ -984,7 +996,7 @@ cmsBool Type_Text_Description_Write(struct _cms_typehandler_struct* self, cmsIO
cmsBool rc = FALSE;
char Filler[68];
- // Used below for writting zeroes
+ // Used below for writing zeroes
memset(Filler, 0, sizeof(Filler));
// Get the len of string
@@ -1146,7 +1158,10 @@ void *Type_Curve_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cm
NewGamma = cmsBuildTabulatedToneCurve16(self ->ContextID, Count, NULL);
if (!NewGamma) return NULL;
- if (!_cmsReadUInt16Array(io, Count, NewGamma -> Table16)) return NULL;
+ if (!_cmsReadUInt16Array(io, Count, NewGamma -> Table16)) {
+ cmsFreeToneCurve(NewGamma);
+ return NULL;
+ }
*nItems = 1;
return NewGamma;
@@ -1206,7 +1221,7 @@ void Type_Curve_Free(struct _cms_typehandler_struct* self, void* Ptr)
// ********************************************************************************
-// Decide which curve type to use on writting
+// Decide which curve type to use on writing
static
cmsTagTypeSignature DecideCurveType(cmsFloat64Number ICCVersion, const void *Data)
{
@@ -1599,7 +1614,7 @@ void Type_MLU_Free(struct _cms_typehandler_struct* self, void* Ptr)
// Type cmsSigLut8Type
// ********************************************************************************
-// Decide which LUT type to use on writting
+// Decide which LUT type to use on writing
static
cmsTagTypeSignature DecideLUTtypeA2B(cmsFloat64Number ICCVersion, const void *Data)
{
@@ -1648,10 +1663,10 @@ Byte Position Field Length (bytes) Content Encoded as...
// Read 8 bit tables as gamma functions
static
-cmsBool Read8bitTables(cmsContext ContextID, cmsIOHANDLER* io, cmsPipeline* lut, int nChannels)
+cmsBool Read8bitTables(cmsContext ContextID, cmsIOHANDLER* io, cmsPipeline* lut, cmsUInt32Number nChannels)
{
cmsUInt8Number* Temp = NULL;
- int i, j;
+ cmsUInt32Number i, j;
cmsToneCurve* Tables[cmsMAXCHANNELS];
if (nChannels > cmsMAXCHANNELS) return FALSE;
@@ -1784,8 +1799,8 @@ void *Type_LUT8_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cms
if (!_cmsReadUInt8Number(io, NULL)) goto Error;
// Do some checking
- if (InputChannels > cmsMAXCHANNELS) goto Error;
- if (OutputChannels > cmsMAXCHANNELS) goto Error;
+ if (InputChannels == 0 || InputChannels > cmsMAXCHANNELS) goto Error;
+ if (OutputChannels == 0 || OutputChannels > cmsMAXCHANNELS) goto Error;
// Allocates an empty Pipeline
NewLUT = cmsPipelineAlloc(self ->ContextID, InputChannels, OutputChannels);
@@ -1842,8 +1857,10 @@ void *Type_LUT8_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cms
_cmsFree(self ->ContextID, Temp);
Temp = NULL;
- if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, cmsStageAllocCLut16bit(self ->ContextID, CLUTpoints, InputChannels, OutputChannels, T)))
+ if (!cmsPipelineInsertStage(NewLUT, cmsAT_END, cmsStageAllocCLut16bit(self ->ContextID, CLUTpoints, InputChannels, OutputChannels, T))) {
+ _cmsFree(self ->ContextID, T);
goto Error;
+ }
_cmsFree(self ->ContextID, T);
}
@@ -1872,7 +1889,7 @@ cmsBool Type_LUT8_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io,
_cmsStageToneCurvesData* PreMPE = NULL, *PostMPE = NULL;
_cmsStageMatrixData* MatMPE = NULL;
_cmsStageCLutData* clut = NULL;
- int clutPoints;
+ cmsUInt32Number clutPoints;
// Disassemble the LUT into components.
mpe = NewLUT -> Elements;
@@ -1992,9 +2009,10 @@ void Type_LUT8_Free(struct _cms_typehandler_struct* self, void* Ptr)
// Read 16 bit tables as gamma functions
static
-cmsBool Read16bitTables(cmsContext ContextID, cmsIOHANDLER* io, cmsPipeline* lut, int nChannels, int nEntries)
+cmsBool Read16bitTables(cmsContext ContextID, cmsIOHANDLER* io, cmsPipeline* lut,
+ cmsUInt32Number nChannels, cmsUInt32Number nEntries)
{
- int i;
+ cmsUInt32Number i;
cmsToneCurve* Tables[cmsMAXCHANNELS];
// Maybe an empty table? (this is a lcms extension)
@@ -2036,10 +2054,10 @@ cmsBool Read16bitTables(cmsContext ContextID, cmsIOHANDLER* io, cmsPipeline* lu
static
cmsBool Write16bitTables(cmsContext ContextID, cmsIOHANDLER* io, _cmsStageToneCurvesData* Tables)
{
- int j;
+ cmsUInt32Number j;
cmsUInt32Number i;
cmsUInt16Number val;
- int nEntries;
+ cmsUInt32Number nEntries;
_cmsAssert(Tables != NULL);
@@ -2077,8 +2095,8 @@ void *Type_LUT16_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cm
if (!_cmsReadUInt8Number(io, NULL)) return NULL;
// Do some checking
- if (InputChannels > cmsMAXCHANNELS) goto Error;
- if (OutputChannels > cmsMAXCHANNELS) goto Error;
+ if (InputChannels == 0 || InputChannels > cmsMAXCHANNELS) goto Error;
+ if (OutputChannels == 0 || OutputChannels > cmsMAXCHANNELS) goto Error;
// Allocates an empty LUT
NewLUT = cmsPipelineAlloc(self ->ContextID, InputChannels, OutputChannels);
@@ -2160,7 +2178,7 @@ cmsBool Type_LUT16_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io
_cmsStageToneCurvesData* PreMPE = NULL, *PostMPE = NULL;
_cmsStageMatrixData* MatMPE = NULL;
_cmsStageCLutData* clut = NULL;
- int i, InputChannels, OutputChannels, clutPoints;
+ cmsUInt32Number i, InputChannels, OutputChannels, clutPoints;
// Disassemble the LUT into components.
mpe = NewLUT -> Elements;
@@ -2346,7 +2364,8 @@ cmsStage* ReadMatrix(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cms
// V4 stuff. Read CLUT part for LutAtoB and LutBtoA
static
-cmsStage* ReadCLUT(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number Offset, int InputChannels, int OutputChannels)
+cmsStage* ReadCLUT(struct _cms_typehandler_struct* self, cmsIOHANDLER* io,
+ cmsUInt32Number Offset, cmsUInt32Number InputChannels, cmsUInt32Number OutputChannels)
{
cmsUInt8Number gridPoints8[cmsMAXCHANNELS]; // Number of grid points in each dimension.
cmsUInt32Number GridPoints[cmsMAXCHANNELS], i;
@@ -2382,7 +2401,10 @@ cmsStage* ReadCLUT(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUI
for (i=0; i < Data ->nEntries; i++) {
- if (io ->Read(io, &v, sizeof(cmsUInt8Number), 1) != 1) return NULL;
+ if (io ->Read(io, &v, sizeof(cmsUInt8Number), 1) != 1) {
+ cmsStageFree(CLUT);
+ return NULL;
+ }
Data ->Tab.T[i] = FROM_8_TO_16(v);
}
@@ -2512,7 +2534,10 @@ void* Type_LUTA2B_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, c
if (!_cmsReadUInt32Number(io, &offsetC)) return NULL;
if (!_cmsReadUInt32Number(io, &offsetA)) return NULL;
- // Allocates an empty LUT
+ if (inputChan == 0 || inputChan >= cmsMAXCHANNELS) return NULL;
+ if (outputChan == 0 || outputChan >= cmsMAXCHANNELS) return NULL;
+
+ // Allocates an empty LUT
NewLUT = cmsPipelineAlloc(self ->ContextID, inputChan, outputChan);
if (NewLUT == NULL) return NULL;
@@ -2694,7 +2719,7 @@ static
cmsBool Type_LUTA2B_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
{
cmsPipeline* Lut = (cmsPipeline*) Ptr;
- int inputChan, outputChan;
+ cmsUInt32Number inputChan, outputChan;
cmsStage *A = NULL, *B = NULL, *M = NULL;
cmsStage * Matrix = NULL;
cmsStage * CLUT = NULL;
@@ -2742,7 +2767,7 @@ cmsBool Type_LUTA2B_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io
if (CLUT != NULL) {
offsetC = io ->Tell(io) - BaseOffset;
- if (!WriteCLUT(self, io, Lut ->SaveAs8Bits ? 1 : 2, CLUT)) return FALSE;
+ if (!WriteCLUT(self, io, (Lut ->SaveAs8Bits ? 1U : 2U), CLUT)) return FALSE;
}
if (M != NULL) {
@@ -2820,6 +2845,9 @@ void* Type_LUTB2A_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, c
if (!_cmsReadUInt8Number(io, &inputChan)) return NULL;
if (!_cmsReadUInt8Number(io, &outputChan)) return NULL;
+ if (inputChan == 0 || inputChan >= cmsMAXCHANNELS) return NULL;
+ if (outputChan == 0 || outputChan >= cmsMAXCHANNELS) return NULL;
+
// Padding
if (!_cmsReadUInt16Number(io, NULL)) return NULL;
@@ -2879,7 +2907,7 @@ static
cmsBool Type_LUTB2A_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
{
cmsPipeline* Lut = (cmsPipeline*) Ptr;
- int inputChan, outputChan;
+ cmsUInt32Number inputChan, outputChan;
cmsStage *A = NULL, *B = NULL, *M = NULL;
cmsStage *Matrix = NULL;
cmsStage *CLUT = NULL;
@@ -2921,7 +2949,7 @@ cmsBool Type_LUTB2A_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* i
if (CLUT != NULL) {
offsetC = io ->Tell(io) - BaseOffset;
- if (!WriteCLUT(self, io, Lut ->SaveAs8Bits ? 1 : 2, CLUT)) return FALSE;
+ if (!WriteCLUT(self, io, (Lut ->SaveAs8Bits ? 1U : 2U), CLUT)) return FALSE;
}
if (M != NULL) {
@@ -3011,7 +3039,7 @@ void *Type_ColorantTable_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER
for (i=0; i < Count; i++) {
if (io ->Read(io, Name, 32, 1) != 1) goto Error;
- Name[33] = 0;
+ Name[32] = 0;
if (!_cmsReadUInt16Array(io, 3, PCS)) goto Error;
@@ -3037,7 +3065,7 @@ static
cmsBool Type_ColorantTable_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
{
cmsNAMEDCOLORLIST* NamedColorList = (cmsNAMEDCOLORLIST*) Ptr;
- int i, nColors;
+ cmsUInt32Number i, nColors;
nColors = cmsNamedColorCount(NamedColorList);
@@ -3045,9 +3073,11 @@ cmsBool Type_ColorantTable_Write(struct _cms_typehandler_struct* self, cmsIOHAN
for (i=0; i < nColors; i++) {
- char root[33];
+ char root[cmsMAX_PATH];
cmsUInt16Number PCS[3];
+ memset(root, 0, sizeof(root));
+
if (!cmsNamedColorInfo(NamedColorList, i, root, NULL, NULL, PCS, NULL)) return 0;
root[32] = 0;
@@ -3107,8 +3137,8 @@ void *Type_NamedColor_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* i
cmsUInt32Number nDeviceCoords; // Num of device coordinates
char prefix[32]; // Prefix for each color name
char suffix[32]; // Suffix for each color name
- cmsNAMEDCOLORLIST* v;
- cmsUInt32Number i;
+ cmsNAMEDCOLORLIST* v;
+ cmsUInt32Number i;
*nItems = 0;
@@ -3129,7 +3159,7 @@ void *Type_NamedColor_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* i
if (nDeviceCoords > cmsMAXCHANNELS) {
cmsSignalError(self->ContextID, cmsERROR_RANGE, "Too many device coordinates '%d'", nDeviceCoords);
- return 0;
+ goto Error;
}
for (i=0; i < count; i++) {
@@ -3138,7 +3168,7 @@ void *Type_NamedColor_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* i
char Root[33];
memset(Colorant, 0, sizeof(Colorant));
- if (io -> Read(io, Root, 32, 1) != 1) return NULL;
+ if (io -> Read(io, Root, 32, 1) != 1) goto Error;
Root[32] = 0; // To prevent exploits
if (!_cmsReadUInt16Array(io, 3, PCS)) goto Error;
@@ -3165,7 +3195,7 @@ cmsBool Type_NamedColor_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER
cmsNAMEDCOLORLIST* NamedColorList = (cmsNAMEDCOLORLIST*) Ptr;
char prefix[33]; // Prefix for each color name
char suffix[33]; // Suffix for each color name
- int i, nColors;
+ cmsUInt32Number i, nColors;
nColors = cmsNamedColorCount(NamedColorList);
@@ -3185,7 +3215,7 @@ cmsBool Type_NamedColor_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER
cmsUInt16Number PCS[3];
cmsUInt16Number Colorant[cmsMAXCHANNELS];
- char Root[33];
+ char Root[cmsMAX_PATH];
if (!cmsNamedColorInfo(NamedColorList, i, Root, NULL, NULL, PCS, Colorant)) return 0;
Root[32] = 0;
@@ -3939,7 +3969,7 @@ cmsToneCurve* ReadSegmentedCurve(struct _cms_typehandler_struct* self, cmsIOHAND
cmsUInt16Number nSegments;
cmsCurveSegment* Segments;
cmsToneCurve* Curve;
- cmsFloat32Number PrevBreak = -1E22F; // - infinite
+ cmsFloat32Number PrevBreak = MINUS_INF; // - infinite
// Take signature and channels for each element.
if (!_cmsReadUInt32Number(io, (cmsUInt32Number*) &ElementSig)) return NULL;
@@ -3964,7 +3994,7 @@ cmsToneCurve* ReadSegmentedCurve(struct _cms_typehandler_struct* self, cmsIOHAND
}
Segments[nSegments-1].x0 = PrevBreak;
- Segments[nSegments-1].x1 = 1E22F; // A big cmsFloat32Number number
+ Segments[nSegments-1].x1 = PLUS_INF; // A big cmsFloat32Number number
// Read segments
for (i=0; i < nSegments; i++) {
@@ -3998,7 +4028,7 @@ cmsToneCurve* ReadSegmentedCurve(struct _cms_typehandler_struct* self, cmsIOHAND
case cmsSigSampledCurveSeg: {
cmsUInt32Number Count;
- if (!_cmsReadUInt32Number(io, &Count)) return NULL;
+ if (!_cmsReadUInt32Number(io, &Count)) goto Error;
Segments[i].nGridPoints = Count;
Segments[i].SampledPoints = (cmsFloat32Number*) _cmsCalloc(self ->ContextID, Count, sizeof(cmsFloat32Number));
@@ -4017,7 +4047,7 @@ cmsToneCurve* ReadSegmentedCurve(struct _cms_typehandler_struct* self, cmsIOHAND
_cmsTagSignature2String(String, (cmsTagSignature) ElementSig);
cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unknown curve element type '%s' found.", String);
}
- return NULL;
+ goto Error;
}
}
@@ -4031,7 +4061,12 @@ cmsToneCurve* ReadSegmentedCurve(struct _cms_typehandler_struct* self, cmsIOHAND
return Curve;
Error:
- if (Segments) _cmsFree(self ->ContextID, Segments);
+ if (Segments) {
+ for (i=0; i < nSegments; i++) {
+ if (Segments[i].SampledPoints) _cmsFree(self ->ContextID, Segments[i].SampledPoints);
+ }
+ _cmsFree(self ->ContextID, Segments);
+ }
return NULL;
}
@@ -4085,7 +4120,7 @@ void *Type_MPEcurve_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io,
}
_cmsFree(self ->ContextID, GammaTables);
- *nItems = (mpe != NULL) ? 1 : 0;
+ *nItems = (mpe != NULL) ? 1U : 0;
return mpe;
cmsUNUSED_PARAMETER(SizeOfTag);
@@ -4216,9 +4251,13 @@ void *Type_MPEmatrix_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io
if (!_cmsReadUInt16Number(io, &OutputChans)) return NULL;
- nElems = InputChans * OutputChans;
+ // Input and output chans may be ANY (up to 0xffff),
+ // but we choose to limit to 16 channels for now
+ if (InputChans >= cmsMAXCHANNELS) return NULL;
+ if (OutputChans >= cmsMAXCHANNELS) return NULL;
+
+ nElems = (cmsUInt32Number) InputChans * OutputChans;
- // Input and output chans may be ANY (up to 0xffff)
Matrix = (cmsFloat64Number*) _cmsCalloc(self ->ContextID, nElems, sizeof(cmsFloat64Number));
if (Matrix == NULL) return NULL;
@@ -4233,7 +4272,11 @@ void *Type_MPEmatrix_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io
cmsFloat32Number v;
- if (!_cmsReadFloat32Number(io, &v)) return NULL;
+ if (!_cmsReadFloat32Number(io, &v)) {
+ _cmsFree(self ->ContextID, Matrix);
+ _cmsFree(self ->ContextID, Offsets);
+ return NULL;
+ }
Matrix[i] = v;
}
@@ -4242,7 +4285,11 @@ void *Type_MPEmatrix_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io
cmsFloat32Number v;
- if (!_cmsReadFloat32Number(io, &v)) return NULL;
+ if (!_cmsReadFloat32Number(io, &v)) {
+ _cmsFree(self ->ContextID, Matrix);
+ _cmsFree(self ->ContextID, Offsets);
+ return NULL;
+ }
Offsets[i] = v;
}
@@ -4313,8 +4360,9 @@ void *Type_MPEclut_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io,
goto Error;
// Copy MAX_INPUT_DIMENSIONS at most. Expand to cmsUInt32Number
- nMaxGrids = InputChans > MAX_INPUT_DIMENSIONS ? MAX_INPUT_DIMENSIONS : InputChans;
- for (i=0; i < nMaxGrids; i++) {
+ nMaxGrids = InputChans > MAX_INPUT_DIMENSIONS ? (cmsUInt32Number) MAX_INPUT_DIMENSIONS : InputChans;
+
+ for (i = 0; i < nMaxGrids; i++) {
if (Dimensions8[i] == 1) goto Error; // Impossible value, 0 for no CLUT and then 2 at least
GridPoints[i] = (cmsUInt32Number)Dimensions8[i];
}
@@ -4323,11 +4371,11 @@ void *Type_MPEclut_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io,
mpe = cmsStageAllocCLutFloatGranular(self ->ContextID, GridPoints, InputChans, OutputChans, NULL);
if (mpe == NULL) goto Error;
- // Read the data
+ // Read and sanitize the data
clut = (_cmsStageCLutData*) mpe ->Data;
for (i=0; i < clut ->nEntries; i++) {
- if (!_cmsReadFloat32Number(io, &clut ->Tab.TFloat[i])) goto Error;
+ if (!_cmsReadFloat32Number(io, &clut->Tab.TFloat[i])) goto Error;
}
*nItems = 1;
@@ -4457,6 +4505,9 @@ void *Type_MPE_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsU
if (!_cmsReadUInt16Number(io, &InputChans)) return NULL;
if (!_cmsReadUInt16Number(io, &OutputChans)) return NULL;
+ if (InputChans == 0 || InputChans >= cmsMAXCHANNELS) return NULL;
+ if (OutputChans == 0 || OutputChans >= cmsMAXCHANNELS) return NULL;
+
// Allocates an empty LUT
NewLUT = cmsPipelineAlloc(self ->ContextID, InputChans, OutputChans);
if (NewLUT == NULL) return NULL;
@@ -4464,6 +4515,10 @@ void *Type_MPE_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsU
if (!_cmsReadUInt32Number(io, &ElementCount)) goto Error;
if (!ReadPositionTable(self, io, ElementCount, BaseOffset, NewLUT, ReadMPEElem)) goto Error;
+ // Check channel count
+ if (InputChans != NewLUT->InputChannels ||
+ OutputChans != NewLUT->OutputChannels) goto Error;
+
// Success
*nItems = 1;
return NewLUT;
@@ -4484,7 +4539,7 @@ static
cmsBool Type_MPE_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
{
cmsUInt32Number i, BaseOffset, DirectoryPos, CurrentPos;
- int inputChan, outputChan;
+ cmsUInt32Number inputChan, outputChan;
cmsUInt32Number ElemCount;
cmsUInt32Number *ElementOffsets = NULL, *ElementSizes = NULL, Before;
cmsStageSignature ElementSig;
@@ -4532,7 +4587,7 @@ cmsBool Type_MPE_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, v
_cmsTagSignature2String(String, (cmsTagSignature) ElementSig);
- // An unknow element was found.
+ // An unknown element was found.
cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Found unknown MPE type '%s'", String);
goto Error;
}
@@ -5267,38 +5322,38 @@ void Type_Dictionary_Free(struct _cms_typehandler_struct* self, void* Ptr)
// This is the list of built-in types
-static _cmsTagTypeLinkedList SupportedTagTypes[] = {
-
-{TYPE_HANDLER(cmsSigChromaticityType, Chromaticity), &SupportedTagTypes[1] },
-{TYPE_HANDLER(cmsSigColorantOrderType, ColorantOrderType), &SupportedTagTypes[2] },
-{TYPE_HANDLER(cmsSigS15Fixed16ArrayType, S15Fixed16), &SupportedTagTypes[3] },
-{TYPE_HANDLER(cmsSigU16Fixed16ArrayType, U16Fixed16), &SupportedTagTypes[4] },
-{TYPE_HANDLER(cmsSigTextType, Text), &SupportedTagTypes[5] },
-{TYPE_HANDLER(cmsSigTextDescriptionType, Text_Description), &SupportedTagTypes[6] },
-{TYPE_HANDLER(cmsSigCurveType, Curve), &SupportedTagTypes[7] },
-{TYPE_HANDLER(cmsSigParametricCurveType, ParametricCurve), &SupportedTagTypes[8] },
-{TYPE_HANDLER(cmsSigDateTimeType, DateTime), &SupportedTagTypes[9] },
-{TYPE_HANDLER(cmsSigLut8Type, LUT8), &SupportedTagTypes[10] },
-{TYPE_HANDLER(cmsSigLut16Type, LUT16), &SupportedTagTypes[11] },
-{TYPE_HANDLER(cmsSigColorantTableType, ColorantTable), &SupportedTagTypes[12] },
-{TYPE_HANDLER(cmsSigNamedColor2Type, NamedColor), &SupportedTagTypes[13] },
-{TYPE_HANDLER(cmsSigMultiLocalizedUnicodeType, MLU), &SupportedTagTypes[14] },
-{TYPE_HANDLER(cmsSigProfileSequenceDescType, ProfileSequenceDesc), &SupportedTagTypes[15] },
-{TYPE_HANDLER(cmsSigSignatureType, Signature), &SupportedTagTypes[16] },
-{TYPE_HANDLER(cmsSigMeasurementType, Measurement), &SupportedTagTypes[17] },
-{TYPE_HANDLER(cmsSigDataType, Data), &SupportedTagTypes[18] },
-{TYPE_HANDLER(cmsSigLutAtoBType, LUTA2B), &SupportedTagTypes[19] },
-{TYPE_HANDLER(cmsSigLutBtoAType, LUTB2A), &SupportedTagTypes[20] },
-{TYPE_HANDLER(cmsSigUcrBgType, UcrBg), &SupportedTagTypes[21] },
-{TYPE_HANDLER(cmsSigCrdInfoType, CrdInfo), &SupportedTagTypes[22] },
-{TYPE_HANDLER(cmsSigMultiProcessElementType, MPE), &SupportedTagTypes[23] },
-{TYPE_HANDLER(cmsSigScreeningType, Screening), &SupportedTagTypes[24] },
-{TYPE_HANDLER(cmsSigViewingConditionsType, ViewingConditions), &SupportedTagTypes[25] },
-{TYPE_HANDLER(cmsSigXYZType, XYZ), &SupportedTagTypes[26] },
-{TYPE_HANDLER(cmsCorbisBrokenXYZtype, XYZ), &SupportedTagTypes[27] },
-{TYPE_HANDLER(cmsMonacoBrokenCurveType, Curve), &SupportedTagTypes[28] },
-{TYPE_HANDLER(cmsSigProfileSequenceIdType, ProfileSequenceId), &SupportedTagTypes[29] },
-{TYPE_HANDLER(cmsSigDictType, Dictionary), &SupportedTagTypes[30] },
+static const _cmsTagTypeLinkedList SupportedTagTypes[] = {
+
+{TYPE_HANDLER(cmsSigChromaticityType, Chromaticity), (_cmsTagTypeLinkedList*) &SupportedTagTypes[1] },
+{TYPE_HANDLER(cmsSigColorantOrderType, ColorantOrderType), (_cmsTagTypeLinkedList*) &SupportedTagTypes[2] },
+{TYPE_HANDLER(cmsSigS15Fixed16ArrayType, S15Fixed16), (_cmsTagTypeLinkedList*) &SupportedTagTypes[3] },
+{TYPE_HANDLER(cmsSigU16Fixed16ArrayType, U16Fixed16), (_cmsTagTypeLinkedList*) &SupportedTagTypes[4] },
+{TYPE_HANDLER(cmsSigTextType, Text), (_cmsTagTypeLinkedList*) &SupportedTagTypes[5] },
+{TYPE_HANDLER(cmsSigTextDescriptionType, Text_Description), (_cmsTagTypeLinkedList*) &SupportedTagTypes[6] },
+{TYPE_HANDLER(cmsSigCurveType, Curve), (_cmsTagTypeLinkedList*) &SupportedTagTypes[7] },
+{TYPE_HANDLER(cmsSigParametricCurveType, ParametricCurve), (_cmsTagTypeLinkedList*) &SupportedTagTypes[8] },
+{TYPE_HANDLER(cmsSigDateTimeType, DateTime), (_cmsTagTypeLinkedList*) &SupportedTagTypes[9] },
+{TYPE_HANDLER(cmsSigLut8Type, LUT8), (_cmsTagTypeLinkedList*) &SupportedTagTypes[10] },
+{TYPE_HANDLER(cmsSigLut16Type, LUT16), (_cmsTagTypeLinkedList*) &SupportedTagTypes[11] },
+{TYPE_HANDLER(cmsSigColorantTableType, ColorantTable), (_cmsTagTypeLinkedList*) &SupportedTagTypes[12] },
+{TYPE_HANDLER(cmsSigNamedColor2Type, NamedColor), (_cmsTagTypeLinkedList*) &SupportedTagTypes[13] },
+{TYPE_HANDLER(cmsSigMultiLocalizedUnicodeType, MLU), (_cmsTagTypeLinkedList*) &SupportedTagTypes[14] },
+{TYPE_HANDLER(cmsSigProfileSequenceDescType, ProfileSequenceDesc),(_cmsTagTypeLinkedList*) &SupportedTagTypes[15] },
+{TYPE_HANDLER(cmsSigSignatureType, Signature), (_cmsTagTypeLinkedList*) &SupportedTagTypes[16] },
+{TYPE_HANDLER(cmsSigMeasurementType, Measurement), (_cmsTagTypeLinkedList*) &SupportedTagTypes[17] },
+{TYPE_HANDLER(cmsSigDataType, Data), (_cmsTagTypeLinkedList*) &SupportedTagTypes[18] },
+{TYPE_HANDLER(cmsSigLutAtoBType, LUTA2B), (_cmsTagTypeLinkedList*) &SupportedTagTypes[19] },
+{TYPE_HANDLER(cmsSigLutBtoAType, LUTB2A), (_cmsTagTypeLinkedList*) &SupportedTagTypes[20] },
+{TYPE_HANDLER(cmsSigUcrBgType, UcrBg), (_cmsTagTypeLinkedList*) &SupportedTagTypes[21] },
+{TYPE_HANDLER(cmsSigCrdInfoType, CrdInfo), (_cmsTagTypeLinkedList*) &SupportedTagTypes[22] },
+{TYPE_HANDLER(cmsSigMultiProcessElementType, MPE), (_cmsTagTypeLinkedList*) &SupportedTagTypes[23] },
+{TYPE_HANDLER(cmsSigScreeningType, Screening), (_cmsTagTypeLinkedList*) &SupportedTagTypes[24] },
+{TYPE_HANDLER(cmsSigViewingConditionsType, ViewingConditions), (_cmsTagTypeLinkedList*) &SupportedTagTypes[25] },
+{TYPE_HANDLER(cmsSigXYZType, XYZ), (_cmsTagTypeLinkedList*) &SupportedTagTypes[26] },
+{TYPE_HANDLER(cmsCorbisBrokenXYZtype, XYZ), (_cmsTagTypeLinkedList*) &SupportedTagTypes[27] },
+{TYPE_HANDLER(cmsMonacoBrokenCurveType, Curve), (_cmsTagTypeLinkedList*) &SupportedTagTypes[28] },
+{TYPE_HANDLER(cmsSigProfileSequenceIdType, ProfileSequenceId), (_cmsTagTypeLinkedList*) &SupportedTagTypes[29] },
+{TYPE_HANDLER(cmsSigDictType, Dictionary), (_cmsTagTypeLinkedList*) &SupportedTagTypes[30] },
{TYPE_HANDLER(cmsSigVcgtType, vcgt), NULL }
};
@@ -5390,7 +5445,7 @@ cmsTagTypeHandler* _cmsGetTagTypeHandler(cmsContext ContextID, cmsTagTypeSignatu
{
_cmsTagTypePluginChunkType* ctx = ( _cmsTagTypePluginChunkType*) _cmsContextGetClientChunk(ContextID, TagTypePlugin);
- return GetHandler(sig, ctx->TagTypes, SupportedTagTypes);
+ return GetHandler(sig, ctx->TagTypes, (_cmsTagTypeLinkedList*) SupportedTagTypes);
}
// ********************************************************************************
@@ -5405,7 +5460,7 @@ typedef struct _cmsTagLinkedList_st {
} _cmsTagLinkedList;
-// This is the list of built-in tags
+// This is the list of built-in tags. The data of this list can be modified by plug-ins
static _cmsTagLinkedList SupportedTags[] = {
{ cmsSigAToB0Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutAtoBType, cmsSigLut8Type}, DecideLUTtypeA2B}, &SupportedTags[1]},
@@ -5454,7 +5509,7 @@ static _cmsTagLinkedList SupportedTags[] = {
{ cmsSigPreview2Tag, { 1, 3, { cmsSigLut16Type, cmsSigLutBtoAType, cmsSigLut8Type }, DecideLUTtypeB2A}, &SupportedTags[32]},
{ cmsSigProfileDescriptionTag, { 1, 3, { cmsSigTextDescriptionType, cmsSigMultiLocalizedUnicodeType, cmsSigTextType}, DecideTextDescType}, &SupportedTags[33]},
- { cmsSigProfileSequenceDescTag, { 1, 1, { cmsSigProfileSequenceDescType }, NULL}, &SupportedTags[34]},
+ { cmsSigProfileSequenceDescTag, { 1, 1, { cmsSigProfileSequenceDescType }, NULL}, &SupportedTags[34]},
{ cmsSigTechnologyTag, { 1, 1, { cmsSigSignatureType }, NULL}, &SupportedTags[35]},
{ cmsSigColorimetricIntentImageStateTag, { 1, 1, { cmsSigSignatureType }, NULL}, &SupportedTags[36]},
@@ -5491,10 +5546,10 @@ static _cmsTagLinkedList SupportedTags[] = {
{ cmsSigVcgtTag, { 1, 1, { cmsSigVcgtType}, NULL }, &SupportedTags[60]},
{ cmsSigMetaTag, { 1, 1, { cmsSigDictType}, NULL }, &SupportedTags[61]},
{ cmsSigProfileSequenceIdTag, { 1, 1, { cmsSigProfileSequenceIdType}, NULL }, &SupportedTags[62]},
+
{ cmsSigProfileDescriptionMLTag,{ 1, 1, { cmsSigMultiLocalizedUnicodeType}, NULL}, &SupportedTags[63]},
{ cmsSigArgyllArtsTag, { 9, 1, { cmsSigS15Fixed16ArrayType}, NULL}, NULL}
-
};
/*
diff --git a/src/java.desktop/share/native/liblcms/cmsvirt.c b/src/java.desktop/share/native/liblcms/cmsvirt.c
index 8d353b369d7..89e55e4e439 100644
--- a/src/java.desktop/share/native/liblcms/cmsvirt.c
+++ b/src/java.desktop/share/native/liblcms/cmsvirt.c
@@ -30,7 +30,7 @@
//---------------------------------------------------------------------------------
//
// Little Color Management System
-// Copyright (c) 1998-2016 Marti Maria Saguer
+// Copyright (c) 1998-2017 Marti Maria Saguer
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
@@ -320,7 +320,7 @@ cmsHPROFILE CMSEXPORT cmsCreateLinearizationDeviceLinkTHR(cmsContext ContextID,
{
cmsHPROFILE hICC;
cmsPipeline* Pipeline;
- int nChannels;
+ cmsUInt32Number nChannels;
hICC = cmsCreateProfilePlaceholder(ContextID);
if (!hICC)
@@ -426,7 +426,7 @@ cmsHPROFILE CMSEXPORT cmsCreateInkLimitingDeviceLinkTHR(cmsContext ContextID,
cmsHPROFILE hICC;
cmsPipeline* LUT;
cmsStage* CLUT;
- int nChannels;
+ cmsUInt32Number nChannels;
if (ColorSpace != cmsSigCmykData) {
cmsSignalError(ContextID, cmsERROR_COLORSPACE_CHECK, "InkLimiting: Only CMYK currently supported");
@@ -755,13 +755,13 @@ int bchswSampler(register const cmsUInt16Number In[], register cmsUInt16Number O
// contrast, Saturation and white point displacement
cmsHPROFILE CMSEXPORT cmsCreateBCHSWabstractProfileTHR(cmsContext ContextID,
- int nLUTPoints,
- cmsFloat64Number Bright,
- cmsFloat64Number Contrast,
- cmsFloat64Number Hue,
- cmsFloat64Number Saturation,
- int TempSrc,
- int TempDest)
+ cmsUInt32Number nLUTPoints,
+ cmsFloat64Number Bright,
+ cmsFloat64Number Contrast,
+ cmsFloat64Number Hue,
+ cmsFloat64Number Saturation,
+ cmsUInt32Number TempSrc,
+ cmsUInt32Number TempDest)
{
cmsHPROFILE hICC;
cmsPipeline* Pipeline;
@@ -769,7 +769,7 @@ cmsHPROFILE CMSEXPORT cmsCreateBCHSWabstractProfileTHR(cmsContext ContextID,
cmsCIExyY WhitePnt;
cmsStage* CLUT;
cmsUInt32Number Dimensions[MAX_INPUT_DIMENSIONS];
- int i;
+ cmsUInt32Number i;
bchsw.Brightness = Bright;
bchsw.Contrast = Contrast;
@@ -807,7 +807,7 @@ cmsHPROFILE CMSEXPORT cmsCreateBCHSWabstractProfileTHR(cmsContext ContextID,
for (i=0; i < MAX_INPUT_DIMENSIONS; i++) Dimensions[i] = nLUTPoints;
CLUT = cmsStageAllocCLut16bitGranular(ContextID, Dimensions, 3, 3, NULL);
- if (CLUT == NULL) return NULL;
+ if (CLUT == NULL) goto Error;
if (!cmsStageSampleCLut16bit(CLUT, bchswSampler, (void*) &bchsw, 0)) {
@@ -840,13 +840,13 @@ cmsHPROFILE CMSEXPORT cmsCreateBCHSWabstractProfileTHR(cmsContext ContextID,
}
-CMSAPI cmsHPROFILE CMSEXPORT cmsCreateBCHSWabstractProfile(int nLUTPoints,
+CMSAPI cmsHPROFILE CMSEXPORT cmsCreateBCHSWabstractProfile(cmsUInt32Number nLUTPoints,
cmsFloat64Number Bright,
cmsFloat64Number Contrast,
cmsFloat64Number Hue,
cmsFloat64Number Saturation,
- int TempSrc,
- int TempDest)
+ cmsUInt32Number TempSrc,
+ cmsUInt32Number TempDest)
{
return cmsCreateBCHSWabstractProfileTHR(NULL, nLUTPoints, Bright, Contrast, Hue, Saturation, TempSrc, TempDest);
}
@@ -859,8 +859,10 @@ cmsHPROFILE CMSEXPORT cmsCreateNULLProfileTHR(cmsContext ContextID)
cmsHPROFILE hProfile;
cmsPipeline* LUT = NULL;
cmsStage* PostLin;
- cmsToneCurve* EmptyTab;
+ cmsStage* OutLin;
+ cmsToneCurve* EmptyTab[3];
cmsUInt16Number Zero[2] = { 0, 0 };
+ const cmsFloat64Number PickLstarMatrix[] = { 1, 0, 0 };
hProfile = cmsCreateProfilePlaceholder(ContextID);
if (!hProfile) // can't allocate
@@ -871,22 +873,28 @@ cmsHPROFILE CMSEXPORT cmsCreateNULLProfileTHR(cmsContext ContextID)
if (!SetTextTags(hProfile, L"NULL profile built-in")) goto Error;
-
cmsSetDeviceClass(hProfile, cmsSigOutputClass);
cmsSetColorSpace(hProfile, cmsSigGrayData);
cmsSetPCS(hProfile, cmsSigLabData);
- // An empty LUTs is all we need
- LUT = cmsPipelineAlloc(ContextID, 1, 1);
+ // Create a valid ICC 4 structure
+ LUT = cmsPipelineAlloc(ContextID, 3, 1);
if (LUT == NULL) goto Error;
- EmptyTab = cmsBuildTabulatedToneCurve16(ContextID, 2, Zero);
- PostLin = cmsStageAllocToneCurves(ContextID, 1, &EmptyTab);
- cmsFreeToneCurve(EmptyTab);
+ EmptyTab[0] = EmptyTab[1] = EmptyTab[2] = cmsBuildTabulatedToneCurve16(ContextID, 2, Zero);
+ PostLin = cmsStageAllocToneCurves(ContextID, 3, EmptyTab);
+ OutLin = cmsStageAllocToneCurves(ContextID, 1, EmptyTab);
+ cmsFreeToneCurve(EmptyTab[0]);
if (!cmsPipelineInsertStage(LUT, cmsAT_END, PostLin))
goto Error;
+ if (!cmsPipelineInsertStage(LUT, cmsAT_END, cmsStageAllocMatrix(ContextID, 1, 3, PickLstarMatrix, NULL)))
+ goto Error;
+
+ if (!cmsPipelineInsertStage(LUT, cmsAT_END, OutLin))
+ goto Error;
+
if (!cmsWriteTag(hProfile, cmsSigBToA0Tag, (void*) LUT)) goto Error;
if (!cmsWriteTag(hProfile, cmsSigMediaWhitePointTag, cmsD50_XYZ())) goto Error;
@@ -967,7 +975,7 @@ cmsHPROFILE CreateNamedColorDevicelink(cmsHTRANSFORM xform)
{
_cmsTRANSFORM* v = (_cmsTRANSFORM*) xform;
cmsHPROFILE hICC = NULL;
- int i, nColors;
+ cmsUInt32Number i, nColors;
cmsNAMEDCOLORLIST *nc2 = NULL, *Original = NULL;
// Create an empty placeholder
@@ -1084,7 +1092,7 @@ cmsHPROFILE CMSEXPORT cmsTransform2DeviceLink(cmsHTRANSFORM hTransform, cmsFloat
{
cmsHPROFILE hProfile = NULL;
cmsUInt32Number FrmIn, FrmOut, ChansIn, ChansOut;
- cmsUInt32Number ColorSpaceBitsIn, ColorSpaceBitsOut;
+ int ColorSpaceBitsIn, ColorSpaceBitsOut;
_cmsTRANSFORM* xform = (_cmsTRANSFORM*) hTransform;
cmsPipeline* LUT = NULL;
cmsStage* mpe;
diff --git a/src/java.desktop/share/native/liblcms/cmswtpnt.c b/src/java.desktop/share/native/liblcms/cmswtpnt.c
index d23b29f1b00..fddf8b5e709 100644
--- a/src/java.desktop/share/native/liblcms/cmswtpnt.c
+++ b/src/java.desktop/share/native/liblcms/cmswtpnt.c
@@ -30,7 +30,7 @@
//---------------------------------------------------------------------------------
//
// Little Color Management System
-// Copyright (c) 1998-2016 Marti Maria Saguer
+// Copyright (c) 1998-2017 Marti Maria Saguer
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
@@ -105,7 +105,6 @@ cmsBool CMSEXPORT cmsWhitePointFromTemp(cmsCIExyY* WhitePoint, cmsFloat64Number
}
// Obtain y(x)
-
y = -3.000*(x*x) + 2.870*x - 0.275;
// wave factors (not used, but here for futures extensions)
@@ -131,7 +130,7 @@ typedef struct {
} ISOTEMPERATURE;
-static ISOTEMPERATURE isotempdata[] = {
+static const ISOTEMPERATURE isotempdata[] = {
// {Mirek, Ut, Vt, Tt }
{0, 0.18006, 0.26352, -0.24341},
{10, 0.18066, 0.26589, -0.25479},
@@ -295,7 +294,7 @@ cmsBool _cmsAdaptMatrixToD50(cmsMAT3* r, const cmsCIExyY* SourceWhitePt)
// Build a White point, primary chromas transfer matrix from RGB to CIE XYZ
// This is just an approximation, I am not handling all the non-linear
// aspects of the RGB to XYZ process, and assumming that the gamma correction
-// has transitive property in the tranformation chain.
+// has transitive property in the transformation chain.
//
// the alghoritm:
//
diff --git a/src/java.desktop/share/native/liblcms/cmsxform.c b/src/java.desktop/share/native/liblcms/cmsxform.c
index dfedd7f5cf9..77d54804a42 100644
--- a/src/java.desktop/share/native/liblcms/cmsxform.c
+++ b/src/java.desktop/share/native/liblcms/cmsxform.c
@@ -30,7 +30,7 @@
//---------------------------------------------------------------------------------
//
// Little Color Management System
-// Copyright (c) 1998-2016 Marti Maria Saguer
+// Copyright (c) 1998-2017 Marti Maria Saguer
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
@@ -284,6 +284,8 @@ void FloatXFORM(_cmsTRANSFORM* p,
strideIn = 0;
strideOut = 0;
+ memset(fIn, 0, sizeof(fIn));
+ memset(fOut, 0, sizeof(fIn));
for (i = 0; i < LineCount; i++) {
@@ -348,6 +350,7 @@ void NullFloatXFORM(_cmsTRANSFORM* p,
strideIn = 0;
strideOut = 0;
+ memset(fIn, 0, sizeof(fIn));
for (i = 0; i < LineCount; i++) {
@@ -385,6 +388,7 @@ void NullXFORM(_cmsTRANSFORM* p,
strideIn = 0;
strideOut = 0;
+ memset(wIn, 0, sizeof(wIn));
for (i = 0; i < LineCount; i++) {
@@ -422,6 +426,8 @@ void PrecalculatedXFORM(_cmsTRANSFORM* p,
strideIn = 0;
strideOut = 0;
+ memset(wIn, 0, sizeof(wIn));
+ memset(wOut, 0, sizeof(wOut));
for (i = 0; i < LineCount; i++) {
@@ -483,6 +489,8 @@ void PrecalculatedXFORMGamutCheck(_cmsTRANSFORM* p,
strideIn = 0;
strideOut = 0;
+ memset(wIn, 0, sizeof(wIn));
+ memset(wOut, 0, sizeof(wOut));
for (i = 0; i < LineCount; i++) {
@@ -790,7 +798,10 @@ _cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsPipeline* lut,
// Allocate needed memory
_cmsTRANSFORM* p = (_cmsTRANSFORM*)_cmsMallocZero(ContextID, sizeof(_cmsTRANSFORM));
- if (!p) return NULL;
+ if (!p) {
+ cmsPipelineFree(lut);
+ return NULL;
+ }
// Store the proposed pipeline
p->Lut = lut;
@@ -823,7 +834,7 @@ _cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsPipeline* lut,
p->FromInputFloat = _cmsGetFormatter(ContextID, *InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_FLOAT).FmtFloat;
p->ToOutputFloat = _cmsGetFormatter(ContextID, *OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_FLOAT).FmtFloat;
- // Save the day?
+ // Save the day? (Ignore the warning)
if (Plugin->OldXform) {
p->OldXform = (_cmsTransformFn) p->xform;
p->xform = _cmsTransform2toTransformAdaptor;
@@ -848,7 +859,7 @@ _cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsPipeline* lut,
if (p ->FromInputFloat == NULL || p ->ToOutputFloat == NULL) {
cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported raster format");
- _cmsFree(ContextID, p);
+ cmsDeleteTransform(p);
return NULL;
}
@@ -870,7 +881,7 @@ _cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsPipeline* lut,
}
else {
- int BytesPerPixelInput;
+ cmsUInt32Number BytesPerPixelInput;
p ->FromInput = _cmsGetFormatter(ContextID, *InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_16BITS).Fmt16;
p ->ToOutput = _cmsGetFormatter(ContextID, *OutputFormat, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS).Fmt16;
@@ -878,7 +889,7 @@ _cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsPipeline* lut,
if (p ->FromInput == NULL || p ->ToOutput == NULL) {
cmsSignalError(ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported raster format");
- _cmsFree(ContextID, p);
+ cmsDeleteTransform(p);
return NULL;
}
@@ -920,13 +931,13 @@ _cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsPipeline* lut,
}
static
-cmsBool GetXFormColorSpaces(int nProfiles, cmsHPROFILE hProfiles[], cmsColorSpaceSignature* Input, cmsColorSpaceSignature* Output)
+cmsBool GetXFormColorSpaces(cmsUInt32Number nProfiles, cmsHPROFILE hProfiles[], cmsColorSpaceSignature* Input, cmsColorSpaceSignature* Output)
{
cmsColorSpaceSignature ColorSpaceIn, ColorSpaceOut;
cmsColorSpaceSignature PostColorSpace;
- int i;
+ cmsUInt32Number i;
- if (nProfiles <= 0) return FALSE;
+ if (nProfiles == 0) return FALSE;
if (hProfiles[0] == NULL) return FALSE;
*Input = PostColorSpace = cmsGetColorSpace(hProfiles[0]);
@@ -975,7 +986,7 @@ cmsBool GetXFormColorSpaces(int nProfiles, cmsHPROFILE hProfiles[], cmsColorSpac
static
cmsBool IsProperColorSpace(cmsColorSpaceSignature Check, cmsUInt32Number dwFormat)
{
- int Space1 = T_COLORSPACE(dwFormat);
+ int Space1 = (int) T_COLORSPACE(dwFormat);
int Space2 = _cmsLCMScolorSpace(Check);
if (Space1 == PT_ANY) return TRUE;
@@ -1231,7 +1242,7 @@ cmsHTRANSFORM CMSEXPORT cmsCreateTransformTHR(cmsContext ContextID,
hArray[0] = Input;
hArray[1] = Output;
- return cmsCreateMultiprofileTransformTHR(ContextID, hArray, Output == NULL ? 1 : 2, InputFormat, OutputFormat, Intent, dwFlags);
+ return cmsCreateMultiprofileTransformTHR(ContextID, hArray, Output == NULL ? 1U : 2U, InputFormat, OutputFormat, Intent, dwFlags);
}
CMSAPI cmsHTRANSFORM CMSEXPORT cmsCreateTransform(cmsHPROFILE Input,
diff --git a/src/java.desktop/share/native/liblcms/lcms2.h b/src/java.desktop/share/native/liblcms/lcms2.h
index cbca89421a5..cc5d0cf60fb 100644
--- a/src/java.desktop/share/native/liblcms/lcms2.h
+++ b/src/java.desktop/share/native/liblcms/lcms2.h
@@ -30,7 +30,7 @@
//---------------------------------------------------------------------------------
//
// Little Color Management System
-// Copyright (c) 1998-2016 Marti Maria Saguer
+// Copyright (c) 1998-2017 Marti Maria Saguer
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
@@ -52,7 +52,7 @@
//
//---------------------------------------------------------------------------------
//
-// Version 2.8
+// Version 2.9rc3
//
#ifndef _lcms2_H
@@ -78,7 +78,7 @@
// #define CMS_USE_CPP_API
// Uncomment this line if you need strict CGATS syntax. Makes CGATS files to
-// require "KEYWORD" on undefined identifiers, keep it comented out unless needed
+// require "KEYWORD" on undefined identifiers, keep it commented out unless needed
// #define CMS_STRICT_CGATS 1
// Uncomment to get rid of the tables for "half" float support
@@ -87,6 +87,9 @@
// Uncomment to get rid of pthreads/windows dependency
// #define CMS_NO_PTHREADS 1
+// Uncomment this for special windows mutex initialization (see lcms2_internal.h)
+// #define CMS_RELY_ON_WINDOWS_STATIC_MUTEX_INIT
+
// ********** End of configuration toggles ******************************
// Needed for streams
@@ -104,7 +107,7 @@ extern "C" {
#endif
// Version/release
-#define LCMS_VERSION 2080
+#define LCMS_VERSION 2090
// I will give the chance of redefining basic types for compilers that are not fully C99 compliant
#ifndef CMS_BASIC_TYPES_ALREADY_DEFINED
@@ -254,16 +257,21 @@ typedef int cmsBool;
# define CMSAPI __declspec(dllexport)
# else
# define CMSAPI __declspec(dllimport)
-# endif
+# endif
# endif
# else
-# define CMSEXPORT
-# define CMSAPI
+# define CMSEXPORT
+# define CMSAPI
# endif
-#else
-# define CMSEXPORT
-# define CMSAPI
-#endif
+#else // not Windows
+# ifdef HAVE_FUNC_ATTRIBUTE_VISIBILITY
+# define CMSEXPORT
+# define CMSAPI __attribute__((visibility("default")))
+# else
+# define CMSEXPORT
+# define CMSAPI
+# endif
+#endif // CMS_IS_WINDOWS_
#ifdef HasTHREADS
# if HasTHREADS == 1
@@ -284,9 +292,9 @@ typedef int cmsBool;
#endif
// D50 XYZ normalized to Y=1.0
-#define cmsD50X 0.9642
-#define cmsD50Y 1.0
-#define cmsD50Z 0.8249
+#define cmsD50X 0.9642
+#define cmsD50Y 1.0
+#define cmsD50Z 0.8249
// V4 perceptual black
#define cmsPERCEPTUAL_BLACK_X 0.00336
@@ -294,8 +302,8 @@ typedef int cmsBool;
#define cmsPERCEPTUAL_BLACK_Z 0.00287
// Definitions in ICC spec
-#define cmsMagicNumber 0x61637370 // 'acsp'
-#define lcmsSignature 0x6c636d73 // 'lcms'
+#define cmsMagicNumber 0x61637370 // 'acsp'
+#define lcmsSignature 0x6c636d73 // 'lcms'
// Base ICC type definitions
@@ -1154,7 +1162,7 @@ typedef struct {
cmsCIEXYZ whitePoint;
cmsFloat64Number Yb;
cmsFloat64Number La;
- int surround;
+ cmsUInt32Number surround;
cmsFloat64Number D_value;
} cmsViewingConditions;
@@ -1182,16 +1190,16 @@ typedef struct {
// The internal representation is none of your business.
typedef struct _cms_curve_struct cmsToneCurve;
-CMSAPI cmsToneCurve* CMSEXPORT cmsBuildSegmentedToneCurve(cmsContext ContextID, cmsInt32Number nSegments, const cmsCurveSegment Segments[]);
+CMSAPI cmsToneCurve* CMSEXPORT cmsBuildSegmentedToneCurve(cmsContext ContextID, cmsUInt32Number nSegments, const cmsCurveSegment Segments[]);
CMSAPI cmsToneCurve* CMSEXPORT cmsBuildParametricToneCurve(cmsContext ContextID, cmsInt32Number Type, const cmsFloat64Number Params[]);
CMSAPI cmsToneCurve* CMSEXPORT cmsBuildGamma(cmsContext ContextID, cmsFloat64Number Gamma);
-CMSAPI cmsToneCurve* CMSEXPORT cmsBuildTabulatedToneCurve16(cmsContext ContextID, cmsInt32Number nEntries, const cmsUInt16Number values[]);
+CMSAPI cmsToneCurve* CMSEXPORT cmsBuildTabulatedToneCurve16(cmsContext ContextID, cmsUInt32Number nEntries, const cmsUInt16Number values[]);
CMSAPI cmsToneCurve* CMSEXPORT cmsBuildTabulatedToneCurveFloat(cmsContext ContextID, cmsUInt32Number nEntries, const cmsFloat32Number values[]);
CMSAPI void CMSEXPORT cmsFreeToneCurve(cmsToneCurve* Curve);
CMSAPI void CMSEXPORT cmsFreeToneCurveTriple(cmsToneCurve* Curve[3]);
CMSAPI cmsToneCurve* CMSEXPORT cmsDupToneCurve(const cmsToneCurve* Src);
CMSAPI cmsToneCurve* CMSEXPORT cmsReverseToneCurve(const cmsToneCurve* InGamma);
-CMSAPI cmsToneCurve* CMSEXPORT cmsReverseToneCurveEx(cmsInt32Number nResultSamples, const cmsToneCurve* InGamma);
+CMSAPI cmsToneCurve* CMSEXPORT cmsReverseToneCurveEx(cmsUInt32Number nResultSamples, const cmsToneCurve* InGamma);
CMSAPI cmsToneCurve* CMSEXPORT cmsJoinToneCurve(cmsContext ContextID, const cmsToneCurve* X, const cmsToneCurve* Y, cmsUInt32Number nPoints);
CMSAPI cmsBool CMSEXPORT cmsSmoothToneCurve(cmsToneCurve* Tab, cmsFloat64Number lambda);
CMSAPI cmsFloat32Number CMSEXPORT cmsEvalToneCurveFloat(const cmsToneCurve* Curve, cmsFloat32Number v);
@@ -1236,7 +1244,7 @@ CMSAPI cmsBool CMSEXPORT cmsPipelineSetSaveAs8bitsFlag(cmsPipeline* lu
// Where to place/locate the stages in the pipeline chain
typedef enum { cmsAT_BEGIN, cmsAT_END } cmsStageLoc;
-CMSAPI int CMSEXPORT cmsPipelineInsertStage(cmsPipeline* lut, cmsStageLoc loc, cmsStage* mpe);
+CMSAPI cmsBool CMSEXPORT cmsPipelineInsertStage(cmsPipeline* lut, cmsStageLoc loc, cmsStage* mpe);
CMSAPI void CMSEXPORT cmsPipelineUnlinkStage(cmsPipeline* lut, cmsStageLoc loc, cmsStage** mpe);
// This function is quite useful to analyze the structure of a Pipeline and retrieve the Stage elements
@@ -1459,7 +1467,7 @@ CMSAPI cmsBool CMSEXPORT cmsLinkTag(cmsHPROFILE hProfile, cmsTagSignat
CMSAPI cmsTagSignature CMSEXPORT cmsTagLinkedTo(cmsHPROFILE hProfile, cmsTagSignature sig);
// Read and write raw data
-CMSAPI cmsInt32Number CMSEXPORT cmsReadRawTag(cmsHPROFILE hProfile, cmsTagSignature sig, void* Buffer, cmsUInt32Number BufferSize);
+CMSAPI cmsUInt32Number CMSEXPORT cmsReadRawTag(cmsHPROFILE hProfile, cmsTagSignature sig, void* Buffer, cmsUInt32Number BufferSize);
CMSAPI cmsBool CMSEXPORT cmsWriteRawTag(cmsHPROFILE hProfile, cmsTagSignature sig, const void* data, cmsUInt32Number Size);
// Access header data
@@ -1550,7 +1558,7 @@ CMSAPI cmsBool CMSEXPORT cmsCloseIOhandler(cmsIOHANDLER* io);
CMSAPI cmsBool CMSEXPORT cmsMD5computeID(cmsHPROFILE hProfile);
-// Profile high level funtions ------------------------------------------------------------------------------------------
+// Profile high level functions ------------------------------------------------------------------------------------------
CMSAPI cmsHPROFILE CMSEXPORT cmsOpenProfileFromFile(const char *ICCProfile, const char *sAccess);
CMSAPI cmsHPROFILE CMSEXPORT cmsOpenProfileFromFileTHR(cmsContext ContextID, const char *ICCProfile, const char *sAccess);
@@ -1610,21 +1618,21 @@ CMSAPI cmsHPROFILE CMSEXPORT cmsCreate_sRGBProfileTHR(cmsContext ContextID)
CMSAPI cmsHPROFILE CMSEXPORT cmsCreate_sRGBProfile(void);
CMSAPI cmsHPROFILE CMSEXPORT cmsCreateBCHSWabstractProfileTHR(cmsContext ContextID,
- int nLUTPoints,
+ cmsUInt32Number nLUTPoints,
cmsFloat64Number Bright,
cmsFloat64Number Contrast,
cmsFloat64Number Hue,
cmsFloat64Number Saturation,
- int TempSrc,
- int TempDest);
+ cmsUInt32Number TempSrc,
+ cmsUInt32Number TempDest);
-CMSAPI cmsHPROFILE CMSEXPORT cmsCreateBCHSWabstractProfile(int nLUTPoints,
+CMSAPI cmsHPROFILE CMSEXPORT cmsCreateBCHSWabstractProfile(cmsUInt32Number nLUTPoints,
cmsFloat64Number Bright,
cmsFloat64Number Contrast,
cmsFloat64Number Hue,
cmsFloat64Number Saturation,
- int TempSrc,
- int TempDest);
+ cmsUInt32Number TempSrc,
+ cmsUInt32Number TempDest);
CMSAPI cmsHPROFILE CMSEXPORT cmsCreateNULLProfileTHR(cmsContext ContextID);
CMSAPI cmsHPROFILE CMSEXPORT cmsCreateNULLProfile(void);
@@ -1666,7 +1674,7 @@ CMSAPI cmsUInt32Number CMSEXPORT cmsGetSupportedIntentsTHR(cmsContext ContextID
#define cmsFLAGS_BLACKPOINTCOMPENSATION 0x2000
#define cmsFLAGS_NOWHITEONWHITEFIXUP 0x0004 // Don't fix scum dot
#define cmsFLAGS_HIGHRESPRECALC 0x0400 // Use more memory to give better accurancy
-#define cmsFLAGS_LOWRESPRECALC 0x0800 // Use less memory to minimize resouces
+#define cmsFLAGS_LOWRESPRECALC 0x0800 // Use less memory to minimize resources
// For devicelink creation
#define cmsFLAGS_8BITS_DEVICELINK 0x0008 // Create 8 bits devicelinks
diff --git a/src/java.desktop/share/native/liblcms/lcms2_internal.h b/src/java.desktop/share/native/liblcms/lcms2_internal.h
index 90094728823..8984981e830 100644
--- a/src/java.desktop/share/native/liblcms/lcms2_internal.h
+++ b/src/java.desktop/share/native/liblcms/lcms2_internal.h
@@ -30,7 +30,7 @@
//
// Little Color Management System
-// Copyright (c) 1998-2016 Marti Maria Saguer
+// Copyright (c) 1998-2017 Marti Maria Saguer
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
@@ -106,7 +106,7 @@
// Maximum of channels for internal pipeline evaluation
#define MAX_STAGE_CHANNELS 128
-// Unused parameter warning supression
+// Unused parameter warning suppression
#define cmsUNUSED_PARAMETER(x) ((void)x)
// The specification for "inline" is section 6.7.4 of the C99 standard (ISO/IEC 9899:1999).
@@ -125,8 +125,16 @@
# ifndef vsnprintf
# define vsnprintf _vsnprintf
# endif
-#endif
+/// Properly define some macros to accommodate
+/// older MSVC versions.
+# if _MSC_VER <= 1700
+ #include
+ #define isnan _isnan
+ #define isinf(x) (!_finite((x)))
+# endif
+
+#endif
// A fast way to convert from/to 16 <-> 8 bits
#define FROM_8_TO_16(rgb) (cmsUInt16Number) ((((cmsUInt16Number) (rgb)) << 8)|(rgb))
@@ -201,19 +209,48 @@ cmsINLINE cmsUInt16Number _cmsQuickSaturateWord(cmsFloat64Number d)
return _cmsQuickFloorWord(d);
}
+// Test bed entry points---------------------------------------------------------------
+#define CMSCHECKPOINT CMSAPI
// Pthread support --------------------------------------------------------------------
#ifndef CMS_NO_PTHREADS
// This is the threading support. Unfortunately, it has to be platform-dependent because
// windows does not support pthreads.
-
#ifdef CMS_IS_WINDOWS_
#define WIN32_LEAN_AND_MEAN 1
#include
+// The locking scheme in LCMS requires a single 'top level' mutex
+// to work. This is actually implemented on Windows as a
+// CriticalSection, because they are lighter weight. With
+// pthreads, this is statically inited. Unfortunately, windows
+// can't officially statically init critical sections.
+//
+// We can work around this in 2 ways.
+//
+// 1) We can use a proper mutex purely to protect the init
+// of the CriticalSection. This in turns requires us to protect
+// the Mutex creation, which we can do using the snappily
+// named InterlockedCompareExchangePointer API (present on
+// windows XP and above).
+//
+// 2) In cases where we want to work on pre-Windows XP, we
+// can use an even more horrible hack described below.
+//
+// So why wouldn't we always use 2)? Because not calling
+// the init function for a critical section means it fails
+// testing with ApplicationVerifier (and presumably similar
+// tools).
+//
+// We therefore default to 1, and people who want to be able
+// to run on pre-Windows XP boxes can build with:
+// CMS_RELY_ON_WINDOWS_STATIC_MUTEX_INIT
+// defined. This is automatically set for builds using
+// versions of MSVC that don't have this API available.
+//
// From: http://locklessinc.com/articles/pthreads_on_windows/
// The pthreads API has an initialization macro that has no correspondence to anything in
// the windows API. By investigating the internal definition of the critical section type,
@@ -235,14 +272,30 @@ cmsINLINE cmsUInt16Number _cmsQuickSaturateWord(cmsFloat64Number d)
typedef CRITICAL_SECTION _cmsMutex;
-#define CMS_MUTEX_INITIALIZER {(PRTL_CRITICAL_SECTION_DEBUG) -1,-1,0,0,0,0}
-
#ifdef _MSC_VER
# if (_MSC_VER >= 1800)
# pragma warning(disable : 26135)
# endif
#endif
+#ifndef CMS_RELY_ON_WINDOWS_STATIC_MUTEX_INIT
+// If we are building with a version of MSVC smaller
+// than 1400 (i.e. before VS2005) then we don't have
+// the InterlockedCompareExchangePointer API, so use
+// the old version.
+# ifdef _MSC_VER
+# if _MSC_VER < 1400
+# define CMS_RELY_ON_WINDOWS_STATIC_MUTEX_INIT
+# endif
+# endif
+#endif
+
+#ifdef CMS_RELY_ON_WINDOWS_STATIC_MUTEX_INIT
+# define CMS_MUTEX_INITIALIZER {(PRTL_CRITICAL_SECTION_DEBUG) -1,-1,0,0,0,0}
+#else
+# define CMS_MUTEX_INITIALIZER {(PRTL_CRITICAL_SECTION_DEBUG)NULL,-1,0,0,0,0}
+#endif
+
cmsINLINE int _cmsLockPrimitive(_cmsMutex *m)
{
EnterCriticalSection(m);
@@ -478,7 +531,7 @@ struct _cmsContext_struct {
void* chunks[MemoryClientMax]; // array of pointers to client chunks. Memory itself is hold in the suballocator.
// If NULL, then it reverts to global Context0
- _cmsMemPluginChunkType DefaultMemoryManager; // The allocators used for creating the context itself. Cannot be overriden
+ _cmsMemPluginChunkType DefaultMemoryManager; // The allocators used for creating the context itself. Cannot be overridden
};
// Returns a pointer to a valid context structure, including the global one if id is zero.
@@ -800,10 +853,10 @@ void _cmsTagSignature2String(char String[5], cmsTagSignature sig
// Interpolation ---------------------------------------------------------------------------------------------------------
-cmsInterpParams* _cmsComputeInterpParams(cmsContext ContextID, int nSamples, int InputChan, int OutputChan, const void* Table, cmsUInt32Number dwFlags);
-cmsInterpParams* _cmsComputeInterpParamsEx(cmsContext ContextID, const cmsUInt32Number nSamples[], int InputChan, int OutputChan, const void* Table, cmsUInt32Number dwFlags);
-void _cmsFreeInterpParams(cmsInterpParams* p);
-cmsBool _cmsSetInterpolationRoutine(cmsContext ContextID, cmsInterpParams* p);
+CMSCHECKPOINT cmsInterpParams* CMSEXPORT _cmsComputeInterpParams(cmsContext ContextID, cmsUInt32Number nSamples, cmsUInt32Number InputChan, cmsUInt32Number OutputChan, const void* Table, cmsUInt32Number dwFlags);
+cmsInterpParams* _cmsComputeInterpParamsEx(cmsContext ContextID, const cmsUInt32Number nSamples[], cmsUInt32Number InputChan, cmsUInt32Number OutputChan, const void* Table, cmsUInt32Number dwFlags);
+CMSCHECKPOINT void CMSEXPORT _cmsFreeInterpParams(cmsInterpParams* p);
+cmsBool _cmsSetInterpolationRoutine(cmsContext ContextID, cmsInterpParams* p);
// Curves ----------------------------------------------------------------------------------------------------------------
@@ -853,20 +906,20 @@ struct _cmsStage_struct {
// Special Stages (cannot be saved)
-cmsStage* _cmsStageAllocLab2XYZ(cmsContext ContextID);
-cmsStage* _cmsStageAllocXYZ2Lab(cmsContext ContextID);
-cmsStage* _cmsStageAllocLabPrelin(cmsContext ContextID);
-cmsStage* _cmsStageAllocLabV2ToV4(cmsContext ContextID);
-cmsStage* _cmsStageAllocLabV2ToV4curves(cmsContext ContextID);
-cmsStage* _cmsStageAllocLabV4ToV2(cmsContext ContextID);
-cmsStage* _cmsStageAllocNamedColor(cmsNAMEDCOLORLIST* NamedColorList, cmsBool UsePCS);
-cmsStage* _cmsStageAllocIdentityCurves(cmsContext ContextID, int nChannels);
-cmsStage* _cmsStageAllocIdentityCLut(cmsContext ContextID, int nChan);
-cmsStage* _cmsStageNormalizeFromLabFloat(cmsContext ContextID);
-cmsStage* _cmsStageNormalizeFromXyzFloat(cmsContext ContextID);
-cmsStage* _cmsStageNormalizeToLabFloat(cmsContext ContextID);
-cmsStage* _cmsStageNormalizeToXyzFloat(cmsContext ContextID);
-cmsStage* _cmsStageClipNegatives(cmsContext ContextID, int nChannels);
+CMSCHECKPOINT cmsStage* CMSEXPORT _cmsStageAllocLab2XYZ(cmsContext ContextID);
+CMSCHECKPOINT cmsStage* CMSEXPORT _cmsStageAllocXYZ2Lab(cmsContext ContextID);
+cmsStage* _cmsStageAllocLabPrelin(cmsContext ContextID);
+CMSCHECKPOINT cmsStage* CMSEXPORT _cmsStageAllocLabV2ToV4(cmsContext ContextID);
+cmsStage* _cmsStageAllocLabV2ToV4curves(cmsContext ContextID);
+CMSCHECKPOINT cmsStage* CMSEXPORT _cmsStageAllocLabV4ToV2(cmsContext ContextID);
+CMSCHECKPOINT cmsStage* CMSEXPORT _cmsStageAllocNamedColor(cmsNAMEDCOLORLIST* NamedColorList, cmsBool UsePCS);
+CMSCHECKPOINT cmsStage* CMSEXPORT _cmsStageAllocIdentityCurves(cmsContext ContextID, cmsUInt32Number nChannels);
+CMSCHECKPOINT cmsStage* CMSEXPORT _cmsStageAllocIdentityCLut(cmsContext ContextID, cmsUInt32Number nChan);
+cmsStage* _cmsStageNormalizeFromLabFloat(cmsContext ContextID);
+cmsStage* _cmsStageNormalizeFromXyzFloat(cmsContext ContextID);
+cmsStage* _cmsStageNormalizeToLabFloat(cmsContext ContextID);
+cmsStage* _cmsStageNormalizeToXyzFloat(cmsContext ContextID);
+cmsStage* _cmsStageClipNegatives(cmsContext ContextID, cmsUInt32Number nChannels);
// For curve set only
@@ -901,9 +954,9 @@ struct _cmsPipeline_struct {
// Read tags using low-level function, provide necessary glue code to adapt versions, etc. All those return a brand new copy
// of the LUTS, since ownership of original is up to the profile. The user should free allocated resources.
-cmsPipeline* _cmsReadInputLUT(cmsHPROFILE hProfile, int Intent);
-cmsPipeline* _cmsReadOutputLUT(cmsHPROFILE hProfile, int Intent);
-cmsPipeline* _cmsReadDevicelinkLUT(cmsHPROFILE hProfile, int Intent);
+CMSCHECKPOINT cmsPipeline* CMSEXPORT _cmsReadInputLUT(cmsHPROFILE hProfile, cmsUInt32Number Intent);
+CMSCHECKPOINT cmsPipeline* CMSEXPORT _cmsReadOutputLUT(cmsHPROFILE hProfile, cmsUInt32Number Intent);
+CMSCHECKPOINT cmsPipeline* CMSEXPORT _cmsReadDevicelinkLUT(cmsHPROFILE hProfile, cmsUInt32Number Intent);
// Special values
cmsBool _cmsReadMediaWhitePoint(cmsCIEXYZ* Dest, cmsHPROFILE hProfile);
@@ -928,8 +981,9 @@ cmsSEQ* _cmsCompileProfileSequence(cmsContext ContextID, cmsUInt32Number nProfil
// LUT optimization ------------------------------------------------------------------------------------------------
-cmsUInt16Number _cmsQuantizeVal(cmsFloat64Number i, int MaxSamples);
-int _cmsReasonableGridpointsByColorspace(cmsColorSpaceSignature Colorspace, cmsUInt32Number dwFlags);
+CMSCHECKPOINT cmsUInt16Number CMSEXPORT _cmsQuantizeVal(cmsFloat64Number i, cmsUInt32Number MaxSamples);
+
+cmsUInt32Number _cmsReasonableGridpointsByColorspace(cmsColorSpaceSignature Colorspace, cmsUInt32Number dwFlags);
cmsBool _cmsEndPointsBySpace(cmsColorSpaceSignature Space,
cmsUInt16Number **White,
@@ -938,7 +992,7 @@ cmsBool _cmsEndPointsBySpace(cmsColorSpaceSignature Space,
cmsBool _cmsOptimizePipeline(cmsContext ContextID,
cmsPipeline** Lut,
- int Intent,
+ cmsUInt32Number Intent,
cmsUInt32Number* InputFormat,
cmsUInt32Number* OutputFormat,
cmsUInt32Number* dwFlags );
@@ -962,17 +1016,17 @@ cmsPipeline* _cmsCreateGamutCheckPipeline(cmsContext ContextID,
cmsBool _cmsFormatterIsFloat(cmsUInt32Number Type);
cmsBool _cmsFormatterIs8bit(cmsUInt32Number Type);
-cmsFormatter _cmsGetFormatter(cmsContext ContextID,
- cmsUInt32Number Type, // Specific type, i.e. TYPE_RGB_8
- cmsFormatterDirection Dir,
- cmsUInt32Number dwFlags);
+CMSCHECKPOINT cmsFormatter CMSEXPORT _cmsGetFormatter(cmsContext ContextID,
+ cmsUInt32Number Type, // Specific type, i.e. TYPE_RGB_8
+ cmsFormatterDirection Dir,
+ cmsUInt32Number dwFlags);
#ifndef CMS_NO_HALF_SUPPORT
// Half float
-cmsFloat32Number _cmsHalf2Float(cmsUInt16Number h);
-cmsUInt16Number _cmsFloat2Half(cmsFloat32Number flt);
+CMSCHECKPOINT cmsFloat32Number CMSEXPORT _cmsHalf2Float(cmsUInt16Number h);
+CMSCHECKPOINT cmsUInt16Number CMSEXPORT _cmsFloat2Half(cmsFloat32Number flt);
#endif
diff --git a/src/java.desktop/share/native/liblcms/lcms2_plugin.h b/src/java.desktop/share/native/liblcms/lcms2_plugin.h
index aff3b48d7ec..6fe59c39665 100644
--- a/src/java.desktop/share/native/liblcms/lcms2_plugin.h
+++ b/src/java.desktop/share/native/liblcms/lcms2_plugin.h
@@ -30,7 +30,7 @@
//---------------------------------------------------------------------------------
//
// Little Color Management System
-// Copyright (c) 1998-2016 Marti Maria Saguer
+// Copyright (c) 1998-2017 Marti Maria Saguer
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the "Software"),
@@ -347,7 +347,7 @@ typedef struct {
// Parametric curves. A negative type means same function but analytically inverted. Max. number of params is 10
-// Evaluator callback for user-suplied parametric curves. May implement more than one type
+// Evaluator callback for user-supplied parametric curves. May implement more than one type
typedef cmsFloat64Number (* cmsParametricCurveEvaluator)(cmsInt32Number Type, const cmsFloat64Number Params[10], cmsFloat64Number R);
// Plug-in may implement an arbitrary number of parametric curves
@@ -457,7 +457,7 @@ typedef struct {
cmsUInt32Number nSupportedTypes; // In how many types this tag can come (MAX_TYPES_IN_LCMS_PLUGIN maximum)
cmsTagTypeSignature SupportedTypes[MAX_TYPES_IN_LCMS_PLUGIN];
- // For writting
+ // For writing
cmsTagTypeSignature (* DecideType)(cmsFloat64Number ICCVersion, const void *Data);
} cmsTagDescriptor;
diff --git a/src/java.desktop/share/native/libmlib_image/mlib_ImageAffine.c b/src/java.desktop/share/native/libmlib_image/mlib_ImageAffine.c
index 84d8a147aa3..e614d5e3410 100644
--- a/src/java.desktop/share/native/libmlib_image/mlib_ImageAffine.c
+++ b/src/java.desktop/share/native/libmlib_image/mlib_ImageAffine.c
@@ -299,7 +299,7 @@ mlib_status mlib_ImageAffine_alltypes(mlib_image *dst,
}
/***************************************************************/
-mlib_status mlib_ImageAffine(mlib_image *dst,
+JNIEXPORT mlib_status JNICALL mlib_ImageAffine(mlib_image *dst,
const mlib_image *src,
const mlib_d64 *mtx,
mlib_filter filter,
diff --git a/src/java.desktop/share/native/libmlib_image/mlib_ImageConvKernelConvert.c b/src/java.desktop/share/native/libmlib_image/mlib_ImageConvKernelConvert.c
index 6e4fdbdca5b..ff62e7b788e 100644
--- a/src/java.desktop/share/native/libmlib_image/mlib_ImageConvKernelConvert.c
+++ b/src/java.desktop/share/native/libmlib_image/mlib_ImageConvKernelConvert.c
@@ -78,7 +78,7 @@
#endif /* __sparc */
/***************************************************************/
-mlib_status mlib_ImageConvKernelConvert(mlib_s32 *ikernel,
+JNIEXPORT mlib_status JNICALL mlib_ImageConvKernelConvert(mlib_s32 *ikernel,
mlib_s32 *iscale,
const mlib_d64 *fkernel,
mlib_s32 m,
diff --git a/src/java.desktop/share/native/libmlib_image/mlib_ImageConvMxN.c b/src/java.desktop/share/native/libmlib_image/mlib_ImageConvMxN.c
index 3c7e835cf62..2206ad11faf 100644
--- a/src/java.desktop/share/native/libmlib_image/mlib_ImageConvMxN.c
+++ b/src/java.desktop/share/native/libmlib_image/mlib_ImageConvMxN.c
@@ -90,7 +90,7 @@
#include "mlib_ImageConvEdge.h"
/***************************************************************/
-mlib_status mlib_ImageConvMxN(mlib_image *dst,
+JNIEXPORT mlib_status JNICALL mlib_ImageConvMxN(mlib_image *dst,
const mlib_image *src,
const mlib_s32 *kernel,
mlib_s32 m,
diff --git a/src/java.desktop/share/native/libmlib_image/mlib_c_ImageLookUp.c b/src/java.desktop/share/native/libmlib_image/mlib_c_ImageLookUp.c
index d86d0b17e9f..c98c3ed5407 100644
--- a/src/java.desktop/share/native/libmlib_image/mlib_c_ImageLookUp.c
+++ b/src/java.desktop/share/native/libmlib_image/mlib_c_ImageLookUp.c
@@ -78,7 +78,7 @@
#include "mlib_c_ImageLookUp.h"
/***************************************************************/
-mlib_status mlib_ImageLookUp(mlib_image *dst,
+JNIEXPORT mlib_status JNICALL mlib_ImageLookUp(mlib_image *dst,
const mlib_image *src,
const void **table)
{
diff --git a/src/java.desktop/share/native/libsplashscreen/splashscreen_impl.h b/src/java.desktop/share/native/libsplashscreen/splashscreen_impl.h
index a10ade1b8cd..b6743af1e65 100644
--- a/src/java.desktop/share/native/libsplashscreen/splashscreen_impl.h
+++ b/src/java.desktop/share/native/libsplashscreen/splashscreen_impl.h
@@ -132,9 +132,6 @@ void SplashDonePlatform(Splash * splash);
unsigned SplashTime();
char* SplashConvertStringAlloc(const char* in, int *size);
-jboolean SplashGetScaledImageName(const char* jarName,
- const char* fileName, float *scaleFactor,
- char *scaleImageName, const size_t scaledImageNameLength);
void SplashLock(Splash * splash);
void SplashUnlock(Splash * splash);
@@ -157,8 +154,7 @@ void SplashDone(Splash * splash);
void SplashUpdateScreenData(Splash * splash);
void SplashCleanup(Splash * splash);
-void SplashSetScaleFactor(float scaleFactor);
-int SplashGetScaledImgNameMaxPstfixLen(const char *fileName);
+
void cleanUp(char *fName, char *xName, char *pctName, float *scaleFactor);
jboolean GetScaledImageName(const char *fileName, char *scaledImgName,
float *scaleFactor, const size_t scaledImageLength);
diff --git a/src/java.desktop/unix/classes/sun/awt/X11/XMouseInfoPeer.java b/src/java.desktop/unix/classes/sun/awt/X11/XMouseInfoPeer.java
index 09c9450a176..f4c46c2766d 100644
--- a/src/java.desktop/unix/classes/sun/awt/X11/XMouseInfoPeer.java
+++ b/src/java.desktop/unix/classes/sun/awt/X11/XMouseInfoPeer.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -25,16 +25,16 @@
package sun.awt.X11;
+import java.awt.GraphicsDevice;
+import java.awt.GraphicsEnvironment;
import java.awt.Point;
import java.awt.Window;
-import java.awt.GraphicsEnvironment;
-import java.awt.GraphicsDevice;
import java.awt.peer.MouseInfoPeer;
-import sun.awt.X11GraphicsDevice;
import sun.awt.AWTAccessor;
+import sun.awt.X11GraphicsDevice;
-public class XMouseInfoPeer implements MouseInfoPeer {
+public final class XMouseInfoPeer implements MouseInfoPeer {
/**
* Package-private constructor to prevent instantiation.
@@ -85,13 +85,14 @@ public int fillPointWithCoords(Point point) {
@SuppressWarnings("deprecation")
public boolean isWindowUnderMouse(Window w) {
-
- long display = XToolkit.getDisplay();
-
- // java.awt.Component.findUnderMouseInWindow checks that
- // the peer is non-null by checking that the component
- // is showing.
+ if (w == null) {
+ return false;
+ }
XWindow peer = AWTAccessor.getComponentAccessor().getPeer(w);
+ if (peer == null) {
+ return false;
+ }
+ long display = XToolkit.getDisplay();
long contentWindow = peer.getContentWindow();
long parent = XlibUtil.getParentWindow(contentWindow);
diff --git a/src/java.desktop/windows/classes/sun/awt/windows/ThemeReader.java b/src/java.desktop/windows/classes/sun/awt/windows/ThemeReader.java
index 26751e953ba..167d4d5b910 100644
--- a/src/java.desktop/windows/classes/sun/awt/windows/ThemeReader.java
+++ b/src/java.desktop/windows/classes/sun/awt/windows/ThemeReader.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -61,6 +61,7 @@ public final class ThemeReader {
private static final Lock readLock = readWriteLock.readLock();
private static final Lock writeLock = readWriteLock.writeLock();
private static volatile boolean valid = false;
+ private static volatile boolean isThemed;
static volatile boolean xpStyleEnabled;
@@ -70,7 +71,17 @@ static void flush() {
valid = false;
}
- public static native boolean isThemed();
+ private static native boolean initThemes();
+
+ public static boolean isThemed() {
+ writeLock.lock();
+ try {
+ isThemed = initThemes();
+ return isThemed;
+ } finally {
+ writeLock.unlock();
+ }
+ }
public static boolean isXPStyleEnabled() {
return xpStyleEnabled;
@@ -98,6 +109,9 @@ private static Long getThemeImpl(String widget) {
// returns theme value
// this method should be invoked with readLock locked
private static Long getTheme(String widget) {
+ if (!isThemed) {
+ throw new IllegalStateException("Themes are not loaded");
+ }
if (!valid) {
readLock.unlock();
writeLock.lock();
diff --git a/src/java.desktop/windows/classes/sun/awt/windows/WToolkit.java b/src/java.desktop/windows/classes/sun/awt/windows/WToolkit.java
index 82ea9d709b9..812ea7a2985 100644
--- a/src/java.desktop/windows/classes/sun/awt/windows/WToolkit.java
+++ b/src/java.desktop/windows/classes/sun/awt/windows/WToolkit.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -47,6 +47,7 @@
import sun.awt.AWTAutoShutdown;
import sun.awt.AWTPermissions;
import sun.awt.AppContext;
+import sun.awt.DisplayChangedListener;
import sun.awt.LightweightFrame;
import sun.awt.SunToolkit;
import sun.awt.util.ThreadGroupUtils;
@@ -802,9 +803,10 @@ public Dimension getBestCursorSize(int preferredWidth, int preferredHeight) {
public native int getMaximumCursorColors();
static void paletteChanged() {
- ((Win32GraphicsEnvironment)GraphicsEnvironment
- .getLocalGraphicsEnvironment())
- .paletteChanged();
+ Object lge = GraphicsEnvironment.getLocalGraphicsEnvironment();
+ if (lge instanceof DisplayChangedListener) {
+ ((DisplayChangedListener) lge).paletteChanged();
+ }
}
/*
@@ -816,9 +818,10 @@ public static void displayChanged() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
- ((Win32GraphicsEnvironment)GraphicsEnvironment
- .getLocalGraphicsEnvironment())
- .displayChanged();
+ Object lge = GraphicsEnvironment.getLocalGraphicsEnvironment();
+ if (lge instanceof DisplayChangedListener) {
+ ((DisplayChangedListener) lge).displayChanged();
+ }
}
});
}
diff --git a/src/java.desktop/windows/native/libawt/windows/MouseInfo.cpp b/src/java.desktop/windows/native/libawt/windows/MouseInfo.cpp
index 90cef5303cf..37fbc914519 100644
--- a/src/java.desktop/windows/native/libawt/windows/MouseInfo.cpp
+++ b/src/java.desktop/windows/native/libawt/windows/MouseInfo.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -48,6 +48,7 @@ Java_sun_awt_windows_WMouseInfoPeer_isWindowUnderMouse(JNIEnv *env, jclass cls,
}
jobject winPeer = AwtObject::GetPeerForTarget(env, window);
+ CHECK_NULL_RETURN(winPeer, JNI_FALSE);
PDATA pData;
pData = JNI_GET_PDATA(winPeer);
env->DeleteLocalRef(winPeer);
diff --git a/src/java.desktop/windows/native/libawt/windows/ThemeReader.cpp b/src/java.desktop/windows/native/libawt/windows/ThemeReader.cpp
index c48ae8fbe31..99ca918a500 100644
--- a/src/java.desktop/windows/native/libawt/windows/ThemeReader.cpp
+++ b/src/java.desktop/windows/native/libawt/windows/ThemeReader.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -232,7 +232,7 @@ BOOL InitThemes() {
return FALSE;
}
-JNIEXPORT jboolean JNICALL Java_sun_awt_windows_ThemeReader_isThemed
+JNIEXPORT jboolean JNICALL Java_sun_awt_windows_ThemeReader_initThemes
(JNIEnv *env, jclass klass) {
static BOOL TryLoadingThemeLib = FALSE;
static BOOL Themed = FALSE;
diff --git a/src/java.desktop/windows/native/libsplashscreen/splashscreen_sys.c b/src/java.desktop/windows/native/libsplashscreen/splashscreen_sys.c
index bf516068f8d..83a7fb36e3b 100644
--- a/src/java.desktop/windows/native/libsplashscreen/splashscreen_sys.c
+++ b/src/java.desktop/windows/native/libsplashscreen/splashscreen_sys.c
@@ -574,7 +574,7 @@ SplashReconfigure(Splash * splash)
PostMessage(splash->hWnd, WM_SPLASHRECONFIGURE, 0, 0);
}
-jboolean
+JNIEXPORT jboolean JNICALL
SplashGetScaledImageName(const char* jarName, const char* fileName,
float *scaleFactor, char *scaleImageName,
const size_t scaledImageLength)
diff --git a/src/java.instrument/share/classes/sun/instrument/InstrumentationImpl.java b/src/java.instrument/share/classes/sun/instrument/InstrumentationImpl.java
index 5cf0c21361f..3241c086d90 100644
--- a/src/java.instrument/share/classes/sun/instrument/InstrumentationImpl.java
+++ b/src/java.instrument/share/classes/sun/instrument/InstrumentationImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -161,6 +161,9 @@ public boolean isModifiableModule(Module module) {
throw new UnsupportedOperationException(
"retransformClasses is not supported in this environment");
}
+ if (classes.length == 0) {
+ return; // no-op
+ }
retransformClasses0(mNativeAgent, classes);
}
diff --git a/src/java.instrument/share/native/libinstrument/Reentrancy.c b/src/java.instrument/share/native/libinstrument/Reentrancy.c
index 8cb69172bf7..2d923e23848 100644
--- a/src/java.instrument/share/native/libinstrument/Reentrancy.c
+++ b/src/java.instrument/share/native/libinstrument/Reentrancy.c
@@ -90,7 +90,7 @@ assertTLSValue( jvmtiEnv * jvmtienv,
jthread thread,
const void * expected) {
jvmtiError error;
- void * test = (void *) 0x99999999UL;
+ void * test = (void *) 0x99999999ULL;
/* now check if we do a fetch we get what we wrote */
error = (*jvmtienv)->GetThreadLocalStorage(
diff --git a/src/java.management/share/classes/javax/management/openmbean/TabularDataSupport.java b/src/java.management/share/classes/javax/management/openmbean/TabularDataSupport.java
index bcbd176266e..c46e0edfd83 100644
--- a/src/java.management/share/classes/javax/management/openmbean/TabularDataSupport.java
+++ b/src/java.management/share/classes/javax/management/openmbean/TabularDataSupport.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -45,6 +45,7 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
+import jdk.internal.misc.SharedSecrets;
// jmx import
//
@@ -922,6 +923,8 @@ private void readObject(ObjectInputStream in)
throws IOException, ClassNotFoundException {
in.defaultReadObject();
List tmpNames = tabularType.getIndexNames();
- indexNamesArray = tmpNames.toArray(new String[tmpNames.size()]);
+ int size = tmpNames.size();
+ SharedSecrets.getJavaObjectInputStreamAccess().checkArray(in, String[].class, size);
+ indexNamesArray = tmpNames.toArray(new String[size]);
}
}
diff --git a/src/java.management/share/classes/module-info.java b/src/java.management/share/classes/module-info.java
index 26f34ba21b9..2b2054cb724 100644
--- a/src/java.management/share/classes/module-info.java
+++ b/src/java.management/share/classes/module-info.java
@@ -64,8 +64,7 @@
exports sun.management.counter.perf to
jdk.management.agent;
exports sun.management.spi to
- jdk.management,
- jdk.internal.vm.compiler.management;
+ jdk.management;
uses javax.management.remote.JMXConnectorProvider;
uses javax.management.remote.JMXConnectorServerProvider;
diff --git a/src/java.management/share/classes/sun/management/MemoryPoolImpl.java b/src/java.management/share/classes/sun/management/MemoryPoolImpl.java
index 881207ae63e..227d19947db 100644
--- a/src/java.management/share/classes/sun/management/MemoryPoolImpl.java
+++ b/src/java.management/share/classes/sun/management/MemoryPoolImpl.java
@@ -55,10 +55,10 @@ class MemoryPoolImpl implements MemoryPoolMXBean {
private long usageThreshold;
private long collectionThreshold;
- private boolean usageSensorRegistered;
- private boolean gcSensorRegistered;
- private Sensor usageSensor;
- private Sensor gcSensor;
+ private boolean usageSensorRegistered; // VM-initialized to false
+ private boolean gcSensorRegistered; // VM-initialized to false
+ private final Sensor usageSensor;
+ private final Sensor gcSensor;
MemoryPoolImpl(String name, boolean isHeap, long usageThreshold,
long gcThreshold) {
@@ -72,8 +72,6 @@ class MemoryPoolImpl implements MemoryPoolMXBean {
this.collectionThresholdSupported = (gcThreshold >= 0);
this.usageSensor = new PoolSensor(this, name + " usage sensor");
this.gcSensor = new CollectionSensor(this, name + " collection sensor");
- this.usageSensorRegistered = false;
- this.gcSensorRegistered = false;
}
public String getName() {
@@ -290,7 +288,7 @@ public boolean isCollectionUsageThresholdSupported() {
* unless the memory usage has returned below the threshold.
*/
class PoolSensor extends Sensor {
- MemoryPoolImpl pool;
+ final MemoryPoolImpl pool;
PoolSensor(MemoryPoolImpl pool, String name) {
super(name);
@@ -316,10 +314,10 @@ void clearAction() {
* when the memory usage of a memory pool after GC is crossing
* the collection threshold.
* The VM will trigger this sensor in subsequent crossing
- * regardless if the memory usage has changed siince the previous GC.
+ * regardless if the memory usage has changed since the previous GC.
*/
class CollectionSensor extends Sensor {
- MemoryPoolImpl pool;
+ final MemoryPoolImpl pool;
CollectionSensor(MemoryPoolImpl pool, String name) {
super(name);
this.pool = pool;
diff --git a/src/java.management/share/classes/sun/management/Sensor.java b/src/java.management/share/classes/sun/management/Sensor.java
index c2da61d174c..58a7e5142df 100644
--- a/src/java.management/share/classes/sun/management/Sensor.java
+++ b/src/java.management/share/classes/sun/management/Sensor.java
@@ -48,10 +48,10 @@
*/
public abstract class Sensor {
- private Object lock;
- private String name;
- private long count;
- private boolean on;
+ private final Object lock = new Object();
+ private final String name;
+ private long count; // VM-initialized to 0
+ private boolean on; // VM-initialized to false
/**
* Constructs a {@code Sensor} object.
@@ -60,9 +60,6 @@ public abstract class Sensor {
*/
public Sensor(String name) {
this.name = name;
- this.count = 0;
- this.on = false;
- this.lock = new Object();
}
/**
diff --git a/src/jdk.incubator.httpclient/share/classes/jdk/incubator/http/HttpClient.java b/src/java.net.http/share/classes/java/net/http/HttpClient.java
similarity index 57%
rename from src/jdk.incubator.httpclient/share/classes/jdk/incubator/http/HttpClient.java
rename to src/java.net.http/share/classes/java/net/http/HttpClient.java
index d537c805d89..47c7ba0c28b 100644
--- a/src/jdk.incubator.httpclient/share/classes/jdk/incubator/http/HttpClient.java
+++ b/src/java.net.http/share/classes/java/net/http/HttpClient.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -23,7 +23,7 @@
* questions.
*/
-package jdk.incubator.http;
+package java.net.http;
import java.io.IOException;
import java.net.Authenticator;
@@ -31,7 +31,9 @@
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.ProxySelector;
-import java.net.URI;
+import java.net.URLPermission;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
@@ -39,19 +41,89 @@
import java.util.concurrent.ThreadFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLParameters;
+import java.net.http.HttpResponse.BodyHandler;
+import java.net.http.HttpResponse.PushPromiseHandler;
+import jdk.internal.net.http.HttpClientBuilderImpl;
/**
- * A container for configuration information common to multiple {@link
- * HttpRequest}s. All requests are sent through a {@code HttpClient}.
- * {@Incubating}
+ * An HTTP Client.
*
- * {@code HttpClient}s are immutable and created from a builder returned
- * from {@link HttpClient#newBuilder()}. Request builders are created by calling
- * {@link HttpRequest#newBuilder() }.
- *
- * See {@link HttpRequest} for examples of usage of this API.
+ *
An {@code HttpClient} can be used to send {@linkplain HttpRequest
+ * requests} and retrieve their {@linkplain HttpResponse responses}. An {@code
+ * HttpClient} is created through a {@link HttpClient#newBuilder() builder}. The
+ * builder can be used to configure per-client state, like: the preferred
+ * protocol version ( HTTP/1.1 or HTTP/2 ), whether to follow redirects, a
+ * proxy, an authenticator, etc. Once built, an {@code HttpClient} is immutable,
+ * and can be used to send multiple requests.
*
- * @since 9
+ *
An {@code HttpClient} provides configuration information, and resource
+ * sharing, for all requests send through it.
+ *
+ *
A {@link BodyHandler BodyHandler} must be supplied for each {@link
+ * HttpRequest} sent. The {@code BodyHandler} determines how to handle the
+ * response body, if any. Once an {@link HttpResponse} is received, the
+ * headers, response code, and body (typically) are available. Whether the
+ * response body bytes have been read or not depends on the type, {@code T}, of
+ * the response body.
+ *
+ *
Requests can be sent either synchronously or asynchronously:
+ *
+ * - {@link HttpClient#send(HttpRequest, BodyHandler)} blocks
+ * until the request has been sent and the response has been received.
+ *
+ * - {@link HttpClient#sendAsync(HttpRequest, BodyHandler)} sends the
+ * request and receives the response asynchronously. The {@code sendAsync}
+ * method returns immediately with a {@link CompletableFuture
+ * CompletableFuture}<{@link HttpResponse}>. The {@code
+ * CompletableFuture} completes when the response becomes available. The
+ * returned {@code CompletableFuture} can be combined in different ways to
+ * declare dependencies among several asynchronous tasks.
+ *
+ *
+ * Synchronous Example
+ *
{@code HttpClient client = HttpClient.newBuilder()
+ * .version(Version.HTTP_1_1)
+ * .followRedirects(Redirect.NORMAL)
+ * .proxy(ProxySelector.of(new InetSocketAddress("proxy.example.com", 80)))
+ * .authenticator(Authenticator.getDefault())
+ * .build();
+ * HttpResponse response = client.send(request, BodyHandlers.ofString());
+ * System.out.println(response.statusCode());
+ * System.out.println(response.body()); }
+ *
+ * Asynchronous Example
+ *
{@code HttpRequest request = HttpRequest.newBuilder()
+ * .uri(URI.create("https://foo.com/"))
+ * .timeout(Duration.ofMinutes(1))
+ * .header("Content-Type", "application/json")
+ * .POST(BodyPublishers.ofFile(Paths.get("file.json")))
+ * .build();
+ * client.sendAsync(request, BodyHandlers.ofString())
+ * .thenApply(HttpResponse::body)
+ * .thenAccept(System.out::println); }
+ *
+ * Security checks
+ *
+ *
If a security manager is present then security checks are performed by
+ * the HTTP Client's sending methods. An appropriate {@link URLPermission} is
+ * required to access the destination server, and proxy server if one has
+ * been configured. The form of the {@code URLPermission} required to access a
+ * proxy has a {@code method} parameter of {@code "CONNECT"} (for all kinds of
+ * proxying) and a {@code URL} string of the form {@code "socket://host:port"}
+ * where host and port specify the proxy's address.
+ *
+ * @implNote If an explicit {@linkplain HttpClient.Builder#executor(Executor)
+ * executor} has not been set for an {@code HttpClient}, and a security manager
+ * has been installed, then the default executor will execute asynchronous and
+ * dependent tasks in a context that is granted no permissions. Custom
+ * {@linkplain HttpRequest.BodyPublisher request body publishers}, {@linkplain
+ * HttpResponse.BodyHandler response body handlers}, {@linkplain
+ * HttpResponse.BodySubscriber response body subscribers}, and {@linkplain
+ * WebSocket.Listener WebSocket Listeners}, if executing operations that require
+ * privileges, should do so within an appropriate {@linkplain
+ * AccessController#doPrivileged(PrivilegedAction) privileged context}.
+ *
+ * @since 11
*/
public abstract class HttpClient {
@@ -61,7 +133,7 @@ public abstract class HttpClient {
protected HttpClient() {}
/**
- * Returns a new HttpClient with default settings.
+ * Returns a new {@code HttpClient} with default settings.
*
*
Equivalent to {@code newBuilder().build()}.
*
@@ -87,38 +159,34 @@ public static HttpClient newHttpClient() {
/**
* Creates a new {@code HttpClient} builder.
*
- * @return a {@code HttpClient.Builder}
+ * @return an {@code HttpClient.Builder}
*/
public static Builder newBuilder() {
return new HttpClientBuilderImpl();
}
/**
- * A builder of immutable {@link HttpClient}s.
- * {@Incubating}
+ * A builder of {@linkplain HttpClient HTTP Clients}.
*
- *
Builders are created by invoking {@linkplain HttpClient#newBuilder()
+ *
Builders are created by invoking {@link HttpClient#newBuilder()
* newBuilder}. Each of the setter methods modifies the state of the builder
* and returns the same instance. Builders are not thread-safe and should not be
* used concurrently from multiple threads without external synchronization.
*
- * @since 9
+ * @since 11
*/
- public abstract static class Builder {
+ public interface Builder {
/**
* A proxy selector that always return {@link Proxy#NO_PROXY} implying
* a direct connection.
- * This is a convenience object that can be passed to {@link #proxy(ProxySelector)}
- * in order to build an instance of {@link HttpClient} that uses no
- * proxy.
+ *
+ *
This is a convenience object that can be passed to
+ * {@link #proxy(ProxySelector)} in order to build an instance of
+ * {@link HttpClient} that uses no proxy.
*/
public static final ProxySelector NO_PROXY = ProxySelector.of(null);
- /**
- * Creates a Builder.
- */
- protected Builder() {}
/**
* Sets a cookie handler.
@@ -126,7 +194,7 @@ protected Builder() {}
* @param cookieHandler the cookie handler
* @return this builder
*/
- public abstract Builder cookieHandler(CookieHandler cookieHandler);
+ public Builder cookieHandler(CookieHandler cookieHandler);
/**
* Sets an {@code SSLContext}.
@@ -140,7 +208,7 @@ protected Builder() {}
* @param sslContext the SSLContext
* @return this builder
*/
- public abstract Builder sslContext(SSLContext sslContext);
+ public Builder sslContext(SSLContext sslContext);
/**
* Sets an {@code SSLParameters}.
@@ -157,7 +225,7 @@ protected Builder() {}
* @param sslParameters the SSLParameters
* @return this builder
*/
- public abstract Builder sslParameters(SSLParameters sslParameters);
+ public Builder sslParameters(SSLParameters sslParameters);
/**
* Sets the executor to be used for asynchronous and dependent tasks.
@@ -175,7 +243,7 @@ protected Builder() {}
* @param executor the Executor
* @return this builder
*/
- public abstract Builder executor(Executor executor);
+ public Builder executor(Executor executor);
/**
* Specifies whether requests will automatically follow redirects issued
@@ -188,7 +256,7 @@ protected Builder() {}
* @param policy the redirection policy
* @return this builder
*/
- public abstract Builder followRedirects(Redirect policy);
+ public Builder followRedirects(Redirect policy);
/**
* Requests a specific HTTP protocol version where possible.
@@ -205,10 +273,14 @@ protected Builder() {}
* will use HTTP/2. If the upgrade fails, then the response will be
* handled using HTTP/1.1
*
+ * @implNote Constraints may also affect the selection of protocol version.
+ * For example, if HTTP/2 is requested through a proxy, and if the implementation
+ * does not support this mode, then HTTP/1.1 may be used
+ *
* @param version the requested HTTP protocol version
* @return this builder
*/
- public abstract Builder version(HttpClient.Version version);
+ public Builder version(HttpClient.Version version);
/**
* Sets the default priority for any HTTP/2 requests sent from this
@@ -219,51 +291,53 @@ protected Builder() {}
* @return this builder
* @throws IllegalArgumentException if the given priority is out of range
*/
- public abstract Builder priority(int priority);
+ public Builder priority(int priority);
/**
* Sets a {@link java.net.ProxySelector}.
*
- * @apiNote {@link ProxySelector#of(InetSocketAddress)}
+ * @apiNote {@link ProxySelector#of(InetSocketAddress) ProxySelector::of}
* provides a {@code ProxySelector} which uses a single proxy for all
* requests. The system-wide proxy selector can be retrieved by
* {@link ProxySelector#getDefault()}.
*
* @implNote
- * If this method is not invoked prior to {@linkplain #build()
- * building}, then newly built clients will use the {@linkplain
- * ProxySelector#getDefault() default proxy selector}, which
- * is normally adequate for client applications. This default
- * behavior can be turned off by supplying an explicit proxy
- * selector to this method, such as {@link #NO_PROXY} or one
- * returned by {@link ProxySelector#of(InetSocketAddress)},
- * before calling {@link #build()}.
+ * If this method is not invoked prior to {@linkplain #build() building},
+ * then newly built clients will use the {@linkplain
+ * ProxySelector#getDefault() default proxy selector}, which is usually
+ * adequate for client applications. The default proxy selector supports
+ * a set of system properties related to
+ *
+ * proxy settings. This default behavior can be disabled by
+ * supplying an explicit proxy selector, such as {@link #NO_PROXY} or
+ * one returned by {@link ProxySelector#of(InetSocketAddress)
+ * ProxySelector::of}, before {@linkplain #build() building}.
*
- * @param selector the ProxySelector
+ * @param proxySelector the ProxySelector
* @return this builder
*/
- public abstract Builder proxy(ProxySelector selector);
+ public Builder proxy(ProxySelector proxySelector);
/**
* Sets an authenticator to use for HTTP authentication.
*
- * @param a the Authenticator
+ * @param authenticator the Authenticator
* @return this builder
*/
- public abstract Builder authenticator(Authenticator a);
+ public Builder authenticator(Authenticator authenticator);
/**
* Returns a new {@link HttpClient} built from the current state of this
* builder.
*
- * @return this builder
+ * @return a new {@code HttpClient}
*/
- public abstract HttpClient build();
+ public HttpClient build();
}
/**
- * Returns an {@code Optional} containing this client's {@linkplain
+ * Returns an {@code Optional} containing this client's {@link
* CookieHandler}. If no {@code CookieHandler} was set in this client's
* builder, then the {@code Optional} is empty.
*
@@ -286,7 +360,7 @@ protected Builder() {}
* builder, then the {@code Optional} is empty.
*
*
Even though this method may return an empty optional, the {@code
- * HttpClient} may still have an non-exposed {@linkplain
+ * HttpClient} may still have a non-exposed {@linkplain
* Builder#proxy(ProxySelector) default proxy selector} that is
* used for sending HTTP requests.
*
@@ -326,15 +400,19 @@ protected Builder() {}
public abstract Optional authenticator();
/**
- * Returns the HTTP protocol version requested for this client. The default
+ * Returns the preferred HTTP protocol version for this client. The default
* value is {@link HttpClient.Version#HTTP_2}
*
+ * @implNote Constraints may also affect the selection of protocol version.
+ * For example, if HTTP/2 is requested through a proxy, and if the
+ * implementation does not support this mode, then HTTP/1.1 may be used
+ *
* @return the HTTP protocol version requested
*/
public abstract HttpClient.Version version();
/**
- * Returns an {@code Optional} containing this client's {@linkplain
+ * Returns an {@code Optional} containing this client's {@link
* Executor}. If no {@code Executor} was set in the client's builder,
* then the {@code Optional} is empty.
*
@@ -349,9 +427,8 @@ protected Builder() {}
/**
* The HTTP protocol version.
- * {@Incubating}
*
- * @since 9
+ * @since 11
*/
public enum Version {
@@ -367,17 +444,25 @@ public enum Version {
}
/**
- * Defines automatic redirection policy.
- * {@Incubating}
+ * Defines the automatic redirection policy.
*
- * This is checked whenever a {@code 3XX} response code is received. If
- * redirection does not happen automatically then the response is returned
- * to the user, where it can be handled manually.
+ *
The automatic redirection policy is checked whenever a {@code 3XX}
+ * response code is received. If redirection does not happen automatically,
+ * then the response, containing the {@code 3XX} response code, is returned,
+ * where it can be handled manually.
*
- *
{@code Redirect} policy is set via the {@link
- * HttpClient.Builder#followRedirects(HttpClient.Redirect)} method.
+ *
{@code Redirect} policy is set via the {@linkplain
+ * HttpClient.Builder#followRedirects(Redirect) Builder.followRedirects}
+ * method.
*
- * @since 9
+ * @implNote When automatic redirection occurs, the request method of the
+ * redirected request may be modified depending on the specific {@code 30X}
+ * status code, as specified in
+ * RFC 7231. In addition, the {@code 301} and {@code 302} status codes
+ * cause a {@code POST} request to be converted to a {@code GET} in the
+ * redirected request.
+ *
+ * @since 11
*/
public enum Redirect {
@@ -392,15 +477,9 @@ public enum Redirect {
ALWAYS,
/**
- * Redirect to same protocol only. Redirection may occur from HTTP URLs
- * to other HTTP URLs, and from HTTPS URLs to other HTTPS URLs.
+ * Always redirect, except from HTTPS URLs to HTTP URLs.
*/
- SAME_PROTOCOL,
-
- /**
- * Redirect always except from HTTPS URLs to HTTP URLs.
- */
- SECURE
+ NORMAL
}
/**
@@ -410,94 +489,96 @@ public enum Redirect {
* handler ).
*
* @param the response body type
- * @param req the request
+ * @param request the request
* @param responseBodyHandler the response body handler
- * @return the response body
+ * @return the response
* @throws IOException if an I/O error occurs when sending or receiving
* @throws InterruptedException if the operation is interrupted
- * @throws IllegalArgumentException if the request method is not supported
+ * @throws IllegalArgumentException if the {@code request} argument is not
+ * a request that could have been validly built as specified by {@link
+ * HttpRequest.Builder HttpRequest.Builder}.
* @throws SecurityException If a security manager has been installed
* and it denies {@link java.net.URLPermission access} to the
* URL in the given request, or proxy if one is configured.
- * See HttpRequest for further information about
- * security checks.
+ * See security checks for further
+ * information.
*/
public abstract HttpResponse
- send(HttpRequest req, HttpResponse.BodyHandler responseBodyHandler)
+ send(HttpRequest request, HttpResponse.BodyHandler responseBodyHandler)
throws IOException, InterruptedException;
/**
- * Sends the given request asynchronously using this client and the given
- * response handler.
+ * Sends the given request asynchronously using this client with the given
+ * response body handler.
*
- * The returned completable future completes exceptionally with:
- *
- * - {@link IOException} - if an I/O error occurs when sending or receiving
- * - {@link IllegalArgumentException} - if the request method is not supported
- * - {@link SecurityException} - If a security manager has been installed
- * and it denies {@link java.net.URLPermission access} to the
- * URL in the given request, or proxy if one is configured.
- * See HttpRequest for further information about
- * security checks.
- *
+ * Equivalent to: {@code sendAsync(request, responseBodyHandler, null)}.
*
* @param the response body type
- * @param req the request
+ * @param request the request
* @param responseBodyHandler the response body handler
* @return a {@code CompletableFuture>}
+ * @throws IllegalArgumentException if the {@code request} argument is not
+ * a request that could have been validly built as specified by {@link
+ * HttpRequest.Builder HttpRequest.Builder}.
*/
public abstract CompletableFuture>
- sendAsync(HttpRequest req, HttpResponse.BodyHandler responseBodyHandler);
+ sendAsync(HttpRequest request,
+ BodyHandler responseBodyHandler);
/**
- * Sends the given request asynchronously using this client and the given
- * multi response handler.
+ * Sends the given request asynchronously using this client with the given
+ * response body handler and push promise handler.
+ *
+ * The returned completable future, if completed successfully, completes
+ * with an {@link HttpResponse}{@code } that contains the response status,
+ * headers, and body ( as handled by given response body handler ).
+ *
+ * {@linkplain PushPromiseHandler Push promises} received, if any, are
+ * handled by the given {@code pushPromiseHandler}. A {@code null} valued
+ * {@code pushPromiseHandler} rejects any push promises.
*
*
The returned completable future completes exceptionally with:
*
* - {@link IOException} - if an I/O error occurs when sending or receiving
- * - {@link IllegalArgumentException} - if the request method is not supported
* - {@link SecurityException} - If a security manager has been installed
* and it denies {@link java.net.URLPermission access} to the
* URL in the given request, or proxy if one is configured.
- * See HttpRequest for further information about
- * security checks.
+ * See security checks for further
+ * information.
*
*
- * @param a type representing the aggregated results
- * @param a type representing all of the response bodies
- * @param req the request
- * @param multiSubscriber the multiSubscriber for the request
- * @return a {@code CompletableFuture}
+ * @param the response body type
+ * @param request the request
+ * @param responseBodyHandler the response body handler
+ * @param pushPromiseHandler push promise handler, may be null
+ * @return a {@code CompletableFuture>}
+ * @throws IllegalArgumentException if the {@code request} argument is not
+ * a request that could have been validly built as specified by {@link
+ * HttpRequest.Builder HttpRequest.Builder}.
*/
- public abstract CompletableFuture
- sendAsync(HttpRequest req, HttpResponse.MultiSubscriber multiSubscriber);
+ public abstract CompletableFuture>
+ sendAsync(HttpRequest request,
+ BodyHandler responseBodyHandler,
+ PushPromiseHandler pushPromiseHandler);
/**
* Creates a new {@code WebSocket} builder (optional operation).
*
* Example
- *
{@code
- * HttpClient client = HttpClient.newHttpClient();
- * CompletableFuture ws = client.newWebSocketBuilder()
- * .buildAsync(URI.create("ws://websocket.example.com"), listener);
- * }
+ * {@code HttpClient client = HttpClient.newHttpClient();
+ * CompletableFuture ws = client.newWebSocketBuilder()
+ * .buildAsync(URI.create("ws://websocket.example.com"), listener); }
*
* Finer control over the WebSocket Opening Handshake can be achieved
* by using a custom {@code HttpClient}.
*
*
Example
- *
{@code
- * InetSocketAddress addr = new InetSocketAddress("proxy.example.com", 80);
- * HttpClient client = HttpClient.newBuilder()
- * .proxy(ProxySelector.of(addr))
- * .build();
- * CompletableFuture ws = client.newWebSocketBuilder()
- * .buildAsync(URI.create("ws://websocket.example.com"), listener);
- * }
- *
- * A {@code WebSocket.Builder} returned from this method is not safe for
- * use by multiple threads without external synchronization.
+ *
{@code InetSocketAddress addr = new InetSocketAddress("proxy.example.com", 80);
+ * HttpClient client = HttpClient.newBuilder()
+ * .proxy(ProxySelector.of(addr))
+ * .build();
+ * CompletableFuture ws = client.newWebSocketBuilder()
+ * .buildAsync(URI.create("ws://websocket.example.com"), listener); }
*
* @implSpec The default implementation of this method throws
* {@code UnsupportedOperationException}. Clients obtained through
diff --git a/src/jdk.incubator.httpclient/share/classes/jdk/incubator/http/HttpHeaders.java b/src/java.net.http/share/classes/java/net/http/HttpHeaders.java
similarity index 89%
rename from src/jdk.incubator.httpclient/share/classes/jdk/incubator/http/HttpHeaders.java
rename to src/java.net.http/share/classes/java/net/http/HttpHeaders.java
index a66908dcc1c..2b8b5bc7d8a 100644
--- a/src/jdk.incubator.httpclient/share/classes/jdk/incubator/http/HttpHeaders.java
+++ b/src/java.net.http/share/classes/java/net/http/HttpHeaders.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -23,7 +23,7 @@
* questions.
*/
-package jdk.incubator.http;
+package java.net.http;
import java.util.List;
import java.util.Map;
@@ -35,15 +35,19 @@
/**
* A read-only view of a set of HTTP headers.
- * {@Incubating}
+ *
+ * An {@code HttpHeaders} is not created directly, but rather returned from
+ * an {@link HttpResponse HttpResponse}. Specific HTTP headers can be set for
+ * {@linkplain HttpRequest requests} through the one of the request builder's
+ * {@link HttpRequest.Builder#header(String, String) headers} methods.
*
*
The methods of this class ( that accept a String header name ), and the
- * Map returned by the {@linkplain #map() map} method, operate without regard to
+ * Map returned by the {@link #map() map} method, operate without regard to
* case when retrieving the header value.
*
- *
HttpHeaders instances are immutable.
+ *
{@code HttpHeaders} instances are immutable.
*
- * @since 9
+ * @since 11
*/
public abstract class HttpHeaders {
@@ -139,7 +143,7 @@ public final boolean equals(Object obj) {
* Computes a hash code for this HTTP headers instance.
*
*
The hash code is based upon the components of the HTTP headers
- * {@linkplain #map() map}, and satisfies the general contract of the
+ * {@link #map() map}, and satisfies the general contract of the
* {@link Object#hashCode Object.hashCode} method.
*
* @return the hash-code value for this HTTP headers
@@ -156,7 +160,7 @@ public final int hashCode() {
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
- sb.append(super.toString()).append(" ");
+ sb.append(super.toString()).append(" { ");
sb.append(map());
sb.append(" }");
return sb.toString();
diff --git a/src/java.net.http/share/classes/java/net/http/HttpRequest.java b/src/java.net.http/share/classes/java/net/http/HttpRequest.java
new file mode 100644
index 00000000000..a06deb70857
--- /dev/null
+++ b/src/java.net.http/share/classes/java/net/http/HttpRequest.java
@@ -0,0 +1,650 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net.http;
+
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.net.URI;
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Path;
+import java.time.Duration;
+import java.util.Iterator;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.concurrent.Flow;
+import java.util.function.Supplier;
+import jdk.internal.net.http.HttpRequestBuilderImpl;
+import jdk.internal.net.http.RequestPublishers;
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+/**
+ * An HTTP request.
+ *
+ *
An {@code HttpRequest} instance is built through an {@code HttpRequest}
+ * {@linkplain HttpRequest.Builder builder}. An {@code HttpRequest} builder
+ * is obtained from one of the {@link HttpRequest#newBuilder(URI) newBuilder}
+ * methods. A request's {@link URI}, headers, and body can be set. Request
+ * bodies are provided through a {@link BodyPublisher BodyPublisher} supplied
+ * to one of the {@link Builder#POST(BodyPublisher) POST},
+ * {@link Builder#PUT(BodyPublisher) PUT} or
+ * {@link Builder#method(String,BodyPublisher) method} methods.
+ * Once all required parameters have been set in the builder, {@link
+ * Builder#build() build} will return the {@code HttpRequest}. Builders can be
+ * copied and modified many times in order to build multiple related requests
+ * that differ in some parameters.
+ *
+ *
The following is an example of a GET request that prints the response
+ * body as a String:
+ *
+ *
{@code HttpClient client = HttpClient.newHttpClient();
+ * HttpRequest request = HttpRequest.newBuilder()
+ * .uri(URI.create("http://foo.com/"))
+ * .build();
+ * client.sendAsync(request, BodyHandlers.ofString())
+ * .thenApply(HttpResponse::body)
+ * .thenAccept(System.out::println)
+ * .join(); }
+ *
+ * The class {@link BodyPublishers BodyPublishers} provides implementations
+ * of many common publishers. Alternatively, a custom {@code BodyPublisher}
+ * implementation can be used.
+ *
+ * @since 11
+ */
+public abstract class HttpRequest {
+
+ /**
+ * Creates an HttpRequest.
+ */
+ protected HttpRequest() {}
+
+ /**
+ * A builder of {@linkplain HttpRequest HTTP requests}.
+ *
+ *
Instances of {@code HttpRequest.Builder} are created by calling {@link
+ * HttpRequest#newBuilder(URI)} or {@link HttpRequest#newBuilder()}.
+ *
+ *
Each of the setter methods modifies the state of the builder
+ * and returns the same instance. The methods are not synchronized and
+ * should not be called from multiple threads without external
+ * synchronization. The {@link #build() build} method returns a new
+ * {@code HttpRequest} each time it is invoked. Once built an {@code
+ * HttpRequest} is immutable, and can be sent multiple times.
+ *
+ *
Note, that not all request headers may be set by user code. Some are
+ * restricted for security reasons and others such as the headers relating
+ * to authentication, redirection and cookie management may be managed by
+ * specific APIs rather than through directly user set headers.
+ *
+ * @since 11
+ */
+ public interface Builder {
+
+ /**
+ * Sets this {@code HttpRequest}'s request {@code URI}.
+ *
+ * @param uri the request URI
+ * @return this builder
+ * @throws IllegalArgumentException if the {@code URI} scheme is not
+ * supported
+ */
+ public Builder uri(URI uri);
+
+ /**
+ * Requests the server to acknowledge the request before sending the
+ * body. This is disabled by default. If enabled, the server is
+ * requested to send an error response or a {@code 100 Continue}
+ * response before the client sends the request body. This means the
+ * request publisher for the request will not be invoked until this
+ * interim response is received.
+ *
+ * @param enable {@code true} if Expect continue to be sent
+ * @return this builder
+ */
+ public Builder expectContinue(boolean enable);
+
+ /**
+ * Sets the preferred {@link HttpClient.Version} for this request.
+ *
+ *
The corresponding {@link HttpResponse} should be checked for the
+ * version that was actually used. If the version is not set in a
+ * request, then the version requested will be that of the sending
+ * {@link HttpClient}.
+ *
+ * @param version the HTTP protocol version requested
+ * @return this builder
+ */
+ public Builder version(HttpClient.Version version);
+
+ /**
+ * Adds the given name value pair to the set of headers for this request.
+ * The given value is added to the list of values for that name.
+ *
+ * @implNote An implementation may choose to restrict some header names
+ * or values, as the HTTP Client may determine their value itself.
+ * For example, "Content-Length", which will be determined by
+ * the request Publisher. In such a case, an implementation of
+ * {@code HttpRequest.Builder} may choose to throw an
+ * {@code IllegalArgumentException} if such a header is passed
+ * to the builder.
+ *
+ * @param name the header name
+ * @param value the header value
+ * @return this builder
+ * @throws IllegalArgumentException if the header name or value is not
+ * valid, see
+ * RFC 7230 section-3.2, or the header name or value is restricted
+ * by the implementation.
+ */
+ public Builder header(String name, String value);
+
+ /**
+ * Adds the given name value pairs to the set of headers for this
+ * request. The supplied {@code String} instances must alternate as
+ * header names and header values.
+ * To add several values to the same name then the same name must
+ * be supplied with each new value.
+ *
+ * @param headers the list of name value pairs
+ * @return this builder
+ * @throws IllegalArgumentException if there are an odd number of
+ * parameters, or if a header name or value is not valid, see
+ *
+ * RFC 7230 section-3.2, or a header name or value is
+ * {@linkplain #header(String, String) restricted} by the
+ * implementation.
+ */
+ public Builder headers(String... headers);
+
+ /**
+ * Sets a timeout for this request. If the response is not received
+ * within the specified timeout then an {@link HttpTimeoutException} is
+ * thrown from {@link HttpClient#send(java.net.http.HttpRequest,
+ * java.net.http.HttpResponse.BodyHandler) HttpClient::send} or
+ * {@link HttpClient#sendAsync(java.net.http.HttpRequest,
+ * java.net.http.HttpResponse.BodyHandler) HttpClient::sendAsync}
+ * completes exceptionally with an {@code HttpTimeoutException}. The effect
+ * of not setting a timeout is the same as setting an infinite Duration, ie.
+ * block forever.
+ *
+ * @param duration the timeout duration
+ * @return this builder
+ * @throws IllegalArgumentException if the duration is non-positive
+ */
+ public abstract Builder timeout(Duration duration);
+
+ /**
+ * Sets the given name value pair to the set of headers for this
+ * request. This overwrites any previously set values for name.
+ *
+ * @param name the header name
+ * @param value the header value
+ * @return this builder
+ * @throws IllegalArgumentException if the header name or value is not valid,
+ * see
+ * RFC 7230 section-3.2, or the header name or value is
+ * {@linkplain #header(String, String) restricted} by the
+ * implementation.
+ */
+ public Builder setHeader(String name, String value);
+
+ /**
+ * Sets the request method of this builder to GET.
+ * This is the default.
+ *
+ * @return this builder
+ */
+ public Builder GET();
+
+ /**
+ * Sets the request method of this builder to POST and sets its
+ * request body publisher to the given value.
+ *
+ * @param bodyPublisher the body publisher
+ *
+ * @return this builder
+ */
+ public Builder POST(BodyPublisher bodyPublisher);
+
+ /**
+ * Sets the request method of this builder to PUT and sets its
+ * request body publisher to the given value.
+ *
+ * @param bodyPublisher the body publisher
+ *
+ * @return this builder
+ */
+ public Builder PUT(BodyPublisher bodyPublisher);
+
+ /**
+ * Sets the request method of this builder to DELETE.
+ *
+ * @return this builder
+ */
+ public Builder DELETE();
+
+ /**
+ * Sets the request method and request body of this builder to the
+ * given values.
+ *
+ * @apiNote The {@link BodyPublishers#noBody() noBody} request
+ * body publisher can be used where no request body is required or
+ * appropriate. Whether a method is restricted, or not, is
+ * implementation specific. For example, some implementations may choose
+ * to restrict the {@code CONNECT} method.
+ *
+ * @param method the method to use
+ * @param bodyPublisher the body publisher
+ * @return this builder
+ * @throws IllegalArgumentException if the method name is not
+ * valid, see
+ * RFC 7230 section-3.1.1, or the method is restricted by the
+ * implementation.
+ */
+ public Builder method(String method, BodyPublisher bodyPublisher);
+
+ /**
+ * Builds and returns an {@link HttpRequest}.
+ *
+ * @return a new {@code HttpRequest}
+ * @throws IllegalStateException if a URI has not been set
+ */
+ public HttpRequest build();
+
+ /**
+ * Returns an exact duplicate copy of this {@code Builder} based on
+ * current state. The new builder can then be modified independently of
+ * this builder.
+ *
+ * @return an exact copy of this builder
+ */
+ public Builder copy();
+ }
+
+ /**
+ * Creates an {@code HttpRequest} builder with the given URI.
+ *
+ * @param uri the request URI
+ * @return a new request builder
+ * @throws IllegalArgumentException if the URI scheme is not supported.
+ */
+ public static HttpRequest.Builder newBuilder(URI uri) {
+ return new HttpRequestBuilderImpl(uri);
+ }
+
+ /**
+ * Creates an {@code HttpRequest} builder.
+ *
+ * @return a new request builder
+ */
+ public static HttpRequest.Builder newBuilder() {
+ return new HttpRequestBuilderImpl();
+ }
+
+ /**
+ * Returns an {@code Optional} containing the {@link BodyPublisher} set on
+ * this request. If no {@code BodyPublisher} was set in the requests's
+ * builder, then the {@code Optional} is empty.
+ *
+ * @return an {@code Optional} containing this request's {@code BodyPublisher}
+ */
+ public abstract Optional bodyPublisher();
+
+ /**
+ * Returns the request method for this request. If not set explicitly,
+ * the default method for any request is "GET".
+ *
+ * @return this request's method
+ */
+ public abstract String method();
+
+ /**
+ * Returns an {@code Optional} containing this request's timeout duration.
+ * If the timeout duration was not set in the request's builder, then the
+ * {@code Optional} is empty.
+ *
+ * @return an {@code Optional} containing this request's timeout duration
+ */
+ public abstract Optional timeout();
+
+ /**
+ * Returns this request's {@linkplain HttpRequest.Builder#expectContinue(boolean)
+ * expect continue} setting.
+ *
+ * @return this request's expect continue setting
+ */
+ public abstract boolean expectContinue();
+
+ /**
+ * Returns this request's {@code URI}.
+ *
+ * @return this request's URI
+ */
+ public abstract URI uri();
+
+ /**
+ * Returns an {@code Optional} containing the HTTP protocol version that
+ * will be requested for this {@code HttpRequest}. If the version was not
+ * set in the request's builder, then the {@code Optional} is empty.
+ * In that case, the version requested will be that of the sending
+ * {@link HttpClient}. The corresponding {@link HttpResponse} should be
+ * queried to determine the version that was actually used.
+ *
+ * @return HTTP protocol version
+ */
+ public abstract Optional version();
+
+ /**
+ * The (user-accessible) request headers that this request was (or will be)
+ * sent with.
+ *
+ * @return this request's HttpHeaders
+ */
+ public abstract HttpHeaders headers();
+
+ /**
+ * Tests this HTTP request instance for equality with the given object.
+ *
+ * If the given object is not an {@code HttpRequest} then this
+ * method returns {@code false}. Two HTTP requests are equal if their URI,
+ * method, and headers fields are all equal.
+ *
+ *
This method satisfies the general contract of the {@link
+ * Object#equals(Object) Object.equals} method.
+ *
+ * @param obj the object to which this object is to be compared
+ * @return {@code true} if, and only if, the given object is an {@code
+ * HttpRequest} that is equal to this HTTP request
+ */
+ @Override
+ public final boolean equals(Object obj) {
+ if (! (obj instanceof HttpRequest))
+ return false;
+ HttpRequest that = (HttpRequest)obj;
+ if (!that.method().equals(this.method()))
+ return false;
+ if (!that.uri().equals(this.uri()))
+ return false;
+ if (!that.headers().equals(this.headers()))
+ return false;
+ return true;
+ }
+
+ /**
+ * Computes a hash code for this HTTP request instance.
+ *
+ *
The hash code is based upon the HTTP request's URI, method, and
+ * header components, and satisfies the general contract of the
+ * {@link Object#hashCode Object.hashCode} method.
+ *
+ * @return the hash-code value for this HTTP request
+ */
+ public final int hashCode() {
+ return method().hashCode()
+ + uri().hashCode()
+ + headers().hashCode();
+ }
+
+ /**
+ * A {@code BodyPublisher} converts high-level Java objects into a flow of
+ * byte buffers suitable for sending as a request body. The class
+ * {@link BodyPublishers BodyPublishers} provides implementations of many
+ * common publishers.
+ *
+ *
The {@code BodyPublisher} interface extends {@link Flow.Publisher
+ * Flow.Publisher<ByteBuffer>}, which means that a {@code BodyPublisher}
+ * acts as a publisher of {@linkplain ByteBuffer byte buffers}.
+ *
+ *
When sending a request that contains a body, the HTTP Client
+ * subscribes to the request's {@code BodyPublisher} in order to receive the
+ * flow of outgoing request body data. The normal semantics of {@link
+ * Flow.Subscriber} and {@link Flow.Publisher} are implemented by the HTTP
+ * Client and are expected from {@code BodyPublisher} implementations. Each
+ * outgoing request results in one HTTP Client {@code Subscriber}
+ * subscribing to the {@code BodyPublisher} in order to provide the sequence
+ * of byte buffers containing the request body. Instances of {@code
+ * ByteBuffer} published by the publisher must be allocated by the
+ * publisher, and must not be accessed after being published to the HTTP
+ * Client. These subscriptions complete normally when the request body is
+ * fully sent, and can be canceled or terminated early through error. If a
+ * request needs to be resent for any reason, then a new subscription is
+ * created which is expected to generate the same data as before.
+ *
+ *
A {@code BodyPublisher} that reports a {@linkplain #contentLength()
+ * content length} of {@code 0} may not be subscribed to by the HTTP Client,
+ * as it has effectively no data to publish.
+ *
+ * @see BodyPublishers
+ * @since 11
+ */
+ public interface BodyPublisher extends Flow.Publisher {
+
+ /**
+ * Returns the content length for this request body. May be zero
+ * if no request body being sent, greater than zero for a fixed
+ * length content, or less than zero for an unknown content length.
+ *
+ * This method may be invoked before the publisher is subscribed to.
+ * This method may be invoked more than once by the HTTP client
+ * implementation, and MUST return the same constant value each time.
+ *
+ * @return the content length for this request body, if known
+ */
+ long contentLength();
+ }
+
+ /**
+ * Implementations of {@link BodyPublisher BodyPublisher} that implement
+ * various useful publishers, such as publishing the request body from a
+ * String, or from a file.
+ *
+ *
The following are examples of using the predefined body publishers to
+ * convert common high-level Java objects into a flow of data suitable for
+ * sending as a request body:
+ *
+ *
{@code // Request body from a String
+ * HttpRequest request = HttpRequest.newBuilder()
+ * .uri(URI.create("https://foo.com/"))
+ * .header("Content-Type", "text/plain; charset=UTF-8")
+ * .POST(BodyPublishers.ofString("some body text"))
+ * .build();
+ *
+ * // Request body from a File
+ * HttpRequest request = HttpRequest.newBuilder()
+ * .uri(URI.create("https://foo.com/"))
+ * .header("Content-Type", "application/json")
+ * .POST(BodyPublishers.ofFile(Paths.get("file.json")))
+ * .build();
+ *
+ * // Request body from a byte array
+ * HttpRequest request = HttpRequest.newBuilder()
+ * .uri(URI.create("https://foo.com/"))
+ * .POST(BodyPublishers.ofByteArray(new byte[] { ... }))
+ * .build(); }
+ *
+ * @since 11
+ */
+ public static class BodyPublishers {
+
+ private BodyPublishers() { }
+
+ /**
+ * Returns a request body publisher whose body is retrieved from the
+ * given {@code Flow.Publisher}. The returned request body publisher
+ * has an unknown content length.
+ *
+ * @apiNote This method can be used as an adapter between {@code
+ * BodyPublisher} and {@code Flow.Publisher}, where the amount of
+ * request body that the publisher will publish is unknown.
+ *
+ * @param publisher the publisher responsible for publishing the body
+ * @return a BodyPublisher
+ */
+ public static BodyPublisher
+ fromPublisher(Flow.Publisher extends ByteBuffer> publisher) {
+ return new RequestPublishers.PublisherAdapter(publisher, -1L);
+ }
+
+ /**
+ * Returns a request body publisher whose body is retrieved from the
+ * given {@code Flow.Publisher}. The returned request body publisher
+ * has the given content length.
+ *
+ * The given {@code contentLength} is a positive number, that
+ * represents the exact amount of bytes the {@code publisher} must
+ * publish.
+ *
+ * @apiNote This method can be used as an adapter between {@code
+ * BodyPublisher} and {@code Flow.Publisher}, where the amount of
+ * request body that the publisher will publish is known.
+ *
+ * @param publisher the publisher responsible for publishing the body
+ * @param contentLength a positive number representing the exact
+ * amount of bytes the publisher will publish
+ * @throws IllegalArgumentException if the content length is
+ * non-positive
+ * @return a BodyPublisher
+ */
+ public static BodyPublisher
+ fromPublisher(Flow.Publisher extends ByteBuffer> publisher,
+ long contentLength) {
+ if (contentLength < 1)
+ throw new IllegalArgumentException("non-positive contentLength: "
+ + contentLength);
+ return new RequestPublishers.PublisherAdapter(publisher, contentLength);
+ }
+
+ /**
+ * Returns a request body publisher whose body is the given {@code
+ * String}, converted using the {@link StandardCharsets#UTF_8 UTF_8}
+ * character set.
+ *
+ * @param body the String containing the body
+ * @return a BodyPublisher
+ */
+ public static BodyPublisher ofString(String body) {
+ return ofString(body, UTF_8);
+ }
+
+ /**
+ * Returns a request body publisher whose body is the given {@code
+ * String}, converted using the given character set.
+ *
+ * @param s the String containing the body
+ * @param charset the character set to convert the string to bytes
+ * @return a BodyPublisher
+ */
+ public static BodyPublisher ofString(String s, Charset charset) {
+ return new RequestPublishers.StringPublisher(s, charset);
+ }
+
+ /**
+ * A request body publisher that reads its data from an {@link
+ * InputStream}. A {@link Supplier} of {@code InputStream} is used in
+ * case the request needs to be repeated, as the content is not buffered.
+ * The {@code Supplier} may return {@code null} on subsequent attempts,
+ * in which case the request fails.
+ *
+ * @param streamSupplier a Supplier of open InputStreams
+ * @return a BodyPublisher
+ */
+ // TODO (spec): specify that the stream will be closed
+ public static BodyPublisher ofInputStream(Supplier extends InputStream> streamSupplier) {
+ return new RequestPublishers.InputStreamPublisher(streamSupplier);
+ }
+
+ /**
+ * Returns a request body publisher whose body is the given byte array.
+ *
+ * @param buf the byte array containing the body
+ * @return a BodyPublisher
+ */
+ public static BodyPublisher ofByteArray(byte[] buf) {
+ return new RequestPublishers.ByteArrayPublisher(buf);
+ }
+
+ /**
+ * Returns a request body publisher whose body is the content of the
+ * given byte array of {@code length} bytes starting from the specified
+ * {@code offset}.
+ *
+ * @param buf the byte array containing the body
+ * @param offset the offset of the first byte
+ * @param length the number of bytes to use
+ * @return a BodyPublisher
+ * @throws IndexOutOfBoundsException if the sub-range is defined to be
+ * out-of-bounds
+ */
+ public static BodyPublisher ofByteArray(byte[] buf, int offset, int length) {
+ Objects.checkFromIndexSize(offset, length, buf.length);
+ return new RequestPublishers.ByteArrayPublisher(buf, offset, length);
+ }
+
+ /**
+ * A request body publisher that takes data from the contents of a File.
+ *
+ *
Security manager permission checks are performed in this factory
+ * method, when the {@code BodyPublisher} is created. Care must be taken
+ * that the {@code BodyPublisher} is not shared with untrusted code.
+ *
+ * @param path the path to the file containing the body
+ * @return a BodyPublisher
+ * @throws java.io.FileNotFoundException if the path is not found
+ * @throws SecurityException if a security manager has been installed
+ * and it denies {@link SecurityManager#checkRead(String)
+ * read access} to the given file
+ */
+ public static BodyPublisher ofFile(Path path) throws FileNotFoundException {
+ Objects.requireNonNull(path);
+ return RequestPublishers.FilePublisher.create(path);
+ }
+
+ /**
+ * A request body publisher that takes data from an {@code Iterable}
+ * of byte arrays. An {@link Iterable} is provided which supplies
+ * {@link Iterator} instances. Each attempt to send the request results
+ * in one invocation of the {@code Iterable}.
+ *
+ * @param iter an Iterable of byte arrays
+ * @return a BodyPublisher
+ */
+ public static BodyPublisher ofByteArrays(Iterable iter) {
+ return new RequestPublishers.IterablePublisher(iter);
+ }
+
+ /**
+ * A request body publisher which sends no request body.
+ *
+ * @return a BodyPublisher which completes immediately and sends
+ * no request body.
+ */
+ public static BodyPublisher noBody() {
+ return new RequestPublishers.EmptyPublisher();
+ }
+ }
+}
diff --git a/src/java.net.http/share/classes/java/net/http/HttpResponse.java b/src/java.net.http/share/classes/java/net/http/HttpResponse.java
new file mode 100644
index 00000000000..0d960bf3ddc
--- /dev/null
+++ b/src/java.net.http/share/classes/java/net/http/HttpResponse.java
@@ -0,0 +1,1315 @@
+/*
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.net.http;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+import java.nio.channels.FileChannel;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.OpenOption;
+import java.nio.file.Path;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CompletionStage;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.Flow;
+import java.util.concurrent.Flow.Subscriber;
+import java.util.concurrent.Flow.Publisher;
+import java.util.concurrent.Flow.Subscription;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.stream.Stream;
+import javax.net.ssl.SSLSession;
+import jdk.internal.net.http.BufferingSubscriber;
+import jdk.internal.net.http.LineSubscriberAdapter;
+import jdk.internal.net.http.ResponseBodyHandlers.FileDownloadBodyHandler;
+import jdk.internal.net.http.ResponseBodyHandlers.PathBodyHandler;
+import jdk.internal.net.http.ResponseBodyHandlers.PushPromisesHandlerWithMap;
+import jdk.internal.net.http.ResponseSubscribers;
+import jdk.internal.net.http.ResponseSubscribers.PathSubscriber;
+import static java.nio.file.StandardOpenOption.*;
+import static jdk.internal.net.http.common.Utils.charsetFrom;
+
+/**
+ * An HTTP response.
+ *
+ * An {@code HttpResponse} is not created directly, but rather returned as
+ * a result of sending an {@link HttpRequest}. An {@code HttpResponse} is
+ * made available when the response status code and headers have been received,
+ * and typically after the response body has also been completely received.
+ * Whether or not the {@code HttpResponse} is made available before the response
+ * body has been completely received depends on the {@link BodyHandler
+ * BodyHandler} provided when sending the {@code HttpRequest}.
+ *
+ *
This class provides methods for accessing the response status code,
+ * headers, the response body, and the {@code HttpRequest} corresponding
+ * to this response.
+ *
+ *
The following is an example of retrieving a response as a String:
+ *
+ *
{@code HttpResponse response = client
+ * .send(request, BodyHandlers.ofString()); }
+ *
+ * The class {@link BodyHandlers BodyHandlers} provides implementations
+ * of many common response handlers. Alternatively, a custom {@code BodyHandler}
+ * implementation can be used.
+ *
+ * @param the response body type
+ * @since 11
+ */
+public interface HttpResponse {
+
+
+ /**
+ * Returns the status code for this response.
+ *
+ * @return the response code
+ */
+ public int statusCode();
+
+ /**
+ * Returns the {@link HttpRequest} corresponding to this response.
+ *
+ * The returned {@code HttpRequest} may not be the initiating request
+ * provided when {@linkplain HttpClient#send(HttpRequest, BodyHandler)
+ * sending}. For example, if the initiating request was redirected, then the
+ * request returned by this method will have the redirected URI, which will
+ * be different from the initiating request URI.
+ *
+ * @see #previousResponse()
+ *
+ * @return the request
+ */
+ public HttpRequest request();
+
+ /**
+ * Returns an {@code Optional} containing the previous intermediate response
+ * if one was received. An intermediate response is one that is received
+ * as a result of redirection or authentication. If no previous response
+ * was received then an empty {@code Optional} is returned.
+ *
+ * @return an Optional containing the HttpResponse, if any.
+ */
+ public Optional> previousResponse();
+
+ /**
+ * Returns the received response headers.
+ *
+ * @return the response headers
+ */
+ public HttpHeaders headers();
+
+ /**
+ * Returns the body. Depending on the type of {@code T}, the returned body
+ * may represent the body after it was read (such as {@code byte[]}, or
+ * {@code String}, or {@code Path}) or it may represent an object with
+ * which the body is read, such as an {@link java.io.InputStream}.
+ *
+ * If this {@code HttpResponse} was returned from an invocation of
+ * {@link #previousResponse()} then this method returns {@code null}
+ *
+ * @return the body
+ */
+ public T body();
+
+ /**
+ * Returns an {@link Optional} containing the {@link SSLSession} in effect
+ * for this response. Returns an empty {@code Optional} if this is not a
+ * HTTPS response.
+ *
+ * @return an {@code Optional} containing the {@code SSLSession} associated
+ * with the response
+ */
+ public Optional sslSession();
+
+ /**
+ * Returns the {@code URI} that the response was received from. This may be
+ * different from the request {@code URI} if redirection occurred.
+ *
+ * @return the URI of the response
+ */
+ public URI uri();
+
+ /**
+ * Returns the HTTP protocol version that was used for this response.
+ *
+ * @return HTTP protocol version
+ */
+ public HttpClient.Version version();
+
+
+ /**
+ * Initial response information supplied to a {@link BodyHandler BodyHandler}
+ * when a response is initially received and before the body is processed.
+ */
+ public interface ResponseInfo {
+ /**
+ * Provides the response status code.
+ * @return the response status code
+ */
+ public int statusCode();
+
+ /**
+ * Provides the response headers.
+ * @return the response headers
+ */
+ public HttpHeaders headers();
+
+ /**
+ * Provides the response protocol version.
+ * @return the response protocol version
+ */
+ public HttpClient.Version version();
+ }
+
+ /**
+ * A handler for response bodies. The class {@link BodyHandlers BodyHandlers}
+ * provides implementations of many common body handlers.
+ *
+ * The {@code BodyHandler} interface allows inspection of the response
+ * code and headers, before the actual response body is received, and is
+ * responsible for creating the response {@link BodySubscriber
+ * BodySubscriber}. The {@code BodySubscriber} consumes the actual response
+ * body bytes and, typically, converts them into a higher-level Java type.
+ *
+ *
A {@code BodyHandler} is a function that takes a {@link ResponseInfo
+ * ResponseInfo} object; and which returns a {@code BodySubscriber}. The
+ * {@code BodyHandler} is invoked when the response status code and headers
+ * are available, but before the response body bytes are received.
+ *
+ *
The following example uses one of the {@linkplain BodyHandlers
+ * predefined body handlers} that always process the response body in the
+ * same way ( streams the response body to a file ).
+ *
+ *
{@code HttpRequest request = HttpRequest.newBuilder()
+ * .uri(URI.create("http://www.foo.com/"))
+ * .build();
+ * client.sendAsync(request, BodyHandlers.ofFile(Paths.get("/tmp/f")))
+ * .thenApply(HttpResponse::body)
+ * .thenAccept(System.out::println); }
+ *
+ * Note, that even though the pre-defined handlers do not examine the
+ * response code, the response code and headers are always retrievable from
+ * the {@link HttpResponse}, when it is returned.
+ *
+ * In the second example, the function returns a different subscriber
+ * depending on the status code.
+ *
{@code HttpRequest request = HttpRequest.newBuilder()
+ * .uri(URI.create("http://www.foo.com/"))
+ * .build();
+ * BodyHandler bodyHandler = (rspInfo) -> rspInfo.statusCode() == 200
+ * ? BodySubscribers.ofFile(Paths.get("/tmp/f"))
+ * : BodySubscribers.replacing(Paths.get("/NULL"));
+ * client.sendAsync(request, bodyHandler)
+ * .thenApply(HttpResponse::body)
+ * .thenAccept(System.out::println); }
+ *
+ * @param the response body type
+ * @see BodyHandlers
+ * @since 11
+ */
+ @FunctionalInterface
+ public interface BodyHandler {
+
+ /**
+ * Returns a {@link BodySubscriber BodySubscriber} considering the
+ * given response status code and headers. This method is invoked before
+ * the actual response body bytes are read and its implementation must
+ * return a {@link BodySubscriber BodySubscriber} to consume the response
+ * body bytes.
+ *
+ * The response body can be discarded using one of {@link
+ * BodyHandlers#discarding() discarding} or {@link
+ * BodyHandlers#replacing(Object) replacing}.
+ *
+ * @param responseInfo the response info
+ * @return a body subscriber
+ */
+ public BodySubscriber apply(ResponseInfo responseInfo);
+ }
+
+ /**
+ * Implementations of {@link BodyHandler BodyHandler} that implement various
+ * useful handlers, such as handling the response body as a String, or
+ * streaming the response body to a file.
+ *
+ * These implementations do not examine the status code, meaning the
+ * body is always accepted. They typically return an equivalently named
+ * {@code BodySubscriber}. Alternatively, a custom handler can be used to
+ * examine the status code and headers, and return a different body
+ * subscriber, of the same type, as appropriate.
+ *
+ *
The following are examples of using the predefined body handlers to
+ * convert a flow of response body data into common high-level Java objects:
+ *
+ *
{@code // Receives the response body as a String
+ * HttpResponse response = client
+ * .send(request, BodyHandlers.ofString());
+ *
+ * // Receives the response body as a file
+ * HttpResponse response = client
+ * .send(request, BodyHandlers.ofFile(Paths.get("example.html")));
+ *
+ * // Receives the response body as an InputStream
+ * HttpResponse response = client
+ * .send(request, BodyHandlers.ofInputStream());
+ *
+ * // Discards the response body
+ * HttpResponse response = client
+ * .send(request, BodyHandlers.discarding()); }
+ *
+ * @since 11
+ */
+ public static class BodyHandlers {
+
+ private BodyHandlers() { }
+
+ /**
+ * Returns a response body handler that returns a {@link BodySubscriber
+ * BodySubscriber}{@code } obtained from {@link
+ * BodySubscribers#fromSubscriber(Subscriber)}, with the given
+ * {@code subscriber}.
+ *
+ * The response body is not available through this, or the {@code
+ * HttpResponse} API, but instead all response body is forwarded to the
+ * given {@code subscriber}, which should make it available, if
+ * appropriate, through some other mechanism, e.g. an entry in a
+ * database, etc.
+ *
+ * @apiNote This method can be used as an adapter between {@code
+ * BodySubscriber} and {@code Flow.Subscriber}.
+ *
+ *
For example:
+ *
{@code TextSubscriber subscriber = new TextSubscriber();
+ * HttpResponse response = client.sendAsync(request,
+ * BodyHandlers.fromSubscriber(subscriber)).join();
+ * System.out.println(response.statusCode()); }
+ *
+ * @param subscriber the subscriber
+ * @return a response body handler
+ */
+ public static BodyHandler
+ fromSubscriber(Subscriber super List> subscriber) {
+ Objects.requireNonNull(subscriber);
+ return (responseInfo) -> BodySubscribers.fromSubscriber(subscriber,
+ s -> null);
+ }
+
+ /**
+ * Returns a response body handler that returns a {@link BodySubscriber
+ * BodySubscriber}{@code } obtained from {@link
+ * BodySubscribers#fromSubscriber(Subscriber, Function)}, with the
+ * given {@code subscriber} and {@code finisher} function.
+ *
+ * The given {@code finisher} function is applied after the given
+ * subscriber's {@code onComplete} has been invoked. The {@code finisher}
+ * function is invoked with the given subscriber, and returns a value
+ * that is set as the response's body.
+ *
+ * @apiNote This method can be used as an adapter between {@code
+ * BodySubscriber} and {@code Flow.Subscriber}.
+ *
+ *
For example:
+ *
{@code TextSubscriber subscriber = ...; // accumulates bytes and transforms them into a String
+ * HttpResponse response = client.sendAsync(request,
+ * BodyHandlers.fromSubscriber(subscriber, TextSubscriber::getTextResult)).join();
+ * String text = response.body(); }
+ *
+ * @param the type of the Subscriber
+ * @param the type of the response body
+ * @param subscriber the subscriber
+ * @param finisher a function to be applied after the subscriber has completed
+ * @return a response body handler
+ */
+ public static >,T> BodyHandler
+ fromSubscriber(S subscriber, Function super S,? extends T> finisher) {
+ Objects.requireNonNull(subscriber);
+ Objects.requireNonNull(finisher);
+ return (responseInfo) -> BodySubscribers.fromSubscriber(subscriber,
+ finisher);
+ }
+
+ /**
+ * Returns a response body handler that returns a {@link BodySubscriber
+ * BodySubscriber}{@code } obtained from {@link
+ * BodySubscribers#fromLineSubscriber(Subscriber, Function, Charset, String)
+ * BodySubscribers.fromLineSubscriber(subscriber, s -> null, charset, null)},
+ * with the given {@code subscriber}.
+ * The {@link Charset charset} used to decode the response body bytes is
+ * obtained from the HTTP response headers as specified by {@link #ofString()},
+ * and lines are delimited in the manner of {@link BufferedReader#readLine()}.
+ *
+ * The response body is not available through this, or the {@code
+ * HttpResponse} API, but instead all response body is forwarded to the
+ * given {@code subscriber}, which should make it available, if
+ * appropriate, through some other mechanism, e.g. an entry in a
+ * database, etc.
+ *
+ * @apiNote This method can be used as an adapter between a {@code
+ * BodySubscriber} and a text based {@code Flow.Subscriber} that parses
+ * text line by line.
+ *
+ *
For example:
+ *
{@code // A PrintSubscriber that implements Flow.Subscriber
+ * // and print lines received by onNext() on System.out
+ * PrintSubscriber subscriber = new PrintSubscriber(System.out);
+ * client.sendAsync(request, BodyHandlers.fromLineSubscriber(subscriber))
+ * .thenApply(HttpResponse::statusCode)
+ * .thenAccept((status) -> {
+ * if (status != 200) {
+ * System.err.printf("ERROR: %d status received%n", status);
+ * }
+ * }); }
+ *
+ * @param subscriber the subscriber
+ * @return a response body handler
+ */
+ public static BodyHandler
+ fromLineSubscriber(Subscriber super String> subscriber) {
+ Objects.requireNonNull(subscriber);
+ return (responseInfo) ->
+ BodySubscribers.fromLineSubscriber(subscriber,
+ s -> null,
+ charsetFrom(responseInfo.headers()),
+ null);
+ }
+
+ /**
+ * Returns a response body handler that returns a {@link BodySubscriber
+ * BodySubscriber}{@code } obtained from {@link
+ * BodySubscribers#fromLineSubscriber(Subscriber, Function, Charset, String)
+ * BodySubscribers.fromLineSubscriber(subscriber, finisher, charset, lineSeparator)},
+ * with the given {@code subscriber}, {@code finisher} function, and line separator.
+ * The {@link Charset charset} used to decode the response body bytes is
+ * obtained from the HTTP response headers as specified by {@link #ofString()}.
+ *
+ * The given {@code finisher} function is applied after the given
+ * subscriber's {@code onComplete} has been invoked. The {@code finisher}
+ * function is invoked with the given subscriber, and returns a value
+ * that is set as the response's body.
+ *
+ * @apiNote This method can be used as an adapter between a {@code
+ * BodySubscriber} and a text based {@code Flow.Subscriber} that parses
+ * text line by line.
+ *
+ *
For example:
+ *
{@code // A LineParserSubscriber that implements Flow.Subscriber
+ * // and accumulates lines that match a particular pattern
+ * Pattern pattern = ...;
+ * LineParserSubscriber subscriber = new LineParserSubscriber(pattern);
+ * HttpResponse> response = client.send(request,
+ * BodyHandlers.fromLineSubscriber(subscriber, s -> s.getMatchingLines(), "\n"));
+ * if (response.statusCode() != 200) {
+ * System.err.printf("ERROR: %d status received%n", response.statusCode());
+ * } }
+ *
+ *
+ * @param the type of the Subscriber
+ * @param the type of the response body
+ * @param subscriber the subscriber
+ * @param finisher a function to be applied after the subscriber has completed
+ * @param lineSeparator an optional line separator: can be {@code null},
+ * in which case lines will be delimited in the manner of
+ * {@link BufferedReader#readLine()}.
+ * @return a response body handler
+ * @throws IllegalArgumentException if the supplied {@code lineSeparator}
+ * is the empty string
+ */
+ public static ,T> BodyHandler
+ fromLineSubscriber(S subscriber,
+ Function super S,? extends T> finisher,
+ String lineSeparator) {
+ Objects.requireNonNull(subscriber);
+ Objects.requireNonNull(finisher);
+ // implicit null check
+ if (lineSeparator != null && lineSeparator.isEmpty())
+ throw new IllegalArgumentException("empty line separator");
+ return (responseInfo) ->
+ BodySubscribers.fromLineSubscriber(subscriber,
+ finisher,
+ charsetFrom(responseInfo.headers()),
+ lineSeparator);
+ }
+
+ /**
+ * Returns a response body handler that discards the response body.
+ *
+ * @return a response body handler
+ */
+ public static BodyHandler discarding() {
+ return (responseInfo) -> BodySubscribers.discarding();
+ }
+
+ /**
+ * Returns a response body handler that returns the given replacement
+ * value, after discarding the response body.
+ *
+ * @param the response body type
+ * @param value the value of U to return as the body, may be {@code null}
+ * @return a response body handler
+ */
+ public static BodyHandler replacing(U value) {
+ return (responseInfo) -> BodySubscribers.replacing(value);
+ }
+
+ /**
+ * Returns a {@code BodyHandler} that returns a
+ * {@link BodySubscriber BodySubscriber}{@code } obtained from
+ * {@link BodySubscribers#ofString(Charset) BodySubscribers.ofString(Charset)}.
+ * The body is decoded using the given character set.
+ *
+ * @param charset the character set to convert the body with
+ * @return a response body handler
+ */
+ public static BodyHandler ofString(Charset charset) {
+ Objects.requireNonNull(charset);
+ return (responseInfo) -> BodySubscribers.ofString(charset);
+ }
+
+ /**
+ * Returns a {@code BodyHandler} that returns a
+ * {@link BodySubscriber BodySubscriber}{@code } obtained from
+ * {@link BodySubscribers#ofFile(Path, OpenOption...)
+ * BodySubscribers.ofFile(Path,OpenOption...)}.
+ *
+ * When the {@code HttpResponse} object is returned, the body has
+ * been completely written to the file, and {@link #body()} returns a
+ * reference to its {@link Path}.
+ *
+ *
Security manager permission checks are performed in this factory
+ * method, when the {@code BodyHandler} is created. Care must be taken
+ * that the {@code BodyHandler} is not shared with untrusted code.
+ *
+ * @param file the file to store the body in
+ * @param openOptions any options to use when opening/creating the file
+ * @return a response body handler
+ * @throws IllegalArgumentException if an invalid set of open options
+ * are specified
+ * @throws SecurityException If a security manager has been installed
+ * and it denies {@link SecurityManager#checkWrite(String)
+ * write access} to the file.
+ */
+ public static BodyHandler ofFile(Path file, OpenOption... openOptions) {
+ Objects.requireNonNull(file);
+ List opts = List.of(openOptions);
+ if (opts.contains(DELETE_ON_CLOSE) || opts.contains(READ)) {
+ // these options make no sense, since the FileChannel is not exposed
+ throw new IllegalArgumentException("invalid openOptions: " + opts);
+ }
+ return PathBodyHandler.create(file, opts);
+ }
+
+ /**
+ * Returns a {@code BodyHandler} that returns a
+ * {@link BodySubscriber BodySubscriber}{@code }.
+ *
+ * Equivalent to: {@code ofFile(file, CREATE, WRITE)}
+ *
+ *
Security manager permission checks are performed in this factory
+ * method, when the {@code BodyHandler} is created. Care must be taken
+ * that the {@code BodyHandler} is not shared with untrusted code.
+ *
+ * @param file the file to store the body in
+ * @return a response body handler
+ * @throws SecurityException If a security manager has been installed
+ * and it denies {@link SecurityManager#checkWrite(String)
+ * write access} to the file.
+ */
+ public static BodyHandler ofFile(Path file) {
+ return BodyHandlers.ofFile(file, CREATE, WRITE);
+ }
+
+ /**
+ * Returns a {@code BodyHandler} that returns a
+ * {@link BodySubscriber BodySubscriber}<{@link Path}>
+ * where the download directory is specified, but the filename is
+ * obtained from the {@code Content-Disposition} response header. The
+ * {@code Content-Disposition} header must specify the attachment
+ * type and must also contain a filename parameter. If the
+ * filename specifies multiple path components only the final component
+ * is used as the filename (with the given directory name).
+ *
+ * When the {@code HttpResponse} object is returned, the body has
+ * been completely written to the file and {@link #body()} returns a
+ * {@code Path} object for the file. The returned {@code Path} is the
+ * combination of the supplied directory name and the file name supplied
+ * by the server. If the destination directory does not exist or cannot
+ * be written to, then the response will fail with an {@link IOException}.
+ *
+ *
Security manager permission checks are performed in this factory
+ * method, when the {@code BodyHandler} is created. Care must be taken
+ * that the {@code BodyHandler} is not shared with untrusted code.
+ *
+ * @param directory the directory to store the file in
+ * @param openOptions open options used when opening the file
+ * @return a response body handler
+ * @throws IllegalArgumentException if the given path does not exist,
+ * is not a directory, is not writable, or if an invalid set
+ * of open options are specified
+ * @throws SecurityException If a security manager has been installed
+ * and it denies
+ * {@linkplain SecurityManager#checkRead(String) read access}
+ * to the directory, or it denies
+ * {@linkplain SecurityManager#checkWrite(String) write access}
+ * to the directory, or it denies
+ * {@linkplain SecurityManager#checkWrite(String) write access}
+ * to the files within the directory.
+ */
+ public static BodyHandler ofFileDownload(Path directory,
+ OpenOption... openOptions) {
+ Objects.requireNonNull(directory);
+ List opts = List.of(openOptions);
+ if (opts.contains(DELETE_ON_CLOSE)) {
+ throw new IllegalArgumentException("invalid option: " + DELETE_ON_CLOSE);
+ }
+ return FileDownloadBodyHandler.create(directory, opts);
+ }
+
+ /**
+ * Returns a {@code BodyHandler} that returns a
+ * {@link BodySubscriber BodySubscriber}{@code } obtained from
+ * {@link BodySubscribers#ofInputStream() BodySubscribers.ofInputStream}.
+ *
+ * When the {@code HttpResponse} object is returned, the response
+ * headers will have been completely read, but the body may not have
+ * been fully received yet. The {@link #body()} method returns an
+ * {@link InputStream} from which the body can be read as it is received.
+ *
+ * @apiNote See {@link BodySubscribers#ofInputStream()} for more
+ * information.
+ *
+ * @return a response body handler
+ */
+ public static BodyHandler ofInputStream() {
+ return (responseInfo) -> BodySubscribers.ofInputStream();
+ }
+
+ /**
+ * Returns a {@code BodyHandler>} that returns a
+ * {@link BodySubscriber BodySubscriber}{@code >} obtained
+ * from {@link BodySubscribers#ofLines(Charset) BodySubscribers.ofLines(charset)}.
+ * The {@link Charset charset} used to decode the response body bytes is
+ * obtained from the HTTP response headers as specified by {@link #ofString()},
+ * and lines are delimited in the manner of {@link BufferedReader#readLine()}.
+ *
+ * When the {@code HttpResponse} object is returned, the body may
+ * not have been completely received.
+ *
+ * @return a response body handler
+ */
+ public static BodyHandler> ofLines() {
+ return (responseInfo) ->
+ BodySubscribers.ofLines(charsetFrom(responseInfo.headers()));
+ }
+
+ /**
+ * Returns a {@code BodyHandler} that returns a
+ * {@link BodySubscriber BodySubscriber}{@code } obtained from
+ * {@link BodySubscribers#ofByteArrayConsumer(Consumer)
+ * BodySubscribers.ofByteArrayConsumer(Consumer)}.
+ *
+ * When the {@code HttpResponse} object is returned, the body has
+ * been completely written to the consumer.
+ *
+ * @apiNote
+ * The subscriber returned by this handler is not flow controlled.
+ * Therefore, the supplied consumer must be able to process whatever
+ * amount of data is delivered in a timely fashion.
+ *
+ * @param consumer a Consumer to accept the response body
+ * @return a response body handler
+ */
+ public static BodyHandler
+ ofByteArrayConsumer(Consumer> consumer) {
+ Objects.requireNonNull(consumer);
+ return (responseInfo) -> BodySubscribers.ofByteArrayConsumer(consumer);
+ }
+
+ /**
+ * Returns a {@code BodyHandler} that returns a
+ * {@link BodySubscriber BodySubscriber}<{@code byte[]}> obtained
+ * from {@link BodySubscribers#ofByteArray() BodySubscribers.ofByteArray()}.
+ *
+ * When the {@code HttpResponse} object is returned, the body has
+ * been completely written to the byte array.
+ *
+ * @return a response body handler
+ */
+ public static BodyHandler ofByteArray() {
+ return (responseInfo) -> BodySubscribers.ofByteArray();
+ }
+
+ /**
+ * Returns a {@code BodyHandler} that returns a
+ * {@link BodySubscriber BodySubscriber}{@code } obtained from
+ * {@link BodySubscribers#ofString(Charset) BodySubscribers.ofString(Charset)}.
+ * The body is decoded using the character set specified in
+ * the {@code Content-Type} response header. If there is no such
+ * header, or the character set is not supported, then
+ * {@link StandardCharsets#UTF_8 UTF_8} is used.
+ *
+ * When the {@code HttpResponse} object is returned, the body has
+ * been completely written to the string.
+ *
+ * @return a response body handler
+ */
+ public static BodyHandler ofString() {
+ return (responseInfo) -> BodySubscribers.ofString(charsetFrom(responseInfo.headers()));
+ }
+
+ /**
+ * Returns a {@code BodyHandler>>} that creates a
+ * {@link BodySubscriber BodySubscriber}{@code >>}
+ * obtained from {@link BodySubscribers#ofPublisher()
+ * BodySubscribers.ofPublisher()}.
+ *
+ * When the {@code HttpResponse} object is returned, the response
+ * headers will have been completely read, but the body may not have
+ * been fully received yet. The {@link #body()} method returns a
+ * {@link Publisher Publisher>} from which the body
+ * response bytes can be obtained as they are received. The publisher
+ * can and must be subscribed to only once.
+ *
+ * @apiNote See {@link BodySubscribers#ofPublisher()} for more
+ * information.
+ *
+ * @return a response body handler
+ */
+ public static BodyHandler>> ofPublisher() {
+ return (responseInfo) -> BodySubscribers.ofPublisher();
+ }
+
+ /**
+ * Returns a {@code BodyHandler} which, when invoked, returns a {@linkplain
+ * BodySubscribers#buffering(BodySubscriber,int) buffering BodySubscriber}
+ * that buffers data before delivering it to the downstream subscriber.
+ * These {@code BodySubscriber} instances are created by calling
+ * {@link BodySubscribers#buffering(BodySubscriber,int)
+ * BodySubscribers.buffering} with a subscriber obtained from the given
+ * downstream handler and the {@code bufferSize} parameter.
+ *
+ * @param the response body type
+ * @param downstreamHandler the downstream handler
+ * @param bufferSize the buffer size parameter passed to {@link
+ * BodySubscribers#buffering(BodySubscriber,int) BodySubscribers.buffering}
+ * @return a body handler
+ * @throws IllegalArgumentException if {@code bufferSize <= 0}
+ */
+ public static BodyHandler buffering(BodyHandler downstreamHandler,
+ int bufferSize) {
+ Objects.requireNonNull(downstreamHandler);
+ if (bufferSize <= 0)
+ throw new IllegalArgumentException("must be greater than 0");
+ return (responseInfo) -> BodySubscribers
+ .buffering(downstreamHandler.apply(responseInfo),
+ bufferSize);
+ }
+ }
+
+ /**
+ * A handler for push promises.
+ *
+ * A push promise is a synthetic request sent by an HTTP/2 server
+ * when retrieving an initiating client-sent request. The server has
+ * determined, possibly through inspection of the initiating request, that
+ * the client will likely need the promised resource, and hence pushes a
+ * synthetic push request, in the form of a push promise, to the client. The
+ * client can choose to accept or reject the push promise request.
+ *
+ *
A push promise request may be received up to the point where the
+ * response body of the initiating client-sent request has been fully
+ * received. The delivery of a push promise response, however, is not
+ * coordinated with the delivery of the response to the initiating
+ * client-sent request.
+ *
+ * @param the push promise response body type
+ * @since 11
+ */
+ public interface PushPromiseHandler {
+
+ /**
+ * Notification of an incoming push promise.
+ *
+ * This method is invoked once for each push promise received, up
+ * to the point where the response body of the initiating client-sent
+ * request has been fully received.
+ *
+ *
A push promise is accepted by invoking the given {@code acceptor}
+ * function. The {@code acceptor} function must be passed a non-null
+ * {@code BodyHandler}, that is to be used to handle the promise's
+ * response body. The acceptor function will return a {@code
+ * CompletableFuture} that completes with the promise's response.
+ *
+ *
If the {@code acceptor} function is not successfully invoked,
+ * then the push promise is rejected. The {@code acceptor} function will
+ * throw an {@code IllegalStateException} if invoked more than once.
+ *
+ * @param initiatingRequest the initiating client-send request
+ * @param pushPromiseRequest the synthetic push request
+ * @param acceptor the acceptor function that must be successfully
+ * invoked to accept the push promise
+ */
+ public void applyPushPromise(
+ HttpRequest initiatingRequest,
+ HttpRequest pushPromiseRequest,
+ Function,CompletableFuture>> acceptor
+ );
+
+
+ /**
+ * Returns a push promise handler that accumulates push promises, and
+ * their responses, into the given map.
+ *
+ * Entries are added to the given map for each push promise accepted.
+ * The entry's key is the push request, and the entry's value is a
+ * {@code CompletableFuture} that completes with the response
+ * corresponding to the key's push request. A push request is rejected /
+ * cancelled if there is already an entry in the map whose key is
+ * {@link HttpRequest#equals equal} to it. A push request is
+ * rejected / cancelled if it does not have the same origin as its
+ * initiating request.
+ *
+ *
Entries are added to the given map as soon as practically
+ * possible when a push promise is received and accepted. That way code,
+ * using such a map like a cache, can determine if a push promise has
+ * been issued by the server and avoid making, possibly, unnecessary
+ * requests.
+ *
+ *
The delivery of a push promise response is not coordinated with
+ * the delivery of the response to the initiating client-sent request.
+ * However, when the response body for the initiating client-sent
+ * request has been fully received, the map is guaranteed to be fully
+ * populated, that is, no more entries will be added. The individual
+ * {@code CompletableFutures} contained in the map may or may not
+ * already be completed at this point.
+ *
+ * @param the push promise response body type
+ * @param pushPromiseHandler t he body handler to use for push promises
+ * @param pushPromisesMap a map to accumulate push promises into
+ * @return a push promise handler
+ */
+ public static PushPromiseHandler
+ of(Function> pushPromiseHandler,
+ ConcurrentMap>> pushPromisesMap) {
+ return new PushPromisesHandlerWithMap<>(pushPromiseHandler, pushPromisesMap);
+ }
+ }
+
+ /**
+ * A {@code BodySubscriber} consumes response body bytes and converts them
+ * into a higher-level Java type. The class {@link BodySubscribers
+ * BodySubscriber} provides implementations of many common body subscribers.
+ *
+ * The object acts as a {@link Flow.Subscriber}<{@link List}<{@link
+ * ByteBuffer}>> to the HTTP client implementation, which publishes
+ * unmodifiable lists of read-only ByteBuffers containing the response body.
+ * The Flow of data, as well as the order of ByteBuffers in the Flow lists,
+ * is a strictly ordered representation of the response body. Both the Lists
+ * and the ByteBuffers, once passed to the subscriber, are no longer used by
+ * the HTTP client. The subscriber converts the incoming buffers of data to
+ * some higher-level Java type {@code T}.
+ *
+ *
The {@link #getBody()} method returns a
+ * {@link CompletionStage}<{@code T}> that provides the response body
+ * object. The {@code CompletionStage} must be obtainable at any time. When
+ * it completes depends on the nature of type {@code T}. In many cases,
+ * when {@code T} represents the entire body after being consumed then
+ * the {@code CompletionStage} completes after the body has been consumed.
+ * If {@code T} is a streaming type, such as {@link java.io.InputStream
+ * InputStream}, then it completes before the body has been read, because
+ * the calling code uses the {@code InputStream} to consume the data.
+ *
+ * @apiNote To ensure that all resources associated with the corresponding
+ * HTTP exchange are properly released, an implementation of {@code
+ * BodySubscriber} should ensure to {@link Flow.Subscription#request
+ * request} more data until one of {@link #onComplete() onComplete} or
+ * {@link #onError(Throwable) onError} are signalled, or {@link
+ * Flow.Subscription#request cancel} its {@linkplain
+ * #onSubscribe(Flow.Subscription) subscription} if unable or unwilling to
+ * do so. Calling {@code cancel} before exhausting the response body data
+ * may cause the underlying HTTP connection to be closed and prevent it
+ * from being reused for subsequent operations.
+ *
+ * @param the response body type
+ * @see BodySubscribers
+ * @since 11
+ */
+ public interface BodySubscriber
+ extends Flow.Subscriber> {
+
+ /**
+ * Returns a {@code CompletionStage} which when completed will return
+ * the response body object. This method can be called at any time
+ * relative to the other {@link Flow.Subscriber} methods and is invoked
+ * using the client's {@link HttpClient#executor() executor}.
+ *
+ * @return a CompletionStage for the response body
+ */
+ public CompletionStage getBody();
+ }
+
+ /**
+ * Implementations of {@link BodySubscriber BodySubscriber} that implement
+ * various useful subscribers, such as converting the response body bytes
+ * into a String, or streaming the bytes to a file.
+ *
+ * The following are examples of using the predefined body subscribers
+ * to convert a flow of response body data into common high-level Java
+ * objects:
+ *
+ *
{@code // Streams the response body to a File
+ * HttpResponse response = client
+ * .send(request, (statusCode, responseHeaders) -> BodySubscribers.ofByteArray());
+ *
+ * // Accumulates the response body and returns it as a byte[]
+ * HttpResponse response = client
+ * .send(request, (statusCode, responseHeaders) -> BodySubscribers.ofByteArray());
+ *
+ * // Discards the response body
+ * HttpResponse response = client
+ * .send(request, (statusCode, responseHeaders) -> BodySubscribers.discarding());
+ *
+ * // Accumulates the response body as a String then maps it to its bytes
+ * HttpResponse response = client
+ * .send(request, (sc, hdrs) ->
+ * BodySubscribers.mapping(BodySubscribers.ofString(), String::getBytes));
+ * }
+ *
+ * @since 11
+ */
+ public static class BodySubscribers {
+
+ private BodySubscribers() { }
+
+ /**
+ * Returns a body subscriber that forwards all response body to the
+ * given {@code Flow.Subscriber}. The {@linkplain BodySubscriber#getBody()
+ * completion stage} of the returned body subscriber completes after one
+ * of the given subscribers {@code onComplete} or {@code onError} has
+ * been invoked.
+ *
+ * @apiNote This method can be used as an adapter between {@code
+ * BodySubscriber} and {@code Flow.Subscriber}.
+ *
+ * @param subscriber the subscriber
+ * @return a body subscriber
+ */
+ public static BodySubscriber
+ fromSubscriber(Subscriber super List> subscriber) {
+ return new ResponseSubscribers.SubscriberAdapter<>(subscriber, s -> null);
+ }
+
+ /**
+ * Returns a body subscriber that forwards all response body to the
+ * given {@code Flow.Subscriber}. The {@linkplain BodySubscriber#getBody()
+ * completion stage} of the returned body subscriber completes after one
+ * of the given subscribers {@code onComplete} or {@code onError} has
+ * been invoked.
+ *
+ * The given {@code finisher} function is applied after the given
+ * subscriber's {@code onComplete} has been invoked. The {@code finisher}
+ * function is invoked with the given subscriber, and returns a value
+ * that is set as the response's body.
+ *
+ * @apiNote This method can be used as an adapter between {@code
+ * BodySubscriber} and {@code Flow.Subscriber}.
+ *
+ * @param the type of the Subscriber
+ * @param the type of the response body
+ * @param subscriber the subscriber
+ * @param finisher a function to be applied after the subscriber has
+ * completed
+ * @return a body subscriber
+ */
+ public static >,T> BodySubscriber
+ fromSubscriber(S subscriber,
+ Function super S,? extends T> finisher) {
+ return new ResponseSubscribers.SubscriberAdapter<>(subscriber, finisher);
+ }
+
+ /**
+ * Returns a body subscriber that forwards all response body to the
+ * given {@code Flow.Subscriber}, line by line.
+ * The {@linkplain BodySubscriber#getBody() completion
+ * stage} of the returned body subscriber completes after one of the
+ * given subscribers {@code onComplete} or {@code onError} has been
+ * invoked.
+ * Bytes are decoded using the {@link StandardCharsets#UTF_8
+ * UTF-8} charset, and lines are delimited in the manner of
+ * {@link BufferedReader#readLine()}.
+ *
+ * @apiNote This method can be used as an adapter between {@code
+ * BodySubscriber} and {@code Flow.Subscriber}.
+ *
+ * @implNote This is equivalent to calling {@code
+ * fromLineSubscriber(subscriber, s -> null, StandardCharsets.UTF_8, null)
+ * }
+ *
+ * @param subscriber the subscriber
+ * @return a body subscriber
+ */
+ public static BodySubscriber
+ fromLineSubscriber(Subscriber super String> subscriber) {
+ return fromLineSubscriber(subscriber, s -> null,
+ StandardCharsets.UTF_8, null);
+ }
+
+ /**
+ * Returns a body subscriber that forwards all response body to the
+ * given {@code Flow.Subscriber}, line by line. The {@linkplain
+ * BodySubscriber#getBody() completion stage} of the returned body
+ * subscriber completes after one of the given subscribers
+ * {@code onComplete} or {@code onError} has been invoked.
+ *
+ * The given {@code finisher} function is applied after the given
+ * subscriber's {@code onComplete} has been invoked. The {@code finisher}
+ * function is invoked with the given subscriber, and returns a value
+ * that is set as the response's body.
+ *
+ * @apiNote This method can be used as an adapter between {@code
+ * BodySubscriber} and {@code Flow.Subscriber}.
+ *
+ * @param the type of the Subscriber
+ * @param the type of the response body
+ * @param subscriber the subscriber
+ * @param finisher a function to be applied after the subscriber has
+ * completed
+ * @param charset a {@link Charset} to decode the bytes
+ * @param lineSeparator an optional line separator: can be {@code null},
+ * in which case lines will be delimited in the manner of
+ * {@link BufferedReader#readLine()}.
+ * @return a body subscriber
+ * @throws IllegalArgumentException if the supplied {@code lineSeparator}
+ * is the empty string
+ */
+ public static ,T> BodySubscriber
+ fromLineSubscriber(S subscriber,
+ Function super S,? extends T> finisher,
+ Charset charset,
+ String lineSeparator) {
+ return LineSubscriberAdapter.create(subscriber,
+ finisher, charset, lineSeparator);
+ }
+
+ /**
+ * Returns a body subscriber which stores the response body as a {@code
+ * String} converted using the given {@code Charset}.
+ *
+ * The {@link HttpResponse} using this subscriber is available after
+ * the entire response has been read.
+ *
+ * @param charset the character set to convert the String with
+ * @return a body subscriber
+ */
+ public static BodySubscriber ofString(Charset charset) {
+ Objects.requireNonNull(charset);
+ return new ResponseSubscribers.ByteArraySubscriber<>(
+ bytes -> new String(bytes, charset)
+ );
+ }
+
+ /**
+ * Returns a {@code BodySubscriber} which stores the response body as a
+ * byte array.
+ *
+ * The {@link HttpResponse} using this subscriber is available after
+ * the entire response has been read.
+ *
+ * @return a body subscriber
+ */
+ public static BodySubscriber ofByteArray() {
+ return new ResponseSubscribers.ByteArraySubscriber<>(
+ Function.identity() // no conversion
+ );
+ }
+
+ /**
+ * Returns a {@code BodySubscriber} which stores the response body in a
+ * file opened with the given options and name. The file will be opened
+ * with the given options using {@link FileChannel#open(Path,OpenOption...)
+ * FileChannel.open} just before the body is read. Any exception thrown
+ * will be returned or thrown from {@link HttpClient#send(HttpRequest,
+ * BodyHandler) HttpClient::send} or {@link HttpClient#sendAsync(HttpRequest,
+ * BodyHandler) HttpClient::sendAsync} as appropriate.
+ *
+ * The {@link HttpResponse} using this subscriber is available after
+ * the entire response has been read.
+ *
+ *
Security manager permission checks are performed in this factory
+ * method, when the {@code BodySubscriber} is created. Care must be taken
+ * that the {@code BodyHandler} is not shared with untrusted code.
+ *
+ * @param file the file to store the body in
+ * @param openOptions the list of options to open the file with
+ * @return a body subscriber
+ * @throws IllegalArgumentException if an invalid set of open options
+ * are specified
+ * @throws SecurityException if a security manager has been installed
+ * and it denies {@link SecurityManager#checkWrite(String)
+ * write access} to the file
+ */
+ public static BodySubscriber ofFile(Path file, OpenOption... openOptions) {
+ Objects.requireNonNull(file);
+ List