{@code
* U result = identity;
* for (T element : this stream)
diff --git a/src/java.base/share/classes/java/util/zip/GZIPInputStream.java b/src/java.base/share/classes/java/util/zip/GZIPInputStream.java
index ebcb9e3204c..72fb8036f08 100644
--- a/src/java.base/share/classes/java/util/zip/GZIPInputStream.java
+++ b/src/java.base/share/classes/java/util/zip/GZIPInputStream.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2026, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2024, 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
@@ -79,11 +79,7 @@ public class GZIPInputStream extends InflaterInputStream {
super(in, createInflater(in, size), size);
usesDefaultInflater = true;
try {
- // we don't expect the stream to be at EOF
- // and if it is, then we want readHeader to
- // raise an exception, so we pass "true" for
- // the "failOnEOF" param.
- readHeader(in, true);
+ readHeader(in);
} catch (IOException ioe) {
this.inf.end();
throw ioe;
@@ -194,40 +190,12 @@ public class GZIPInputStream extends InflaterInputStream {
/*
* Reads GZIP member header and returns the total byte number
* of this member header.
- * If failOnEOF is false and if the given InputStream has already
- * reached EOF when this method was invoked, then this method returns
- * -1 (indicating that there's no GZIP member header).
- * In all other cases of malformed header or EOF being detected
- * when reading the header, this method will throw an IOException.
*/
- private int readHeader(InputStream this_in, boolean failOnEOF) throws IOException {
+ private int readHeader(InputStream this_in) throws IOException {
CheckedInputStream in = new CheckedInputStream(this_in, crc);
crc.reset();
-
- int magic;
- if (!failOnEOF) {
- // read an unsigned short value representing the GZIP magic header.
- // this is the same as calling readUShort(in), except that here,
- // when reading the first byte, we don't raise an EOFException
- // if the stream has already reached EOF.
-
- // read unsigned byte
- int b = in.read();
- if (b == -1) { // EOF
- crc.reset();
- return -1; // represents no header bytes available
- }
- checkUnexpectedByte(b);
- // read the next unsigned byte to form the unsigned
- // short. we throw the usual EOFException/ZipException
- // from this point on if there is no more data or
- // the data doesn't represent a header.
- magic = (readUByte(in) << 8) | b;
- } else {
- magic = readUShort(in);
- }
// Check header magic
- if (magic != GZIP_MAGIC) {
+ if (readUShort(in) != GZIP_MAGIC) {
throw new ZipException("Not in GZIP format");
}
// Check compression method
@@ -290,21 +258,23 @@ public class GZIPInputStream extends InflaterInputStream {
(readUInt(in) != (inf.getBytesWritten() & 0xffffffffL)))
throw new ZipException("Corrupt GZIP trailer");
+ // If there are more bytes available in "in" or
+ // the leftover in the "inf" is > 26 bytes:
+ // this.trailer(8) + next.header.min(10) + next.trailer(8)
// try concatenated case
- int m = 8; // this.trailer
- try {
- int numNextHeaderBytes = readHeader(in, false); // next.header (if available)
- if (numNextHeaderBytes == -1) {
- return true; // end of stream reached
+ if (this.in.available() > 0 || n > 26) {
+ int m = 8; // this.trailer
+ try {
+ m += readHeader(in); // next.header
+ } catch (IOException ze) {
+ return true; // ignore any malformed, do nothing
}
- m += numNextHeaderBytes;
- } catch (IOException ze) {
- return true; // ignore any malformed, do nothing
+ inf.reset();
+ if (n > m)
+ inf.setInput(buf, len - n + m, n - m);
+ return false;
}
- inf.reset();
- if (n > m)
- inf.setInput(buf, len - n + m, n - m);
- return false;
+ return true;
}
/*
@@ -331,16 +301,12 @@ public class GZIPInputStream extends InflaterInputStream {
if (b == -1) {
throw new EOFException();
}
- checkUnexpectedByte(b);
- return b;
- }
-
- private void checkUnexpectedByte(final int b) throws IOException {
if (b < -1 || b > 255) {
- // report the InputStream type which returned this unexpected byte
+ // Report on this.in, not argument in; see read{Header, Trailer}.
throw new IOException(this.in.getClass().getName()
- + ".read() returned value out of range -1..255: " + b);
+ + ".read() returned value out of range -1..255: " + b);
}
+ return b;
}
private byte[] tmpbuf = new byte[128];
diff --git a/src/java.base/share/classes/jdk/internal/access/JavaSecurityPropertiesAccess.java b/src/java.base/share/classes/jdk/internal/access/JavaSecurityPropertiesAccess.java
index a4875f357e3..2d9dbea052a 100644
--- a/src/java.base/share/classes/jdk/internal/access/JavaSecurityPropertiesAccess.java
+++ b/src/java.base/share/classes/jdk/internal/access/JavaSecurityPropertiesAccess.java
@@ -29,4 +29,5 @@ import java.util.Properties;
public interface JavaSecurityPropertiesAccess {
Properties getInitialProperties();
+ Properties getCurrentProperties();
}
diff --git a/src/java.base/share/classes/jdk/internal/vm/VMSupport.java b/src/java.base/share/classes/jdk/internal/vm/VMSupport.java
index 197da0d456c..32c358340af 100644
--- a/src/java.base/share/classes/jdk/internal/vm/VMSupport.java
+++ b/src/java.base/share/classes/jdk/internal/vm/VMSupport.java
@@ -98,6 +98,11 @@ public class VMSupport {
return serializePropertiesToByteArray(onlyStrings(System.getProperties()));
}
+ public static byte[] serializeSecurityPropertiesToByteArray() throws IOException {
+ Properties p = SharedSecrets.getJavaSecurityPropertiesAccess().getCurrentProperties();
+ return serializePropertiesToByteArray(onlyStrings(p));
+ }
+
public static byte[] serializeAgentPropertiesToByteArray() throws IOException {
return serializePropertiesToByteArray(onlyStrings(getAgentProperties()));
}
diff --git a/src/java.base/share/classes/sun/security/provider/DigestBase.java b/src/java.base/share/classes/sun/security/provider/DigestBase.java
index 2aaf0a2fac6..0bb15ef3efe 100644
--- a/src/java.base/share/classes/sun/security/provider/DigestBase.java
+++ b/src/java.base/share/classes/sun/security/provider/DigestBase.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2026, 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
@@ -242,4 +242,21 @@ abstract class DigestBase extends MessageDigestSpi implements Cloneable {
padding = new byte[136];
padding[0] = (byte)0x80;
}
+
+ /**
+ * Digest block-length bytes in a single operation.
+ * Subclasses are expected to override this method. It is intended
+ * for fixed-length short input where input includes padding bytes.
+ * @param input byte array to be digested
+ * @param inLen the length of the input
+ * @param output the output buffer
+ * @param outOffset the offset into output buffer where digest should be written
+ * @param outLen the length of the output buffer
+ * @throws UnsupportedOperationException if a subclass does not override this method
+ */
+ void implDigestFixedLengthPreprocessed (
+ byte[] input, int inLen, byte[] output, int outOffset, int outLen)
+ throws UnsupportedOperationException {
+ throw new UnsupportedOperationException("should not be here");
+ }
}
diff --git a/src/java.base/share/classes/sun/security/provider/HSS.java b/src/java.base/share/classes/sun/security/provider/HSS.java
index c1cb5ed6a30..50afba7cab8 100644
--- a/src/java.base/share/classes/sun/security/provider/HSS.java
+++ b/src/java.base/share/classes/sun/security/provider/HSS.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2023, 2026, 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
@@ -24,16 +24,22 @@
*/
package sun.security.provider;
+import java.io.ByteArrayOutputStream;
+import java.io.InvalidObjectException;
+import java.io.Serial;
+import java.io.Serializable;
+import java.security.SecureRandom;
+import java.security.*;
+import java.security.spec.AlgorithmParameterSpec;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.KeySpec;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.Arrays;
+
import sun.security.util.*;
import sun.security.x509.AlgorithmId;
import sun.security.x509.X509Key;
-import java.io.*;
-import java.security.*;
-import java.security.SecureRandom;
-import java.security.spec.*;
-import java.util.Arrays;
-
/**
* Implementation of the Hierarchical Signature System using the
* Leighton-Micali Signatures (HSS/LMS) as described in RFC 8554 and
@@ -196,42 +202,94 @@ public final class HSS extends SignatureSpi {
static class LMSUtils {
static final int LMS_RESERVED = 0;
- static final int LMS_SHA256_M32_H5 = 5;
- static final int LMS_SHA256_M32_H10 = 6;
- static final int LMS_SHA256_M32_H15 = 7;
- static final int LMS_SHA256_M32_H20 = 8;
- static final int LMS_SHA256_M32_H25 = 9;
+ static final int LMS_SHA256_M32_H5 = 0x05;
+ static final int LMS_SHA256_M32_H10 = 0x06;
+ static final int LMS_SHA256_M32_H15 = 0x07;
+ static final int LMS_SHA256_M32_H20 = 0x08;
+ static final int LMS_SHA256_M32_H25 = 0x09;
+ static final int LMS_SHA256_M24_H5 = 0x0a;
+ static final int LMS_SHA256_M24_H10 = 0x0b;
+ static final int LMS_SHA256_M24_H15 = 0x0c;
+ static final int LMS_SHA256_M24_H20 = 0x0d;
+ static final int LMS_SHA256_M24_H25 = 0x0e;
+ static final int LMS_SHAKE_M32_H5 = 0x0f;
+ static final int LMS_SHAKE_M32_H10 = 0x10;
+ static final int LMS_SHAKE_M32_H15 = 0x11;
+ static final int LMS_SHAKE_M32_H20 = 0x12;
+ static final int LMS_SHAKE_M32_H25 = 0x13;
+ static final int LMS_SHAKE_M24_H5 = 0x14;
+ static final int LMS_SHAKE_M24_H10 = 0x15;
+ static final int LMS_SHAKE_M24_H15 = 0x16;
+ static final int LMS_SHAKE_M24_H20 = 0x17;
+ static final int LMS_SHAKE_M24_H25 = 0x18;
static String lmsType(int type) {
- String typeStr;
- switch (type) {
- case LMS_RESERVED: typeStr = "LMS_RESERVED"; break;
- case LMS_SHA256_M32_H5: typeStr = "LMS_SHA256_M32_H5"; break;
- case LMS_SHA256_M32_H10: typeStr = "LMS_SHA256_M32_H10"; break;
- case LMS_SHA256_M32_H15: typeStr = "LMS_SHA256_M32_H15"; break;
- case LMS_SHA256_M32_H20: typeStr = "LMS_SHA256_M32_H20"; break;
- case LMS_SHA256_M32_H25: typeStr = "LMS_SHA256_M32_H25"; break;
- default: typeStr = "unrecognized";
- }
+ String typeStr = switch (type) {
+ case LMS_RESERVED -> "LMS_RESERVED";
+ case LMS_SHA256_M32_H5 -> "LMS_SHA256_M32_H5";
+ case LMS_SHA256_M32_H10 -> "LMS_SHA256_M32_H10";
+ case LMS_SHA256_M32_H15 -> "LMS_SHA256_M32_H15";
+ case LMS_SHA256_M32_H20 -> "LMS_SHA256_M32_H20";
+ case LMS_SHA256_M32_H25 -> "LMS_SHA256_M32_H25";
+ case LMS_SHA256_M24_H5 -> "LMS_SHA256_M24_H5";
+ case LMS_SHA256_M24_H10 -> "LMS_SHA256_M24_H10";
+ case LMS_SHA256_M24_H15 -> "LMS_SHA256_M24_H15";
+ case LMS_SHA256_M24_H20 -> "LMS_SHA256_M24_H20";
+ case LMS_SHA256_M24_H25 -> "LMS_SHA256_M24_H25";
+ case LMS_SHAKE_M32_H5 -> "LMS_SHAKE_M32_H5";
+ case LMS_SHAKE_M32_H10 -> "LMS_SHAKE_M32_H10";
+ case LMS_SHAKE_M32_H15 -> "LMS_SHAKE_M32_H15";
+ case LMS_SHAKE_M32_H20 -> "LMS_SHAKE_M32_H20";
+ case LMS_SHAKE_M32_H25 -> "LMS_SHAKE_M32_H25";
+ case LMS_SHAKE_M24_H5 -> "LMS_SHAKE_M24_H5";
+ case LMS_SHAKE_M24_H10 -> "LMS_SHAKE_M24_H10";
+ case LMS_SHAKE_M24_H15 -> "LMS_SHAKE_M24_H15";
+ case LMS_SHAKE_M24_H20 -> "LMS_SHAKE_M24_H20";
+ case LMS_SHAKE_M24_H25 -> "LMS_SHAKE_M24_H25";
+ default -> "unrecognized";
+ };
return typeStr;
}
static final int LMOTS_RESERVED = 0;
- static final int LMOTS_SHA256_N32_W1 = 1;
- static final int LMOTS_SHA256_N32_W2 = 2;
- static final int LMOTS_SHA256_N32_W4 = 3;
- static final int LMOTS_SHA256_N32_W8 = 4;
+ static final int LMOTS_SHA256_N32_W1 = 0x01;
+ static final int LMOTS_SHA256_N32_W2 = 0x02;
+ static final int LMOTS_SHA256_N32_W4 = 0x03;
+ static final int LMOTS_SHA256_N32_W8 = 0x04;
+ static final int LMOTS_SHA256_N24_W1 = 0x05;
+ static final int LMOTS_SHA256_N24_W2 = 0x06;
+ static final int LMOTS_SHA256_N24_W4 = 0x07;
+ static final int LMOTS_SHA256_N24_W8 = 0x08;
+ static final int LMOTS_SHAKE_N32_W1 = 0x09;
+ static final int LMOTS_SHAKE_N32_W2 = 0x0a;
+ static final int LMOTS_SHAKE_N32_W4 = 0x0b;
+ static final int LMOTS_SHAKE_N32_W8 = 0x0c;
+ static final int LMOTS_SHAKE_N24_W1 = 0x0d;
+ static final int LMOTS_SHAKE_N24_W2 = 0x0e;
+ static final int LMOTS_SHAKE_N24_W4 = 0x0f;
+ static final int LMOTS_SHAKE_N24_W8 = 0x10;
static String lmotsType(int type) {
- String typeStr;
- switch (type) {
- case LMOTS_RESERVED: typeStr = "LMOTS_RESERVED"; break;
- case LMOTS_SHA256_N32_W1: typeStr = "LMOTS_SHA256_N32_W1"; break;
- case LMOTS_SHA256_N32_W2: typeStr = "LMOTS_SHA256_N32_W2"; break;
- case LMOTS_SHA256_N32_W4: typeStr = "LMOTS_SHA256_N32_W4"; break;
- case LMOTS_SHA256_N32_W8: typeStr = "LMOTS_SHA256_N32_W8"; break;
- default: typeStr = "unrecognized";
- }
+ String typeStr = switch (type) {
+ case LMOTS_RESERVED -> "LMOTS_RESERVED";
+ case LMOTS_SHA256_N32_W1 -> "LMOTS_SHA256_N32_W1";
+ case LMOTS_SHA256_N32_W2 -> "LMOTS_SHA256_N32_W2";
+ case LMOTS_SHA256_N32_W4 -> "LMOTS_SHA256_N32_W4";
+ case LMOTS_SHA256_N32_W8 -> "LMOTS_SHA256_N32_W8";
+ case LMOTS_SHA256_N24_W1 -> "LMOTS_SHA256_N24_W1";
+ case LMOTS_SHA256_N24_W2 -> "LMOTS_SHA256_N24_W2";
+ case LMOTS_SHA256_N24_W4 -> "LMOTS_SHA256_N24_W4";
+ case LMOTS_SHA256_N24_W8 -> "LMOTS_SHA256_N24_W8";
+ case LMOTS_SHAKE_N32_W1 -> "LMOTS_SHAKE_N32_W1";
+ case LMOTS_SHAKE_N32_W2 -> "LMOTS_SHAKE_N32_W2";
+ case LMOTS_SHAKE_N32_W4 -> "LMOTS_SHAKE_N32_W4";
+ case LMOTS_SHAKE_N32_W8 -> "LMOTS_SHAKE_N32_W8";
+ case LMOTS_SHAKE_N24_W1 -> "LMOTS_SHAKE_N24_W1";
+ case LMOTS_SHAKE_N24_W2 -> "LMOTS_SHAKE_N24_W2";
+ case LMOTS_SHAKE_N24_W4 -> "LMOTS_SHAKE_N24_W4";
+ case LMOTS_SHAKE_N24_W8 -> "LMOTS_SHAKE_N24_W8";
+ default -> "unrecognized";
+ };
return typeStr;
}
@@ -352,53 +410,65 @@ public final class HSS extends SignatureSpi {
static class LMSParams {
final int m; // the number of bytes used from the hash output
- final int hashAlg_m = 32; // output length of the LMS tree hash function
+ final int hashAlg_m; // output length of the LMS tree hash function
final int h; // height of the LMS tree
final int twoPowh;
final String hashAlgStr;
- LMSParams(int m, int h, String hashAlgStr) {
+ private LMSParams(int m, int h, String hashAlgStr, int hashAlg_m) {
this.m = m;
this.h = h;
this.hashAlgStr = hashAlgStr;
+ this.hashAlg_m = hashAlg_m;
twoPowh = 1 << h;
}
static LMSParams of(int type) {
- int m;
- int h;
- String hashAlgStr;
- switch (type) {
- case LMSUtils.LMS_SHA256_M32_H5:
- m = 32;
- h = 5;
- hashAlgStr = "SHA-256";
- break;
- case LMSUtils.LMS_SHA256_M32_H10:
- m = 32;
- h = 10;
- hashAlgStr = "SHA-256";
- break;
- case LMSUtils.LMS_SHA256_M32_H15:
- m = 32;
- h = 15;
- hashAlgStr = "SHA-256";
- break;
- case LMSUtils.LMS_SHA256_M32_H20:
- m = 32;
- h = 20;
- hashAlgStr = "SHA-256";
- break;
- case LMSUtils.LMS_SHA256_M32_H25:
- m = 32;
- h = 25;
- hashAlgStr = "SHA-256";
- break;
- default:
+ LMSParams params = switch (type) {
+ case LMSUtils.LMS_SHA256_M32_H5 ->
+ new LMSParams(32, 5, "SHA-256", 32);
+ case LMSUtils.LMS_SHA256_M32_H10 ->
+ new LMSParams(32, 10, "SHA-256", 32);
+ case LMSUtils.LMS_SHA256_M32_H15 ->
+ new LMSParams(32, 15, "SHA-256", 32);
+ case LMSUtils.LMS_SHA256_M32_H20 ->
+ new LMSParams(32, 20, "SHA-256", 32);
+ case LMSUtils.LMS_SHA256_M32_H25 ->
+ new LMSParams(32, 25, "SHA-256", 32);
+ case LMSUtils.LMS_SHA256_M24_H5 ->
+ new LMSParams(24, 5, "SHA-256", 32);
+ case LMSUtils.LMS_SHA256_M24_H10 ->
+ new LMSParams(24, 10, "SHA-256", 32);
+ case LMSUtils.LMS_SHA256_M24_H15 ->
+ new LMSParams(24, 15, "SHA-256", 32);
+ case LMSUtils.LMS_SHA256_M24_H20 ->
+ new LMSParams(24, 20, "SHA-256", 32);
+ case LMSUtils.LMS_SHA256_M24_H25 ->
+ new LMSParams(24, 25, "SHA-256", 32);
+ case LMSUtils.LMS_SHAKE_M32_H5 ->
+ new LMSParams(32, 5, "SHAKE256-512", 64);
+ case LMSUtils.LMS_SHAKE_M32_H10 ->
+ new LMSParams(32, 10, "SHAKE256-512", 64);
+ case LMSUtils.LMS_SHAKE_M32_H15 ->
+ new LMSParams(32, 15, "SHAKE256-512", 64);
+ case LMSUtils.LMS_SHAKE_M32_H20 ->
+ new LMSParams(32, 20, "SHAKE256-512", 64);
+ case LMSUtils.LMS_SHAKE_M32_H25 ->
+ new LMSParams(32, 25, "SHAKE256-512", 64);
+ case LMSUtils.LMS_SHAKE_M24_H5 ->
+ new LMSParams(24, 5, "SHAKE256-512", 64);
+ case LMSUtils.LMS_SHAKE_M24_H10 ->
+ new LMSParams(24, 10, "SHAKE256-512", 64);
+ case LMSUtils.LMS_SHAKE_M24_H15 ->
+ new LMSParams(24, 15, "SHAKE256-512", 64);
+ case LMSUtils.LMS_SHAKE_M24_H20 ->
+ new LMSParams(24, 20, "SHAKE256-512", 64);
+ case LMSUtils.LMS_SHAKE_M24_H25 ->
+ new LMSParams(24, 25, "SHAKE256-512", 64);
+ default ->
throw new IllegalArgumentException("Unsupported or bad LMS type");
- }
-
- return new LMSParams(m, h, hashAlgStr);
+ };
+ return params;
}
boolean hasSameHash(LMSParams other) {
@@ -495,7 +565,7 @@ public final class HSS extends SignatureSpi {
static class LMOTSParams {
final int lmotSigType;
final int n; // the number of bytes used from the hash output
- final int hashAlg_n = 32; // the output length of the hash function
+ int hashAlg_n; // the output length of the hash function
final int w;
final int twoPowWMinus1;
final int ls;
@@ -511,6 +581,7 @@ public final class HSS extends SignatureSpi {
// back into the buffer. This way, we avoid memory allocations and some
// computations that would have to be done otherwise.
final byte[] hashBuf;
+
// Precomputed block for SHA256 when the message size is 55 bytes
// (i.e. when SHA256 is used)
private static final byte[] hashbufSha256_32 = {
@@ -523,10 +594,64 @@ public final class HSS extends SignatureSpi {
0, 0, 0, 0, 0, 0, 0, (byte) 0x80,
0, 0, 0, 0, 0, 0, 1, (byte) 0xb8
};
+ // Precomputed block for SHA256 when the message size is 47 bytes
+ // (i.e. when SHA256-192 is used)
+ private static final byte[] hashbufSha256_24 = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, (byte) 0x80,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 1, 0x78
+ };
+ // Precomputed block for SHAKE256 when the message size is 55 bytes
+ // (i.e. when SHAKE256 is used)
+ private static final byte[] hashbufShake256_32 = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, (byte) 0x1F,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, (byte) 0x80
+ };
+ // Precomputed block for SHAKE256 when the message size is 47 bytes
+ // (i.e. when SHAKE256-192 is used)
+ private static final byte[] hashbufShake256_24 = {
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, (byte) 0x1F,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, (byte) 0x80
+ };
private LMOTSParams(
int lmotSigType, int hLen, int w,
- int ls, int p, String hashAlgName) {
+ int ls, int p, String hashAlgName, int hashAlg_n) {
this.lmotSigType = lmotSigType;
this.n = hLen;
this.w = w;
@@ -534,32 +659,60 @@ public final class HSS extends SignatureSpi {
this.p = p;
twoPowWMinus1 = (1 << w) - 1;
this.hashAlgName = hashAlgName;
- hashBuf = hashbufSha256_32;
+ this.hashAlg_n = hashAlg_n;
+ hashBuf = switch (hashAlgName) {
+ case "SHAKE256-512" -> {
+ yield this.n == 24 ?
+ hashbufShake256_24 : hashbufShake256_32;
+ }
+ case "SHA-256" -> {
+ yield this.n == 24 ?
+ hashbufSha256_24 : hashbufSha256_32;
+ }
+ default ->
+ throw new IllegalArgumentException(
+ "Unknown hash algorithm "+hashAlgName);
+ };
}
static LMOTSParams of(int lmotsType) {
- LMOTSParams params;
- switch (lmotsType) {
- case LMSUtils.LMOTS_SHA256_N32_W1:
- params = new LMOTSParams(
- lmotsType, 32, 1, 7, 265, "SHA-256");
- break;
- case LMSUtils.LMOTS_SHA256_N32_W2:
- params = new LMOTSParams(
- lmotsType, 32, 2, 6, 133, "SHA-256");
- break;
- case LMSUtils.LMOTS_SHA256_N32_W4:
- params = new LMOTSParams(
- lmotsType, 32, 4, 4, 67, "SHA-256");
- break;
- case LMSUtils.LMOTS_SHA256_N32_W8:
- params = new LMOTSParams(
- lmotsType, 32, 8, 0, 34, "SHA-256");
- break;
- default:
+ LMOTSParams params = switch (lmotsType) {
+ case LMSUtils.LMOTS_SHA256_N32_W1 ->
+ new LMOTSParams(lmotsType, 32, 1, 7, 265, "SHA-256", 32);
+ case LMSUtils.LMOTS_SHA256_N32_W2 ->
+ new LMOTSParams(lmotsType, 32, 2, 6, 133, "SHA-256", 32);
+ case LMSUtils.LMOTS_SHA256_N32_W4 ->
+ new LMOTSParams(lmotsType, 32, 4, 4, 67, "SHA-256", 32);
+ case LMSUtils.LMOTS_SHA256_N32_W8 ->
+ new LMOTSParams(lmotsType, 32, 8, 0, 34, "SHA-256", 32);
+ case LMSUtils.LMOTS_SHA256_N24_W1 ->
+ new LMOTSParams(lmotsType, 24, 1, 8, 200, "SHA-256", 32);
+ case LMSUtils.LMOTS_SHA256_N24_W2 ->
+ new LMOTSParams(lmotsType, 24, 2, 6, 101, "SHA-256", 32);
+ case LMSUtils.LMOTS_SHA256_N24_W4 ->
+ new LMOTSParams(lmotsType, 24, 4, 4, 51, "SHA-256", 32);
+ case LMSUtils.LMOTS_SHA256_N24_W8 ->
+ new LMOTSParams(lmotsType, 24, 8, 0, 26, "SHA-256", 32);
+ case LMSUtils.LMOTS_SHAKE_N32_W1 ->
+ new LMOTSParams(lmotsType, 32, 1, 7, 265, "SHAKE256-512", 64);
+ case LMSUtils.LMOTS_SHAKE_N32_W2 ->
+ new LMOTSParams(lmotsType, 32, 2, 6, 133, "SHAKE256-512", 64);
+ case LMSUtils.LMOTS_SHAKE_N32_W4 ->
+ new LMOTSParams(lmotsType, 32, 4, 4, 67, "SHAKE256-512", 64);
+ case LMSUtils.LMOTS_SHAKE_N32_W8 ->
+ new LMOTSParams(lmotsType, 32, 8, 0, 34, "SHAKE256-512", 64);
+ case LMSUtils.LMOTS_SHAKE_N24_W1 ->
+ new LMOTSParams(lmotsType, 24, 1, 8, 200, "SHAKE256-512", 64);
+ case LMSUtils.LMOTS_SHAKE_N24_W2 ->
+ new LMOTSParams(lmotsType, 24, 2, 6, 101, "SHAKE256-512", 64);
+ case LMSUtils.LMOTS_SHAKE_N24_W4 ->
+ new LMOTSParams(lmotsType, 24, 4, 4, 51, "SHAKE256-512", 64);
+ case LMSUtils.LMOTS_SHAKE_N24_W8 ->
+ new LMOTSParams(lmotsType, 24, 8, 0, 26, "SHAKE256-512", 64);
+ default ->
throw new IllegalArgumentException(
"Unsupported or bad OTS Algorithm Identifier.");
- }
+ };
return params;
}
@@ -580,13 +733,6 @@ public final class HSS extends SignatureSpi {
S[len + 1] = (byte) (sum & 0xff);
}
- void digestFixedLengthPreprocessed(
- SHA2.SHA256 sha256, byte[] input, int inLen,
- byte[] output, int outOffset, int outLen) {
- sha256.implDigestFixedLengthPreprocessed(
- input, inLen, output, outOffset, outLen);
- }
-
byte[] lmotsPubKeyCandidate(
LMSignature lmSig, byte[] message, LMSPublicKey pKey)
throws SignatureException {
@@ -625,7 +771,13 @@ public final class HSS extends SignatureSpi {
byte[] preZi = hashBuf.clone();
int hashLen = hashBuf.length;
- SHA2.SHA256 sha256 = new SHA2.SHA256();
+
+ DigestBase db;
+ if (hashAlgName.startsWith("SHAKE")) {
+ db = new SHA3.SHAKE256Hash();
+ } else {
+ db = new SHA2.SHA256();
+ }
pKey.getI(preZi, 0);
lmSig.getQArr(preZi, 16);
@@ -643,11 +795,11 @@ public final class HSS extends SignatureSpi {
for (int j = a; j < twoPowWMinus1; j++) {
preZi[22] = (byte) j;
if (j < twoPowWMinus2) {
- digestFixedLengthPreprocessed(
- sha256, preZi, hashLen, preZi, 23, n);
+ db.implDigestFixedLengthPreprocessed(preZi,
+ hashLen, preZi, 23, n);
} else {
- digestFixedLengthPreprocessed(
- sha256, preZi, hashLen, preCandidate, 22 + i * n, n);
+ db.implDigestFixedLengthPreprocessed(preZi,
+ hashLen, preCandidate, 22 + i * n, n);
}
}
}
diff --git a/src/java.base/share/classes/sun/security/provider/SHA2.java b/src/java.base/share/classes/sun/security/provider/SHA2.java
index e966e6b77f8..7d8c2840de9 100644
--- a/src/java.base/share/classes/sun/security/provider/SHA2.java
+++ b/src/java.base/share/classes/sun/security/provider/SHA2.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2026, 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
@@ -117,6 +117,7 @@ abstract class SHA2 extends DigestBase {
}
+ @Override
protected void implDigestFixedLengthPreprocessed(
byte[] input, int inLen, byte[] output, int outOffset, int outLen) {
implReset();
diff --git a/src/java.base/share/classes/sun/security/provider/SHA3.java b/src/java.base/share/classes/sun/security/provider/SHA3.java
index a096cac5f50..0578645c1cd 100644
--- a/src/java.base/share/classes/sun/security/provider/SHA3.java
+++ b/src/java.base/share/classes/sun/security/provider/SHA3.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2026, 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
@@ -98,6 +98,15 @@ public abstract class SHA3 extends DigestBase {
this.suffix = suffix;
}
+ @Override
+ protected void implDigestFixedLengthPreprocessed(
+ byte[] input, int inLen, byte[] output, int outOffset, int outLen) {
+ implReset();
+
+ implCompress(input, 0);
+ implDigest0(output, outOffset, outLen);
+ }
+
private void implCompressCheck(byte[] b, int ofs) {
Objects.requireNonNull(b);
Preconditions.checkIndex(ofs + blockSize - 1, b.length, Preconditions.AIOOBE_FORMATTER);
@@ -136,9 +145,6 @@ public abstract class SHA3 extends DigestBase {
* DigestBase calls implReset() when necessary.
*/
void implDigest(byte[] out, int ofs) {
- // Moving this allocation to the block where it is used causes a little
- // performance drop, that is why it is here.
- byte[] byteState = new byte[8];
if (engineGetDigestLength() == 0) {
// This is an XOF, so the digest() call is illegal.
throw new ProviderException("Calling digest() is not allowed in an XOF");
@@ -146,8 +152,12 @@ public abstract class SHA3 extends DigestBase {
finishAbsorb();
+ implDigest0(out, ofs, engineGetDigestLength());
+ }
+
+ void implDigest0(byte[] out, int ofs, int outLen) {
int availableBytes = blockSize;
- int numBytes = engineGetDigestLength();
+ int numBytes = outLen;
while (numBytes > availableBytes) {
for (int i = 0; i < availableBytes / 8; i++) {
@@ -163,6 +173,10 @@ public abstract class SHA3 extends DigestBase {
asLittleEndian.set(out, ofs, state[i]);
ofs += 8;
}
+
+ // Moving this allocation to the block where it is used causes a little
+ // performance drop, that is why it is here.
+ byte[] byteState = new byte[8];
if (numBytes % 8 != 0) {
asLittleEndian.set(byteState, 0, state[numLongs]);
System.arraycopy(byteState, 0, out, ofs, numBytes % 8);
diff --git a/src/java.base/share/classes/sun/security/ssl/Alert.java b/src/java.base/share/classes/sun/security/ssl/Alert.java
index fb06b02a5d4..e9588a09b3d 100644
--- a/src/java.base/share/classes/sun/security/ssl/Alert.java
+++ b/src/java.base/share/classes/sun/security/ssl/Alert.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2026, 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
@@ -281,6 +281,8 @@ public enum Alert {
// consumer so the state machine doesn't expect it.
tc.handshakeContext.handshakeConsumers.remove(
SSLHandshake.CERTIFICATE.id);
+ tc.handshakeContext.handshakeConsumers.remove(
+ SSLHandshake.COMPRESSED_CERTIFICATE.id);
tc.handshakeContext.handshakeConsumers.remove(
SSLHandshake.CERTIFICATE_VERIFY.id);
}
diff --git a/src/java.base/share/classes/sun/security/ssl/CertificateMessage.java b/src/java.base/share/classes/sun/security/ssl/CertificateMessage.java
index c6897d71aa6..af5007d7899 100644
--- a/src/java.base/share/classes/sun/security/ssl/CertificateMessage.java
+++ b/src/java.base/share/classes/sun/security/ssl/CertificateMessage.java
@@ -781,14 +781,6 @@ final class CertificateMessage {
}
}
- T13CertificateMessage(HandshakeContext handshakeContext,
- byte[] requestContext, List certificates) {
- super(handshakeContext);
-
- this.requestContext = requestContext.clone();
- this.certEntries = certificates;
- }
-
T13CertificateMessage(HandshakeContext handshakeContext,
ByteBuffer m) throws IOException {
super(handshakeContext);
@@ -925,16 +917,26 @@ final class CertificateMessage {
HandshakeMessage message) throws IOException {
// The producing happens in handshake context only.
HandshakeContext hc = (HandshakeContext)context;
- if (hc.sslConfig.isClientMode) {
- return onProduceCertificate(
- (ClientHandshakeContext)context, message);
- } else {
- return onProduceCertificate(
+ T13CertificateMessage cm = hc.sslConfig.isClientMode ?
+ onProduceCertificate(
+ (ClientHandshakeContext)context, message) :
+ onProduceCertificate(
(ServerHandshakeContext)context, message);
+
+ // Output the handshake message.
+ if (hc.certDeflater == null) {
+ cm.write(hc.handshakeOutput);
+ hc.handshakeOutput.flush();
+ } else {
+ // Replace with CompressedCertificate message
+ CompressedCertificate.handshakeProducer.produce(hc, cm);
}
+
+ // The handshake message has been delivered.
+ return null;
}
- private byte[] onProduceCertificate(ServerHandshakeContext shc,
+ private T13CertificateMessage onProduceCertificate(ServerHandshakeContext shc,
HandshakeMessage message) throws IOException {
ClientHelloMessage clientHello = (ClientHelloMessage)message;
@@ -993,12 +995,7 @@ final class CertificateMessage {
SSLLogger.fine("Produced server Certificate message", cm);
}
- // Output the handshake message.
- cm.write(shc.handshakeOutput);
- shc.handshakeOutput.flush();
-
- // The handshake message has been delivered.
- return null;
+ return cm;
}
private static SSLPossession choosePossession(
@@ -1045,7 +1042,7 @@ final class CertificateMessage {
return pos;
}
- private byte[] onProduceCertificate(ClientHandshakeContext chc,
+ private T13CertificateMessage onProduceCertificate(ClientHandshakeContext chc,
HandshakeMessage message) throws IOException {
ClientHelloMessage clientHello = (ClientHelloMessage)message;
SSLPossession pos = choosePossession(chc, clientHello);
@@ -1091,12 +1088,7 @@ final class CertificateMessage {
SSLLogger.fine("Produced client Certificate message", cm);
}
- // Output the handshake message.
- cm.write(chc.handshakeOutput);
- chc.handshakeOutput.flush();
-
- // The handshake message has been delivered.
- return null;
+ return cm;
}
}
@@ -1116,6 +1108,7 @@ final class CertificateMessage {
HandshakeContext hc = (HandshakeContext)context;
// clean up this consumer
+ hc.handshakeConsumers.remove(SSLHandshake.COMPRESSED_CERTIFICATE.id);
hc.handshakeConsumers.remove(SSLHandshake.CERTIFICATE.id);
// Ensure that the Certificate message has not been sent w/o
diff --git a/src/java.base/share/classes/sun/security/ssl/CertificateRequest.java b/src/java.base/share/classes/sun/security/ssl/CertificateRequest.java
index 039399560cd..2eceb4d9ebd 100644
--- a/src/java.base/share/classes/sun/security/ssl/CertificateRequest.java
+++ b/src/java.base/share/classes/sun/security/ssl/CertificateRequest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2026, 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
@@ -956,6 +956,11 @@ final class CertificateRequest {
// update
//
shc.certRequestContext = crm.requestContext.clone();
+ if (shc.certInflaters != null && !shc.certInflaters.isEmpty()) {
+ shc.handshakeConsumers.put(
+ SSLHandshake.COMPRESSED_CERTIFICATE.id,
+ SSLHandshake.COMPRESSED_CERTIFICATE);
+ }
shc.handshakeConsumers.put(SSLHandshake.CERTIFICATE.id,
SSLHandshake.CERTIFICATE);
shc.handshakeConsumers.put(SSLHandshake.CERTIFICATE_VERIFY.id,
diff --git a/src/java.base/share/classes/sun/security/ssl/CompressCertExtension.java b/src/java.base/share/classes/sun/security/ssl/CompressCertExtension.java
new file mode 100644
index 00000000000..eff97857ef0
--- /dev/null
+++ b/src/java.base/share/classes/sun/security/ssl/CompressCertExtension.java
@@ -0,0 +1,306 @@
+/*
+ * Copyright (C) 2022 THL A29 Limited, a Tencent company. All rights reserved.
+ * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.security.ssl;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.text.MessageFormat;
+import java.util.Locale;
+import java.util.Map;
+import java.util.function.Function;
+import javax.net.ssl.SSLProtocolException;
+import sun.security.ssl.SSLExtension.ExtensionConsumer;
+import sun.security.ssl.SSLExtension.SSLExtensionSpec;
+import sun.security.ssl.SSLHandshake.HandshakeMessage;
+
+/**
+ * Pack of the "compress_certificate" extensions [RFC 5246].
+ */
+final class CompressCertExtension {
+
+ static final HandshakeProducer chNetworkProducer =
+ new CHCompressCertificateProducer();
+ static final ExtensionConsumer chOnLoadConsumer =
+ new CHCompressCertificateConsumer();
+
+ static final HandshakeProducer crNetworkProducer =
+ new CRCompressCertificateProducer();
+ static final ExtensionConsumer crOnLoadConsumer =
+ new CRCompressCertificateConsumer();
+
+ static final SSLStringizer ccStringizer =
+ new CompressCertificateStringizer();
+
+ /**
+ * The "signature_algorithms" extension.
+ */
+ static final class CertCompressionSpec implements SSLExtensionSpec {
+
+ private final int[] compressionAlgorithms; // non-null
+
+ CertCompressionSpec(
+ Map> certInflaters) {
+ compressionAlgorithms = new int[certInflaters.size()];
+ int i = 0;
+ for (Integer id : certInflaters.keySet()) {
+ compressionAlgorithms[i++] = id;
+ }
+ }
+
+ CertCompressionSpec(HandshakeContext hc,
+ ByteBuffer buffer) throws IOException {
+ if (buffer.remaining() < 2) { // 2: the length of the list
+ throw hc.conContext.fatal(Alert.DECODE_ERROR,
+ new SSLProtocolException(
+ "Invalid compress_certificate: insufficient data"));
+ }
+
+ byte[] algs = Record.getBytes8(buffer);
+ if (buffer.hasRemaining()) {
+ throw hc.conContext.fatal(Alert.DECODE_ERROR,
+ new SSLProtocolException(
+ "Invalid compress_certificate: unknown extra data"));
+ }
+
+ if (algs.length == 0 || (algs.length & 0x01) != 0) {
+ throw hc.conContext.fatal(Alert.DECODE_ERROR,
+ new SSLProtocolException(
+ "Invalid compress_certificate: incomplete data"));
+ }
+
+ int[] compressionAlgs = new int[algs.length / 2];
+ for (int i = 0, j = 0; i < algs.length; ) {
+ byte hash = algs[i++];
+ byte sign = algs[i++];
+ compressionAlgs[j++] = ((hash & 0xFF) << 8) | (sign & 0xFF);
+ }
+
+ this.compressionAlgorithms = compressionAlgs;
+ }
+
+ @Override
+ public String toString() {
+ MessageFormat messageFormat = new MessageFormat(
+ "\"compression algorithms\": '['{0}']'", Locale.ENGLISH);
+
+ if (compressionAlgorithms.length == 0) {
+ Object[] messageFields = {
+ ""
+ };
+ return messageFormat.format(messageFields);
+ } else {
+ StringBuilder builder = new StringBuilder(512);
+ boolean isFirst = true;
+ for (int ca : compressionAlgorithms) {
+ if (isFirst) {
+ isFirst = false;
+ } else {
+ builder.append(", ");
+ }
+
+ builder.append(CompressionAlgorithm.nameOf(ca));
+ }
+
+ Object[] messageFields = {
+ builder.toString()
+ };
+
+ return messageFormat.format(messageFields);
+ }
+ }
+ }
+
+ private static final
+ class CompressCertificateStringizer implements SSLStringizer {
+
+ @Override
+ public String toString(HandshakeContext hc, ByteBuffer buffer) {
+ try {
+ return (new CertCompressionSpec(hc, buffer)).toString();
+ } catch (IOException ioe) {
+ // For debug logging only, so please swallow exceptions.
+ return ioe.getMessage();
+ }
+ }
+ }
+
+ /**
+ * Network data producer of a "compress_certificate" extension in
+ * the ClientHello handshake message.
+ */
+ private static final
+ class CHCompressCertificateProducer implements HandshakeProducer {
+
+ // Prevent instantiation of this class.
+ private CHCompressCertificateProducer() {
+ // blank
+ }
+
+ @Override
+ public byte[] produce(ConnectionContext context,
+ HandshakeMessage message) throws IOException {
+ // The producing happens in client side only.
+ return produceCompCertExt(context,
+ SSLExtension.CH_COMPRESS_CERTIFICATE);
+ }
+ }
+
+ /**
+ * Network data consumer of a "compress_certificate" extension in
+ * the ClientHello handshake message.
+ */
+ private static final
+ class CHCompressCertificateConsumer implements ExtensionConsumer {
+
+ // Prevent instantiation of this class.
+ private CHCompressCertificateConsumer() {
+ // blank
+ }
+
+ @Override
+ public void consume(ConnectionContext context,
+ HandshakeMessage message, ByteBuffer buffer)
+ throws IOException {
+ // The consuming happens in server side only.
+ consumeCompCertExt(context, buffer,
+ SSLExtension.CH_COMPRESS_CERTIFICATE);
+ }
+ }
+
+ /**
+ * Network data producer of a "compress_certificate" extension in
+ * the CertificateRequest handshake message.
+ */
+ private static final
+ class CRCompressCertificateProducer implements HandshakeProducer {
+
+ // Prevent instantiation of this class.
+ private CRCompressCertificateProducer() {
+ // blank
+ }
+
+ @Override
+ public byte[] produce(ConnectionContext context,
+ HandshakeMessage message) throws IOException {
+ // The producing happens in server side only.
+ return produceCompCertExt(context,
+ SSLExtension.CR_COMPRESS_CERTIFICATE);
+ }
+ }
+
+ /**
+ * Network data consumer of a "compress_certificate" extension in
+ * the CertificateRequest handshake message.
+ */
+ private static final
+ class CRCompressCertificateConsumer implements ExtensionConsumer {
+
+ // Prevent instantiation of this class.
+ private CRCompressCertificateConsumer() {
+ // blank
+ }
+
+ @Override
+ public void consume(ConnectionContext context,
+ HandshakeMessage message, ByteBuffer buffer)
+ throws IOException {
+ // The consuming happens in client side only.
+ consumeCompCertExt(context, buffer,
+ SSLExtension.CR_COMPRESS_CERTIFICATE);
+ }
+ }
+
+ private static byte[] produceCompCertExt(
+ ConnectionContext context, SSLExtension extension)
+ throws IOException {
+
+ HandshakeContext hc = (HandshakeContext) context;
+ // Is it a supported and enabled extension?
+ if (!hc.sslConfig.isAvailable(extension)) {
+ if (SSLLogger.isOn() && SSLLogger.isOn(SSLLogger.Opt.HANDSHAKE)) {
+ SSLLogger.fine("Ignore unavailable " +
+ "compress_certificate extension");
+ }
+ return null;
+ }
+
+ // Produce the extension.
+ hc.certInflaters = CompressionAlgorithm.getInflaters();
+
+ if (hc.certInflaters.isEmpty()) {
+ if (SSLLogger.isOn() && SSLLogger.isOn(SSLLogger.Opt.HANDSHAKE)) {
+ SSLLogger.warning("Unable to produce the extension: "
+ + "no certificate compression inflaters defined");
+ }
+ return null;
+ }
+
+ int vectorLen = CompressionAlgorithm.sizeInRecord() *
+ hc.certInflaters.size();
+ byte[] extData = new byte[vectorLen + 1];
+ ByteBuffer m = ByteBuffer.wrap(extData);
+ Record.putInt8(m, vectorLen);
+ for (Integer algId : hc.certInflaters.keySet()) {
+ Record.putInt16(m, algId);
+ }
+
+ // Update the context.
+ hc.handshakeExtensions.put(
+ extension, new CertCompressionSpec(hc.certInflaters));
+
+ return extData;
+ }
+
+ private static void consumeCompCertExt(ConnectionContext context,
+ ByteBuffer buffer, SSLExtension extension) throws IOException {
+
+ HandshakeContext hc = (HandshakeContext) context;
+ // Is it a supported and enabled extension?
+ if (!hc.sslConfig.isAvailable(extension)) {
+ if (SSLLogger.isOn() && SSLLogger.isOn(SSLLogger.Opt.HANDSHAKE)) {
+ SSLLogger.fine("Ignore unavailable " +
+ "compress_certificate extension");
+ }
+ return; // ignore the extension
+ }
+
+ // Parse the extension.
+ CertCompressionSpec spec = new CertCompressionSpec(hc, buffer);
+
+ // Update the context.
+ hc.certDeflater = CompressionAlgorithm.selectDeflater(
+ spec.compressionAlgorithms);
+
+ if (hc.certDeflater == null) {
+ if (SSLLogger.isOn() && SSLLogger.isOn(SSLLogger.Opt.HANDSHAKE)) {
+ SSLLogger.fine("Ignore, no supported " +
+ "certificate compression algorithms");
+ }
+ }
+ // No impact on session resumption.
+ }
+}
diff --git a/src/java.base/share/classes/sun/security/ssl/CompressedCertificate.java b/src/java.base/share/classes/sun/security/ssl/CompressedCertificate.java
new file mode 100644
index 00000000000..067a0344c9d
--- /dev/null
+++ b/src/java.base/share/classes/sun/security/ssl/CompressedCertificate.java
@@ -0,0 +1,264 @@
+/*
+ * Copyright (C) 2022 THL A29 Limited, a Tencent company. All rights reserved.
+ * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.security.ssl;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.text.MessageFormat;
+import java.util.Locale;
+import java.util.function.Function;
+import javax.net.ssl.SSLProtocolException;
+import sun.security.ssl.SSLHandshake.HandshakeMessage;
+import sun.security.util.Cache;
+import sun.security.util.Cache.EqualByteArray;
+import sun.security.util.HexDumpEncoder;
+
+/**
+ * Pack of the CompressedCertificate handshake message.
+ */
+final class CompressedCertificate {
+
+ static final SSLConsumer handshakeConsumer =
+ new CompressedCertConsumer();
+ static final HandshakeProducer handshakeProducer =
+ new CompressedCertProducer();
+
+ record CompCertCacheKey(EqualByteArray eba, int algId) {}
+
+ /**
+ * The CompressedCertificate handshake message for TLS 1.3.
+ */
+ static final class CompressedCertMessage extends HandshakeMessage {
+
+ private final int algorithmId;
+ private final int uncompressedLength;
+ private final byte[] compressedCert;
+
+ CompressedCertMessage(HandshakeContext context,
+ int algorithmId, int uncompressedLength,
+ byte[] compressedCert) {
+ super(context);
+
+ this.algorithmId = algorithmId;
+ this.uncompressedLength = uncompressedLength;
+ this.compressedCert = compressedCert;
+ }
+
+ CompressedCertMessage(HandshakeContext handshakeContext,
+ ByteBuffer m) throws IOException {
+ super(handshakeContext);
+
+ // struct {
+ // CertificateCompressionAlgorithm algorithm;
+ // uint24 uncompressed_length;
+ // opaque compressed_certificate_message<1..2^24-1>;
+ // } CompressedCertificate;
+ if (m.remaining() < 9) {
+ throw new SSLProtocolException(
+ "Invalid CompressedCertificate message: " +
+ "insufficient data (length=" + m.remaining()
+ + ")");
+ }
+ this.algorithmId = Record.getInt16(m);
+ this.uncompressedLength = Record.getInt24(m);
+ this.compressedCert = Record.getBytes24(m);
+
+ if (m.hasRemaining()) {
+ throw handshakeContext.conContext.fatal(
+ Alert.HANDSHAKE_FAILURE,
+ "Invalid CompressedCertificate message: " +
+ "unknown extra data");
+ }
+ }
+
+ @Override
+ public SSLHandshake handshakeType() {
+ return SSLHandshake.COMPRESSED_CERTIFICATE;
+ }
+
+ @Override
+ public int messageLength() {
+ return 8 + compressedCert.length;
+ }
+
+ @Override
+ public void send(HandshakeOutStream hos) throws IOException {
+ hos.putInt16(algorithmId);
+ hos.putInt24(uncompressedLength);
+ hos.putBytes24(compressedCert);
+ }
+
+ @Override
+ public String toString() {
+ MessageFormat messageFormat = new MessageFormat(
+ """
+ "CompressedCertificate": '{'
+ "algorithm": "{0}",
+ "uncompressed_length": {1}
+ "compressed_certificate_message": [
+ {2}
+ ]
+ '}'""",
+ Locale.ENGLISH);
+
+ HexDumpEncoder hexEncoder = new HexDumpEncoder();
+ Object[] messageFields = {
+ CompressionAlgorithm.nameOf(algorithmId),
+ uncompressedLength,
+ Utilities.indent(hexEncoder.encode(compressedCert), " ")
+ };
+
+ return messageFormat.format(messageFields);
+ }
+ }
+
+ /**
+ * The "CompressedCertificate" handshake message producer for TLS 1.3.
+ */
+ private static final
+ class CompressedCertProducer implements HandshakeProducer {
+
+ // Prevent instantiation of this class.
+ private CompressedCertProducer() {
+ // blank
+ }
+
+ // Note this is a special producer, which can only be called from
+ // the CertificateMessage producer. The input 'message' parameter
+ // represents the Certificate handshake message.
+ @Override
+ public byte[] produce(ConnectionContext context,
+ HandshakeMessage message) throws IOException {
+ // The producing happens in handshake context only.
+ HandshakeContext hc = (HandshakeContext) context;
+
+ // Compress the Certificate message.
+ HandshakeOutStream hos = new HandshakeOutStream(null);
+ message.send(hos);
+ byte[] certMsg = hos.toByteArray();
+ byte[] compressedCertMsg;
+
+ // First byte is the size of certificate_request_context which
+ // should be random if present. Don't cache a randomized message.
+ if (certMsg[0] != 0) {
+ compressedCertMsg = hc.certDeflater.getValue().apply(certMsg);
+ } else {
+ Cache cache =
+ hc.sslContext.getCompCertCache();
+ CompCertCacheKey key = new CompCertCacheKey(
+ new EqualByteArray(certMsg), hc.certDeflater.getKey());
+ compressedCertMsg = cache.get(key);
+
+ if (compressedCertMsg == null) {
+ compressedCertMsg =
+ hc.certDeflater.getValue().apply(certMsg);
+
+ if (SSLLogger.isOn()
+ && SSLLogger.isOn(SSLLogger.Opt.HANDSHAKE)) {
+ SSLLogger.fine("Caching CompressedCertificate message");
+ }
+
+ cache.put(key, compressedCertMsg);
+ }
+ }
+
+ if (compressedCertMsg == null || compressedCertMsg.length == 0) {
+ throw hc.conContext.fatal(Alert.HANDSHAKE_FAILURE,
+ "No compressed Certificate data");
+ }
+
+ CompressedCertMessage ccm = new CompressedCertMessage(hc,
+ hc.certDeflater.getKey(), certMsg.length,
+ compressedCertMsg);
+
+ if (SSLLogger.isOn() && SSLLogger.isOn(SSLLogger.Opt.HANDSHAKE)) {
+ SSLLogger.fine(
+ "Produced CompressedCertificate handshake message",
+ ccm);
+ }
+
+ ccm.write(hc.handshakeOutput);
+ hc.handshakeOutput.flush();
+
+ // The handshake message has been delivered.
+ return null;
+ }
+ }
+
+ /**
+ * The "CompressedCertificate" handshake message consumer for TLS 1.3.
+ */
+ private static final class CompressedCertConsumer implements SSLConsumer {
+
+ // Prevent instantiation of this class.
+ private CompressedCertConsumer() {
+ // blank
+ }
+
+ @Override
+ public void consume(ConnectionContext context,
+ ByteBuffer message) throws IOException {
+ // The consuming happens in handshake context only.
+ HandshakeContext hc = (HandshakeContext) context;
+
+ // clean up this consumer
+ hc.handshakeConsumers.remove(
+ SSLHandshake.COMPRESSED_CERTIFICATE.id);
+ hc.handshakeConsumers.remove(SSLHandshake.CERTIFICATE.id);
+
+ // Parse the handshake message
+ CompressedCertMessage ccm = new CompressedCertMessage(hc, message);
+ if (SSLLogger.isOn() && SSLLogger.isOn(SSLLogger.Opt.HANDSHAKE)) {
+ SSLLogger.fine(
+ "Consuming CompressedCertificate handshake message",
+ ccm);
+ }
+
+ // check the compression algorithm
+ Function inflater =
+ hc.certInflaters.get(ccm.algorithmId);
+ if (inflater == null) {
+ throw hc.conContext.fatal(Alert.BAD_CERTIFICATE,
+ "Unsupported certificate compression algorithm");
+ }
+
+ // decompress
+ byte[] certificateMessage = inflater.apply(ccm.compressedCert);
+
+ // check the uncompressed length
+ if (certificateMessage == null ||
+ certificateMessage.length != ccm.uncompressedLength) {
+ throw hc.conContext.fatal(Alert.BAD_CERTIFICATE,
+ "Improper certificate compression");
+ }
+
+ // Call the Certificate handshake message consumer.
+ CertificateMessage.t13HandshakeConsumer.consume(hc,
+ ByteBuffer.wrap(certificateMessage));
+ }
+ }
+}
diff --git a/src/java.base/share/classes/sun/security/ssl/CompressionAlgorithm.java b/src/java.base/share/classes/sun/security/ssl/CompressionAlgorithm.java
new file mode 100644
index 00000000000..3e9ef154424
--- /dev/null
+++ b/src/java.base/share/classes/sun/security/ssl/CompressionAlgorithm.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2022 THL A29 Limited, a Tencent company. All rights reserved.
+ * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.security.ssl;
+
+import java.io.ByteArrayOutputStream;
+import java.util.AbstractMap;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.zip.Deflater;
+import java.util.zip.Inflater;
+
+/**
+ * Enum for TLS certificate compression algorithms.
+ * This class also defines internally supported inflate/deflate functions.
+ */
+
+enum CompressionAlgorithm {
+ ZLIB(1); // Currently only ZLIB is supported.
+
+ final int id;
+
+ CompressionAlgorithm(int id) {
+ this.id = id;
+ }
+
+ static CompressionAlgorithm nameOf(int id) {
+ for (CompressionAlgorithm ca : CompressionAlgorithm.values()) {
+ if (ca.id == id) {
+ return ca;
+ }
+ }
+
+ return null;
+ }
+
+ // Return the size of a compression algorithms structure in TLS record.
+ static int sizeInRecord() {
+ return 2;
+ }
+
+ // The size of compression/decompression buffer.
+ private static final int BUF_SIZE = 1024;
+
+ private static final Map> DEFLATORS =
+ Map.of(ZLIB.id, (input) -> {
+ try (Deflater deflater = new Deflater();
+ ByteArrayOutputStream outputStream =
+ new ByteArrayOutputStream(input.length)) {
+
+ deflater.setInput(input);
+ deflater.finish();
+ byte[] buffer = new byte[BUF_SIZE];
+
+ while (!deflater.finished()) {
+ int compressedSize = deflater.deflate(buffer);
+ outputStream.write(buffer, 0, compressedSize);
+ }
+
+ return outputStream.toByteArray();
+ } catch (Exception e) {
+ if (SSLLogger.isOn()
+ && SSLLogger.isOn(SSLLogger.Opt.HANDSHAKE)) {
+ SSLLogger.warning("Exception during certificate "
+ + "compression: ", e);
+ }
+ return null;
+ }
+ });
+
+ static Map.Entry> selectDeflater(
+ int[] compressionAlgorithmIds) {
+
+ for (var entry : DEFLATORS.entrySet()) {
+ for (int id : compressionAlgorithmIds) {
+ if (id == entry.getKey()) {
+ return new AbstractMap.SimpleImmutableEntry<>(entry);
+ }
+ }
+ }
+
+ return null;
+ }
+
+ private static final Map> INFLATORS =
+ Map.of(ZLIB.id, (input) -> {
+ try (Inflater inflater = new Inflater();
+ ByteArrayOutputStream outputStream =
+ new ByteArrayOutputStream(input.length)) {
+
+ inflater.setInput(input);
+ byte[] buffer = new byte[BUF_SIZE];
+
+ while (!inflater.finished()) {
+ int decompressedSize = inflater.inflate(buffer);
+
+ if (decompressedSize == 0) {
+ if (inflater.needsDictionary()) {
+ if (SSLLogger.isOn()
+ && SSLLogger.isOn(
+ SSLLogger.Opt.HANDSHAKE)) {
+ SSLLogger.warning("Compressed input "
+ + "requires a dictionary");
+ }
+
+ return null;
+ }
+
+ if (inflater.needsInput()) {
+ if (SSLLogger.isOn()
+ && SSLLogger.isOn(
+ SSLLogger.Opt.HANDSHAKE)) {
+ SSLLogger.warning(
+ "Incomplete compressed input");
+ }
+
+ return null;
+ }
+
+ // Else just break the loop.
+ break;
+ }
+
+ outputStream.write(buffer, 0, decompressedSize);
+
+ // Bound the memory usage.
+ if (outputStream.size()
+ > SSLConfiguration.maxHandshakeMessageSize) {
+ if (SSLLogger.isOn()
+ && SSLLogger.isOn(
+ SSLLogger.Opt.HANDSHAKE)) {
+ SSLLogger.warning("The size of the "
+ + "uncompressed certificate message "
+ + "exceeds maximum allowed size of "
+ + SSLConfiguration.maxHandshakeMessageSize
+ + " bytes; compressed size: "
+ + input.length);
+ }
+
+ return null;
+ }
+ }
+
+ return outputStream.toByteArray();
+ } catch (Exception e) {
+ if (SSLLogger.isOn()
+ && SSLLogger.isOn(SSLLogger.Opt.HANDSHAKE)) {
+ SSLLogger.warning(
+ "Exception during certificate decompression: ",
+ e);
+ }
+ return null;
+ }
+ });
+
+ static Map> getInflaters() {
+ return INFLATORS;
+ }
+}
diff --git a/src/java.base/share/classes/sun/security/ssl/HandshakeContext.java b/src/java.base/share/classes/sun/security/ssl/HandshakeContext.java
index 54a2650c058..fbf2c00bbb4 100644
--- a/src/java.base/share/classes/sun/security/ssl/HandshakeContext.java
+++ b/src/java.base/share/classes/sun/security/ssl/HandshakeContext.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2026, 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
@@ -33,6 +33,7 @@ import java.security.AlgorithmConstraints;
import java.security.CryptoPrimitive;
import java.util.*;
import java.util.AbstractMap.SimpleImmutableEntry;
+import java.util.function.Function;
import javax.crypto.SecretKey;
import javax.net.ssl.SNIServerName;
import javax.net.ssl.SSLHandshakeException;
@@ -131,6 +132,10 @@ abstract class HandshakeContext implements ConnectionContext {
List peerRequestedSignatureSchemes;
List peerRequestedCertSignSchemes;
+ // CertificateCompressionAlgorithm
+ Map> certInflaters;
+ Map.Entry> certDeflater;
+
// Known authorities
X500Principal[] peerSupportedAuthorities = null;
diff --git a/src/java.base/share/classes/sun/security/ssl/QuicTLSEngineImpl.java b/src/java.base/share/classes/sun/security/ssl/QuicTLSEngineImpl.java
index b5f1eff179c..3384bf5f089 100644
--- a/src/java.base/share/classes/sun/security/ssl/QuicTLSEngineImpl.java
+++ b/src/java.base/share/classes/sun/security/ssl/QuicTLSEngineImpl.java
@@ -73,6 +73,7 @@ public final class QuicTLSEngineImpl implements QuicTLSEngine, SSLTransport {
SSLHandshake.ENCRYPTED_EXTENSIONS.id, HANDSHAKE,
SSLHandshake.CERTIFICATE_REQUEST.id, HANDSHAKE,
SSLHandshake.CERTIFICATE.id, HANDSHAKE,
+ SSLHandshake.COMPRESSED_CERTIFICATE.id, HANDSHAKE,
SSLHandshake.CERTIFICATE_VERIFY.id, HANDSHAKE,
SSLHandshake.FINISHED.id, HANDSHAKE,
SSLHandshake.NEW_SESSION_TICKET.id, ONE_RTT);
diff --git a/src/java.base/share/classes/sun/security/ssl/SSLContextImpl.java b/src/java.base/share/classes/sun/security/ssl/SSLContextImpl.java
index a1cc3ee112f..fdeb94bb496 100644
--- a/src/java.base/share/classes/sun/security/ssl/SSLContextImpl.java
+++ b/src/java.base/share/classes/sun/security/ssl/SSLContextImpl.java
@@ -34,7 +34,9 @@ import java.util.concurrent.locks.ReentrantLock;
import java.util.stream.Collectors;
import javax.net.ssl.*;
import sun.security.provider.certpath.AlgorithmChecker;
+import sun.security.ssl.CompressedCertificate.CompCertCacheKey;
import sun.security.ssl.SSLAlgorithmConstraints.SIGNATURE_CONSTRAINTS_MODE;
+import sun.security.util.Cache;
import sun.security.validator.Validator;
/**
@@ -73,6 +75,10 @@ public abstract class SSLContextImpl extends SSLContextSpi {
private final ReentrantLock contextLock = new ReentrantLock();
+ // Avoid compressing local certificates repeatedly for every handshake.
+ private final Cache compCertCache =
+ Cache.newSoftMemoryCache(12);
+
SSLContextImpl() {
ephemeralKeyManager = new EphemeralKeyManager();
clientCache = new SSLSessionContextImpl(false);
@@ -225,6 +231,10 @@ public abstract class SSLContextImpl extends SSLContextSpi {
return ephemeralKeyManager;
}
+ Cache getCompCertCache() {
+ return compCertCache;
+ }
+
// Used for DTLS in server mode only.
HelloCookieManager getHelloCookieManager(ProtocolVersion protocolVersion) {
if (helloCookieManagerBuilder == null) {
diff --git a/src/java.base/share/classes/sun/security/ssl/SSLExtension.java b/src/java.base/share/classes/sun/security/ssl/SSLExtension.java
index aacb9420748..b13edc0359c 100644
--- a/src/java.base/share/classes/sun/security/ssl/SSLExtension.java
+++ b/src/java.base/share/classes/sun/security/ssl/SSLExtension.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2026, 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
@@ -270,6 +270,27 @@ enum SSLExtension implements SSLStringizer {
// Extensions defined in RFC 7924 (TLS Cached Information Extension)
CACHED_INFO (0x0019, "cached_info"),
+ // Extensions defined in RFC 8879 (TLS Certificate Compression)
+ CH_COMPRESS_CERTIFICATE (0x001B, "compress_certificate",
+ SSLHandshake.CLIENT_HELLO,
+ ProtocolVersion.PROTOCOLS_OF_13,
+ CompressCertExtension.chNetworkProducer,
+ CompressCertExtension.chOnLoadConsumer,
+ null,
+ null,
+ null,
+ CompressCertExtension.ccStringizer),
+
+ CR_COMPRESS_CERTIFICATE (0x001B, "compress_certificate",
+ SSLHandshake.CERTIFICATE_REQUEST,
+ ProtocolVersion.PROTOCOLS_OF_13,
+ CompressCertExtension.crNetworkProducer,
+ CompressCertExtension.crOnLoadConsumer,
+ null,
+ null,
+ null,
+ CompressCertExtension.ccStringizer),
+
// Extensions defined in RFC 5077 (TLS Session Resumption without Server-Side State)
CH_SESSION_TICKET (0x0023, "session_ticket",
SSLHandshake.CLIENT_HELLO,
diff --git a/src/java.base/share/classes/sun/security/ssl/SSLHandshake.java b/src/java.base/share/classes/sun/security/ssl/SSLHandshake.java
index 7c78f6c3005..2c6b58bafa5 100644
--- a/src/java.base/share/classes/sun/security/ssl/SSLHandshake.java
+++ b/src/java.base/share/classes/sun/security/ssl/SSLHandshake.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2006, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 2026, 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,7 +370,22 @@ enum SSLHandshake implements SSLConsumer, HandshakeProducer {
}),
// RFC 8879 - TLS Certificate Compression
- COMPRESSED_CERTIFICATE ((byte)0x19, "compressed_certificate"),
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ COMPRESSED_CERTIFICATE ((byte)0x19, "compressed_certificate",
+ (new Map.Entry[] {
+ new SimpleImmutableEntry<>(
+ CompressedCertificate.handshakeConsumer,
+ ProtocolVersion.PROTOCOLS_OF_13
+ )
+ }),
+ (new Map.Entry[] {
+ // Note that the producing of this message is delegated to
+ // CertificateMessage producer.
+ new SimpleImmutableEntry<>(
+ CertificateMessage.t13HandshakeProducer,
+ ProtocolVersion.PROTOCOLS_OF_13
+ )
+ })),
// RFC 8870 - Encrypted Key Transport for DTLS/Secure RTP
EKT_KEY ((byte)0x1A, "ekt_key"),
diff --git a/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java b/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java
index f603cc22949..cef2f43526a 100644
--- a/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java
+++ b/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2026, 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
@@ -28,13 +28,13 @@ package sun.security.ssl;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
-import java.io.InterruptedIOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.SocketException;
+import java.net.SocketTimeoutException;
import java.nio.ByteBuffer;
import java.util.List;
import java.util.concurrent.TimeUnit;
@@ -77,10 +77,10 @@ public final class SSLSocketImpl
/**
* ERROR HANDLING GUIDELINES
* (which exceptions to throw and catch and which not to throw and catch)
- *
+ *
* - if there is an IOException (SocketException) when accessing the
* underlying Socket, pass it through
- *
+ *
* - do not throw IOExceptions, throw SSLExceptions (or a subclass)
*/
@@ -454,12 +454,12 @@ public final class SSLSocketImpl
if (!conContext.isNegotiated) {
readHandshakeRecord();
}
- } catch (InterruptedIOException iioe) {
+ } catch (SocketTimeoutException e) {
if(resumable){
- handleException(iioe);
+ handleException(e);
} else{
throw conContext.fatal(Alert.HANDSHAKE_FAILURE,
- "Couldn't kickstart handshaking", iioe);
+ "Couldn't kickstart handshaking", e);
}
} catch (SocketException se) {
handleException(se);
@@ -1427,7 +1427,7 @@ public final class SSLSocketImpl
return 0;
}
} catch (SSLException |
- InterruptedIOException | SocketException se) {
+ SocketTimeoutException | SocketException se) {
// Don't change exception in case of timeouts or interrupts
// or SocketException.
throw se;
@@ -1486,7 +1486,7 @@ public final class SSLSocketImpl
return buffer;
}
} catch (SSLException |
- InterruptedIOException | SocketException se) {
+ SocketTimeoutException | SocketException se) {
// Don't change exception in case of timeouts or interrupts
// or SocketException.
throw se;
@@ -1677,40 +1677,23 @@ public final class SSLSocketImpl
SSLLogger.warning("handling exception", cause);
}
- // Don't close the Socket in case of timeouts or interrupts.
- if (cause instanceof InterruptedIOException) {
- throw (IOException)cause;
- }
-
- // need to perform error shutdown
- boolean isSSLException = (cause instanceof SSLException);
- Alert alert;
- if (isSSLException) {
- if (cause instanceof SSLHandshakeException) {
- alert = Alert.HANDSHAKE_FAILURE;
- } else {
- alert = Alert.UNEXPECTED_MESSAGE;
+ throw switch (cause) {
+ // Don't close the Socket in case of timeouts.
+ case SocketTimeoutException ste -> ste;
+ // Send TLS alert with "fatal", then throw the socket exception.
+ case SocketException se -> {
+ try {
+ throw conContext.fatal(Alert.UNEXPECTED_MESSAGE, se);
+ } catch (Exception _) {
+ }
+ yield se;
}
- } else {
- if (cause instanceof IOException) {
- alert = Alert.UNEXPECTED_MESSAGE;
- } else {
- // RuntimeException
- alert = Alert.INTERNAL_ERROR;
- }
- }
-
- if (cause instanceof SocketException) {
- try {
- throw conContext.fatal(alert, cause);
- } catch (Exception e) {
- // Just delivering the fatal alert, re-throw the socket exception instead.
- }
-
- throw (SocketException)cause;
- }
-
- throw conContext.fatal(alert, cause);
+ case SSLHandshakeException sslhe ->
+ conContext.fatal(Alert.HANDSHAKE_FAILURE, sslhe);
+ case IOException ioe ->
+ conContext.fatal(Alert.UNEXPECTED_MESSAGE, ioe);
+ default -> conContext.fatal(Alert.INTERNAL_ERROR, cause);
+ };
}
private Plaintext handleEOF(EOFException eofe) throws IOException {
diff --git a/src/java.base/share/classes/sun/security/ssl/SSLSocketInputRecord.java b/src/java.base/share/classes/sun/security/ssl/SSLSocketInputRecord.java
index fd9c4b171e7..fc3d9733150 100644
--- a/src/java.base/share/classes/sun/security/ssl/SSLSocketInputRecord.java
+++ b/src/java.base/share/classes/sun/security/ssl/SSLSocketInputRecord.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2026, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, Azul Systems, Inc. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@@ -27,10 +27,10 @@
package sun.security.ssl;
import java.io.EOFException;
-import java.io.InterruptedIOException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.net.SocketTimeoutException;
import java.nio.ByteBuffer;
import java.security.GeneralSecurityException;
import java.util.ArrayList;
@@ -180,7 +180,7 @@ final class SSLSocketInputRecord extends InputRecord implements SSLRecord {
if (plaintext == null) {
plaintext = decodeInputRecord();
}
- } catch(InterruptedIOException e) {
+ } catch (SocketTimeoutException e) {
// do not clean header and recordBody in case of Socket Timeout
cleanInBuffer = false;
throw e;
diff --git a/src/java.base/share/classes/sun/security/ssl/SSLTransport.java b/src/java.base/share/classes/sun/security/ssl/SSLTransport.java
index 50bff1e6d21..02551b4a8c1 100644
--- a/src/java.base/share/classes/sun/security/ssl/SSLTransport.java
+++ b/src/java.base/share/classes/sun/security/ssl/SSLTransport.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2026, 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 @@ package sun.security.ssl;
import java.io.EOFException;
import java.io.IOException;
-import java.io.InterruptedIOException;
import java.net.SocketException;
+import java.net.SocketTimeoutException;
import java.nio.ByteBuffer;
import javax.crypto.AEADBadTagException;
import javax.crypto.BadPaddingException;
@@ -138,7 +138,7 @@ interface SSLTransport {
} catch (EOFException eofe) {
// rethrow EOFException, the call will handle it if needed.
throw eofe;
- } catch (InterruptedIOException | SocketException se) {
+ } catch (SocketTimeoutException | SocketException se) {
// don't close the Socket in case of timeouts or interrupts or SocketException.
throw se;
} catch (IOException ioe) {
diff --git a/src/java.base/share/classes/sun/security/ssl/ServerHello.java b/src/java.base/share/classes/sun/security/ssl/ServerHello.java
index 6980c216697..4bd2b0a059f 100644
--- a/src/java.base/share/classes/sun/security/ssl/ServerHello.java
+++ b/src/java.base/share/classes/sun/security/ssl/ServerHello.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2026, 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
@@ -1461,6 +1461,11 @@ final class ServerHello {
chc.handshakeConsumers.put(
SSLHandshake.CERTIFICATE_REQUEST.id,
SSLHandshake.CERTIFICATE_REQUEST);
+ if (chc.certInflaters != null && !chc.certInflaters.isEmpty()) {
+ chc.handshakeConsumers.put(
+ SSLHandshake.COMPRESSED_CERTIFICATE.id,
+ SSLHandshake.COMPRESSED_CERTIFICATE);
+ }
chc.handshakeConsumers.put(
SSLHandshake.CERTIFICATE.id,
SSLHandshake.CERTIFICATE);
diff --git a/src/java.base/share/classes/sun/security/util/KeyUtil.java b/src/java.base/share/classes/sun/security/util/KeyUtil.java
index 942a91d61b8..e9dabdc5b06 100644
--- a/src/java.base/share/classes/sun/security/util/KeyUtil.java
+++ b/src/java.base/share/classes/sun/security/util/KeyUtil.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2026, 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
@@ -444,15 +444,16 @@ public final class KeyUtil {
// is the LMS public key for the top-level tree.
// Section 5.3: LMS public key is u32str(type) || u32str(otstype) || I || T[1]
// Section 8: type is the numeric identifier for an LMS specification.
- // This RFC defines 5 SHA-256 based types, value from 5 to 9.
if (rawKey.length < 8) {
throw new NoSuchAlgorithmException("Cannot decode public key");
}
int num = ((rawKey[4] & 0xff) << 24) + ((rawKey[5] & 0xff) << 16)
+ ((rawKey[6] & 0xff) << 8) + (rawKey[7] & 0xff);
return switch (num) {
- // RFC 8554 only supports SHA_256 hash algorithm
+ // RFC 8554 only supports SHA_256 hash algorithms
case 5, 6, 7, 8, 9 -> AlgorithmId.SHA256_oid;
+ // RFC 9858 supports SHAKE_256 hash algorithms
+ case 15, 16, 17, 18, 19 -> AlgorithmId.SHAKE256_512_oid;
default -> throw new NoSuchAlgorithmException("Unknown LMS type: " + num);
};
} catch (IOException e) {
diff --git a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessible.java b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessible.java
index 5be7f70b981..4315abe6197 100644
--- a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessible.java
+++ b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessible.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2026, 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,6 @@ final class CAccessible extends CFRetainedResource implements Accessible {
// Do send check box state changes to native side
if (thisRole == AccessibleRole.CHECK_BOX) {
- if (!Objects.equals(newValue, oldValue)) {
- valueChanged(ptr);
- }
-
// Notify native side to handle check box style menuitem
if (parentRole == AccessibleRole.POPUP_MENU && newValue != null
&& ((AccessibleState)newValue) == AccessibleState.FOCUSED) {
@@ -201,23 +197,12 @@ final class CAccessible extends CFRetainedResource implements Accessible {
// Do send radio button state changes to native side
if (thisRole == AccessibleRole.RADIO_BUTTON) {
- if (newValue != null && !newValue.equals(oldValue)) {
- valueChanged(ptr);
- }
-
// Notify native side to handle radio button style menuitem
if (parentRole == AccessibleRole.POPUP_MENU && newValue != null
&& ((AccessibleState)newValue) == AccessibleState.FOCUSED) {
menuItemSelected(ptr);
}
}
-
- // Do send toggle button state changes to native side
- if (thisRole == AccessibleRole.TOGGLE_BUTTON) {
- if (!Objects.equals(newValue, oldValue)) {
- valueChanged(ptr);
- }
- }
} else if (name.equals(ACCESSIBLE_NAME_PROPERTY)) {
//for now trigger only for JTabbedPane.
if (e.getSource() instanceof JTabbedPane) {
@@ -227,7 +212,10 @@ final class CAccessible extends CFRetainedResource implements Accessible {
AccessibleRole thisRole = accessible.getAccessibleContext()
.getAccessibleRole();
if (thisRole == AccessibleRole.SLIDER ||
- thisRole == AccessibleRole.PROGRESS_BAR) {
+ thisRole == AccessibleRole.PROGRESS_BAR ||
+ thisRole == AccessibleRole.CHECK_BOX ||
+ thisRole == AccessibleRole.RADIO_BUTTON ||
+ thisRole == AccessibleRole.TOGGLE_BUTTON ) {
valueChanged(ptr);
}
}
diff --git a/src/java.desktop/share/classes/sun/font/ExtendedTextSourceLabel.java b/src/java.desktop/share/classes/sun/font/ExtendedTextSourceLabel.java
index f3569941321..78ae70629b6 100644
--- a/src/java.desktop/share/classes/sun/font/ExtendedTextSourceLabel.java
+++ b/src/java.desktop/share/classes/sun/font/ExtendedTextSourceLabel.java
@@ -57,15 +57,16 @@ import java.util.Map;
* Align bounds is a rect that defines how to align this to margins.
* it generally allows some overhang that logical bounds would prevent.
*/
-class ExtendedTextSourceLabel implements TextLineComponent, Decoration.Label {
+final class ExtendedTextSourceLabel implements TextLineComponent, Decoration.Label {
private final TextSource source;
private final Decoration decorator;
// caches
- private Font font;
- private AffineTransform baseTX;
- private CoreMetrics cm;
+ private final Font font;
+ private final AffineTransform baseTX;
+ private final CoreMetrics cm;
+ private final float advTracking;
private Rectangle2D lb;
private Rectangle2D ab;
@@ -74,34 +75,18 @@ class ExtendedTextSourceLabel implements TextLineComponent, Decoration.Label {
private StandardGlyphVector gv;
private float[] charinfo;
- private float advTracking;
-
/**
* Create from a TextSource.
*/
public ExtendedTextSourceLabel(TextSource source, Decoration decorator) {
this.source = source;
this.decorator = decorator;
- finishInit();
- }
-
- /**
- * Create from a TextSource, optionally using cached data from oldLabel starting at the offset.
- * If present oldLabel must have been created from a run of text that includes the text used in
- * the new label. Start in source corresponds to logical character offset in oldLabel.
- */
- public ExtendedTextSourceLabel(TextSource source, ExtendedTextSourceLabel oldLabel, int offset) {
- // currently no optimization.
- this.source = source;
- this.decorator = oldLabel.decorator;
- finishInit();
- }
-
- private void finishInit() {
- font = source.getFont();
+ Font font = source.getFont();
Map atts = font.getAttributes();
- baseTX = AttributeValues.getBaselineTransform(atts);
+ AffineTransform baseTX = AttributeValues.getBaselineTransform(atts);
+
+ CoreMetrics cm;
if (baseTX == null){
cm = source.getCoreMetrics();
} else {
@@ -110,13 +95,15 @@ class ExtendedTextSourceLabel implements TextLineComponent, Decoration.Label {
charTX = new AffineTransform();
}
font = font.deriveFont(charTX);
-
LineMetrics lm = font.getLineMetrics(source.getChars(), source.getStart(),
source.getStart() + source.getLength(), source.getFRC());
cm = CoreMetrics.get(lm);
}
- advTracking = font.getSize() * AttributeValues.getTracking(atts);
+ this.font = font;
+ this.baseTX = baseTX;
+ this.cm = cm;
+ this.advTracking = font.getSize() * AttributeValues.getTracking(atts);
}
/**
diff --git a/src/java.desktop/share/classes/sun/font/GlyphLayout.java b/src/java.desktop/share/classes/sun/font/GlyphLayout.java
index 5bff127f143..851201fe347 100644
--- a/src/java.desktop/share/classes/sun/font/GlyphLayout.java
+++ b/src/java.desktop/share/classes/sun/font/GlyphLayout.java
@@ -125,10 +125,10 @@ public final class GlyphLayout {
}
private static final class SDCache {
- public AffineTransform dtx;
- public AffineTransform gtx;
- public Point2D.Float delta;
- public FontStrikeDesc sd;
+ private final AffineTransform dtx;
+ private final AffineTransform gtx;
+ private final Point2D.Float delta;
+ private final FontStrikeDesc sd;
private SDCache(Font font, FontRenderContext frc) {
// !!! add getVectorTransform and hasVectorTransform to frc? then
diff --git a/src/java.desktop/share/classes/sun/print/RasterPrinterJob.java b/src/java.desktop/share/classes/sun/print/RasterPrinterJob.java
index 32728efde6c..b28723f94a6 100644
--- a/src/java.desktop/share/classes/sun/print/RasterPrinterJob.java
+++ b/src/java.desktop/share/classes/sun/print/RasterPrinterJob.java
@@ -33,24 +33,23 @@ import java.awt.HeadlessException;
import java.awt.KeyboardFocusManager;
import java.awt.Rectangle;
import java.awt.Shape;
+import java.awt.Window;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.awt.print.Book;
-import java.awt.print.Pageable;
import java.awt.print.PageFormat;
+import java.awt.print.Pageable;
import java.awt.print.Paper;
import java.awt.print.Printable;
import java.awt.print.PrinterAbortException;
import java.awt.print.PrinterException;
import java.awt.print.PrinterJob;
-import java.awt.Window;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Locale;
-import sun.awt.image.ByteInterleavedRaster;
import javax.print.Doc;
import javax.print.DocFlavor;
@@ -69,8 +68,8 @@ import javax.print.attribute.ResolutionSyntax;
import javax.print.attribute.Size2DSyntax;
import javax.print.attribute.standard.Copies;
import javax.print.attribute.standard.Destination;
-import javax.print.attribute.standard.DialogTypeSelection;
import javax.print.attribute.standard.DialogOwner;
+import javax.print.attribute.standard.DialogTypeSelection;
import javax.print.attribute.standard.Fidelity;
import javax.print.attribute.standard.JobName;
import javax.print.attribute.standard.JobSheets;
@@ -81,15 +80,17 @@ import javax.print.attribute.standard.MediaSizeName;
import javax.print.attribute.standard.OrientationRequested;
import javax.print.attribute.standard.OutputBin;
import javax.print.attribute.standard.PageRanges;
+import javax.print.attribute.standard.PrinterIsAcceptingJobs;
import javax.print.attribute.standard.PrinterResolution;
import javax.print.attribute.standard.PrinterState;
import javax.print.attribute.standard.PrinterStateReason;
import javax.print.attribute.standard.PrinterStateReasons;
-import javax.print.attribute.standard.PrinterIsAcceptingJobs;
import javax.print.attribute.standard.RequestingUserName;
import javax.print.attribute.standard.SheetCollate;
import javax.print.attribute.standard.Sides;
+import sun.awt.image.ByteInterleavedRaster;
+
import static sun.font.FontUtilities.isIgnorableWhitespace;
/**
@@ -1613,8 +1614,7 @@ public abstract class RasterPrinterJob extends PrinterJob {
} catch (PrinterException pe) {
throw pe;
} catch (Throwable printError) {
- throw (PrinterException)
- new PrinterException().initCause(printError.getCause());
+ throw (PrinterException) new PrinterException().initCause(printError);
} finally {
// reset previousPaper in case this job is invoked again.
previousPaper = null;
diff --git a/src/java.desktop/share/legal/libpng.md b/src/java.desktop/share/legal/libpng.md
index 034de22bf25..7783fc7ff03 100644
--- a/src/java.desktop/share/legal/libpng.md
+++ b/src/java.desktop/share/legal/libpng.md
@@ -1,4 +1,4 @@
-## libpng v1.6.56
+## libpng v1.6.57
### libpng License
@@ -180,6 +180,7 @@ Authors, for copyright and licensing purposes.
* Mans Rullgard
* Matt Sarett
* Mike Klein
+ * Mohammad Seet
* Pascal Massimino
* Paul Schmidt
* Petr Simecek
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/CHANGES b/src/java.desktop/share/native/libsplashscreen/libpng/CHANGES
index 673d4d50420..ba81df0c0e6 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/CHANGES
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/CHANGES
@@ -6368,6 +6368,17 @@ Version 1.6.56 [March 25, 2026]
(Contributed by Bob Friesenhahn and Philippe Antoine.)
Performed various refactorings and cleanups.
+Version 1.6.57 [April 8, 2026]
+ Fixed CVE-2026-34757 (medium severity):
+ Use-after-free in `png_set_PLTE`, `png_set_tRNS` and `png_set_hIST`
+ leading to corrupted chunk data and potential heap information disclosure.
+ Also hardened the append-style setters (`png_set_text`, `png_set_sPLT`,
+ `png_set_unknown_chunks`) against a theoretical variant of the same
+ aliasing pattern.
+ (Reported by Iv4n .)
+ Fixed integer overflow in rowbytes computation in read transforms.
+ (Contributed by Mohammad Seet.)
+
Send comments/corrections/commendations to png-mng-implement at lists.sf.net.
Subscription is required; visit
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/README b/src/java.desktop/share/native/libsplashscreen/libpng/README
index d0b085f7933..179b8dc8cb4 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/README
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/README
@@ -1,4 +1,4 @@
-README for libpng version 1.6.56
+README for libpng version 1.6.57
================================
See the note about version numbers near the top of `png.h`.
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/png.c b/src/java.desktop/share/native/libsplashscreen/libpng/png.c
index fd095b515b9..e4e13b0a684 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/png.c
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/png.c
@@ -42,7 +42,7 @@
#include "pngpriv.h"
/* Generate a compiler error if there is an old png.h in the search path. */
-typedef png_libpng_version_1_6_56 Your_png_h_is_not_version_1_6_56;
+typedef png_libpng_version_1_6_57 Your_png_h_is_not_version_1_6_57;
/* Sanity check the chunks definitions - PNG_KNOWN_CHUNKS from pngpriv.h and the
* corresponding macro definitions. This causes a compile time failure if
@@ -849,7 +849,7 @@ png_get_copyright(png_const_structrp png_ptr)
return PNG_STRING_COPYRIGHT
#else
return PNG_STRING_NEWLINE \
- "libpng version 1.6.56" PNG_STRING_NEWLINE \
+ "libpng version 1.6.57" PNG_STRING_NEWLINE \
"Copyright (c) 2018-2026 Cosmin Truta" PNG_STRING_NEWLINE \
"Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson" \
PNG_STRING_NEWLINE \
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/png.h b/src/java.desktop/share/native/libsplashscreen/libpng/png.h
index 56ec204cd1a..349e7d07383 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/png.h
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/png.h
@@ -29,7 +29,7 @@
* However, the following notice accompanied the original version of this
* file and, per its terms, should not be removed:
*
- * libpng version 1.6.56
+ * libpng version 1.6.57
*
* Copyright (c) 2018-2026 Cosmin Truta
* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson
@@ -43,7 +43,7 @@
* libpng versions 0.89, June 1996, through 0.96, May 1997: Andreas Dilger
* libpng versions 0.97, January 1998, through 1.6.35, July 2018:
* Glenn Randers-Pehrson
- * libpng versions 1.6.36, December 2018, through 1.6.56, March 2026:
+ * libpng versions 1.6.36, December 2018, through 1.6.57, April 2026:
* Cosmin Truta
* See also "Contributing Authors", below.
*/
@@ -267,7 +267,7 @@
* ...
* 1.5.30 15 10530 15.so.15.30[.0]
* ...
- * 1.6.56 16 10656 16.so.16.56[.0]
+ * 1.6.57 16 10657 16.so.16.57[.0]
*
* Henceforth the source version will match the shared-library major and
* minor numbers; the shared-library major version number will be used for
@@ -303,7 +303,7 @@
*/
/* Version information for png.h - this should match the version in png.c */
-#define PNG_LIBPNG_VER_STRING "1.6.56"
+#define PNG_LIBPNG_VER_STRING "1.6.57"
#define PNG_HEADER_VERSION_STRING " libpng version " PNG_LIBPNG_VER_STRING "\n"
/* The versions of shared library builds should stay in sync, going forward */
@@ -314,7 +314,7 @@
/* These should match the first 3 components of PNG_LIBPNG_VER_STRING: */
#define PNG_LIBPNG_VER_MAJOR 1
#define PNG_LIBPNG_VER_MINOR 6
-#define PNG_LIBPNG_VER_RELEASE 56
+#define PNG_LIBPNG_VER_RELEASE 57
/* This should be zero for a public release, or non-zero for a
* development version.
@@ -345,7 +345,7 @@
* From version 1.0.1 it is:
* XXYYZZ, where XX=major, YY=minor, ZZ=release
*/
-#define PNG_LIBPNG_VER 10656 /* 1.6.56 */
+#define PNG_LIBPNG_VER 10657 /* 1.6.57 */
/* Library configuration: these options cannot be changed after
* the library has been built.
@@ -455,7 +455,7 @@ extern "C" {
/* This triggers a compiler error in png.c, if png.c and png.h
* do not agree upon the version number.
*/
-typedef char *png_libpng_version_1_6_56;
+typedef char *png_libpng_version_1_6_57;
/* Basic control structions. Read libpng-manual.txt or libpng.3 for more info.
*
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngconf.h b/src/java.desktop/share/native/libsplashscreen/libpng/pngconf.h
index 5772e6ebb1c..1a5bb7b60f8 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/pngconf.h
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngconf.h
@@ -29,7 +29,7 @@
* However, the following notice accompanied the original version of this
* file and, per its terms, should not be removed:
*
- * libpng version 1.6.56
+ * libpng version 1.6.57
*
* Copyright (c) 2018-2026 Cosmin Truta
* Copyright (c) 1998-2002,2004,2006-2016,2018 Glenn Randers-Pehrson
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pnglibconf.h b/src/java.desktop/share/native/libsplashscreen/libpng/pnglibconf.h
index 4a7e51d112d..de63c998927 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/pnglibconf.h
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/pnglibconf.h
@@ -31,7 +31,7 @@
* However, the following notice accompanied the original version of this
* file and, per its terms, should not be removed:
*/
-/* libpng version 1.6.56 */
+/* libpng version 1.6.57 */
/* Copyright (c) 2018-2026 Cosmin Truta */
/* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson */
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngrtran.c b/src/java.desktop/share/native/libsplashscreen/libpng/pngrtran.c
index f0972ba9bef..838c8460f91 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/pngrtran.c
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngrtran.c
@@ -2408,7 +2408,7 @@ png_do_unpack(png_row_infop row_info, png_bytep row)
}
row_info->bit_depth = 8;
row_info->pixel_depth = (png_byte)(8 * row_info->channels);
- row_info->rowbytes = row_width * row_info->channels;
+ row_info->rowbytes = (size_t)row_width * row_info->channels;
}
}
#endif
@@ -2610,7 +2610,7 @@ png_do_scale_16_to_8(png_row_infop row_info, png_bytep row)
row_info->bit_depth = 8;
row_info->pixel_depth = (png_byte)(8 * row_info->channels);
- row_info->rowbytes = row_info->width * row_info->channels;
+ row_info->rowbytes = (size_t)row_info->width * row_info->channels;
}
}
#endif
@@ -2638,7 +2638,7 @@ png_do_chop(png_row_infop row_info, png_bytep row)
row_info->bit_depth = 8;
row_info->pixel_depth = (png_byte)(8 * row_info->channels);
- row_info->rowbytes = row_info->width * row_info->channels;
+ row_info->rowbytes = (size_t)row_info->width * row_info->channels;
}
}
#endif
@@ -2874,7 +2874,7 @@ png_do_read_filler(png_row_infop row_info, png_bytep row,
*(--dp) = lo_filler;
row_info->channels = 2;
row_info->pixel_depth = 16;
- row_info->rowbytes = row_width * 2;
+ row_info->rowbytes = (size_t)row_width * 2;
}
else
@@ -2889,7 +2889,7 @@ png_do_read_filler(png_row_infop row_info, png_bytep row,
}
row_info->channels = 2;
row_info->pixel_depth = 16;
- row_info->rowbytes = row_width * 2;
+ row_info->rowbytes = (size_t)row_width * 2;
}
}
@@ -2912,7 +2912,7 @@ png_do_read_filler(png_row_infop row_info, png_bytep row,
*(--dp) = hi_filler;
row_info->channels = 2;
row_info->pixel_depth = 32;
- row_info->rowbytes = row_width * 4;
+ row_info->rowbytes = (size_t)row_width * 4;
}
else
@@ -2929,7 +2929,7 @@ png_do_read_filler(png_row_infop row_info, png_bytep row,
}
row_info->channels = 2;
row_info->pixel_depth = 32;
- row_info->rowbytes = row_width * 4;
+ row_info->rowbytes = (size_t)row_width * 4;
}
}
#endif
@@ -2953,7 +2953,7 @@ png_do_read_filler(png_row_infop row_info, png_bytep row,
*(--dp) = lo_filler;
row_info->channels = 4;
row_info->pixel_depth = 32;
- row_info->rowbytes = row_width * 4;
+ row_info->rowbytes = (size_t)row_width * 4;
}
else
@@ -2970,7 +2970,7 @@ png_do_read_filler(png_row_infop row_info, png_bytep row,
}
row_info->channels = 4;
row_info->pixel_depth = 32;
- row_info->rowbytes = row_width * 4;
+ row_info->rowbytes = (size_t)row_width * 4;
}
}
@@ -2997,7 +2997,7 @@ png_do_read_filler(png_row_infop row_info, png_bytep row,
*(--dp) = hi_filler;
row_info->channels = 4;
row_info->pixel_depth = 64;
- row_info->rowbytes = row_width * 8;
+ row_info->rowbytes = (size_t)row_width * 8;
}
else
@@ -3019,7 +3019,7 @@ png_do_read_filler(png_row_infop row_info, png_bytep row,
row_info->channels = 4;
row_info->pixel_depth = 64;
- row_info->rowbytes = row_width * 8;
+ row_info->rowbytes = (size_t)row_width * 8;
}
}
#endif
@@ -4513,7 +4513,7 @@ png_do_expand_palette(png_structrp png_ptr, png_row_infop row_info,
}
row_info->bit_depth = 8;
row_info->pixel_depth = 32;
- row_info->rowbytes = row_width * 4;
+ row_info->rowbytes = (size_t)row_width * 4;
row_info->color_type = 6;
row_info->channels = 4;
}
@@ -4521,7 +4521,7 @@ png_do_expand_palette(png_structrp png_ptr, png_row_infop row_info,
else
{
sp = row + (size_t)row_width - 1;
- dp = row + (size_t)(row_width * 3) - 1;
+ dp = row + (size_t)row_width * 3 - 1;
i = 0;
#ifdef PNG_ARM_NEON_INTRINSICS_AVAILABLE
i = png_do_expand_palette_rgb8_neon(png_ptr, row_info, row,
@@ -4540,7 +4540,7 @@ png_do_expand_palette(png_structrp png_ptr, png_row_infop row_info,
row_info->bit_depth = 8;
row_info->pixel_depth = 24;
- row_info->rowbytes = row_width * 3;
+ row_info->rowbytes = (size_t)row_width * 3;
row_info->color_type = 2;
row_info->channels = 3;
}
diff --git a/src/java.desktop/share/native/libsplashscreen/libpng/pngset.c b/src/java.desktop/share/native/libsplashscreen/libpng/pngset.c
index 05d18cd06b7..29082a6be08 100644
--- a/src/java.desktop/share/native/libsplashscreen/libpng/pngset.c
+++ b/src/java.desktop/share/native/libsplashscreen/libpng/pngset.c
@@ -414,6 +414,7 @@ void PNGAPI
png_set_hIST(png_const_structrp png_ptr, png_inforp info_ptr,
png_const_uint_16p hist)
{
+ png_uint_16 safe_hist[PNG_MAX_PALETTE_LENGTH];
int i;
png_debug1(1, "in %s storage function", "hIST");
@@ -430,6 +431,13 @@ png_set_hIST(png_const_structrp png_ptr, png_inforp info_ptr,
return;
}
+ /* Snapshot the caller's hist before freeing, in case it points to
+ * info_ptr->hist (getter-to-setter aliasing).
+ */
+ memcpy(safe_hist, hist, (unsigned int)info_ptr->num_palette *
+ (sizeof (png_uint_16)));
+ hist = safe_hist;
+
png_free_data(png_ptr, info_ptr, PNG_FREE_HIST, 0);
/* Changed from info->num_palette to PNG_MAX_PALETTE_LENGTH in
@@ -771,7 +779,7 @@ void PNGAPI
png_set_PLTE(png_structrp png_ptr, png_inforp info_ptr,
png_const_colorp palette, int num_palette)
{
-
+ png_color safe_palette[PNG_MAX_PALETTE_LENGTH];
png_uint_32 max_palette_length;
png_debug1(1, "in %s storage function", "PLTE");
@@ -805,6 +813,15 @@ png_set_PLTE(png_structrp png_ptr, png_inforp info_ptr,
png_error(png_ptr, "Invalid palette");
}
+ /* Snapshot the caller's palette before freeing, in case it points to
+ * info_ptr->palette (getter-to-setter aliasing).
+ */
+ if (num_palette > 0)
+ memcpy(safe_palette, palette, (unsigned int)num_palette *
+ (sizeof (png_color)));
+
+ palette = safe_palette;
+
png_free_data(png_ptr, info_ptr, PNG_FREE_PLTE, 0);
/* Changed in libpng-1.2.1 to allocate PNG_MAX_PALETTE_LENGTH instead
@@ -966,6 +983,7 @@ png_set_text_2(png_const_structrp png_ptr, png_inforp info_ptr,
png_const_textp text_ptr, int num_text)
{
int i;
+ png_textp old_text = NULL;
png_debug1(1, "in text storage function, chunk typeid = 0x%lx",
png_ptr == NULL ? 0xabadca11UL : (unsigned long)png_ptr->chunk_name);
@@ -1013,7 +1031,10 @@ png_set_text_2(png_const_structrp png_ptr, png_inforp info_ptr,
return 1;
}
- png_free(png_ptr, info_ptr->text);
+ /* Defer freeing the old array until after the copy loop below,
+ * in case text_ptr aliases info_ptr->text (getter-to-setter).
+ */
+ old_text = info_ptr->text;
info_ptr->text = new_text;
info_ptr->free_me |= PNG_FREE_TEXT;
@@ -1098,6 +1119,7 @@ png_set_text_2(png_const_structrp png_ptr, png_inforp info_ptr,
{
png_chunk_report(png_ptr, "text chunk: out of memory",
PNG_CHUNK_WRITE_ERROR);
+ png_free(png_ptr, old_text);
return 1;
}
@@ -1151,6 +1173,8 @@ png_set_text_2(png_const_structrp png_ptr, png_inforp info_ptr,
png_debug1(3, "transferred text chunk %d", info_ptr->num_text);
}
+ png_free(png_ptr, old_text);
+
return 0;
}
#endif
@@ -1194,6 +1218,16 @@ png_set_tRNS(png_structrp png_ptr, png_inforp info_ptr,
if (trans_alpha != NULL)
{
+ /* Snapshot the caller's trans_alpha before freeing, in case it
+ * points to info_ptr->trans_alpha (getter-to-setter aliasing).
+ */
+ png_byte safe_trans[PNG_MAX_PALETTE_LENGTH];
+
+ if (num_trans > 0 && num_trans <= PNG_MAX_PALETTE_LENGTH)
+ memcpy(safe_trans, trans_alpha, (size_t)num_trans);
+
+ trans_alpha = safe_trans;
+
png_free_data(png_ptr, info_ptr, PNG_FREE_TRNS, 0);
if (num_trans > 0 && num_trans <= PNG_MAX_PALETTE_LENGTH)
@@ -1278,6 +1312,7 @@ png_set_sPLT(png_const_structrp png_ptr,
*/
{
png_sPLT_tp np;
+ png_sPLT_tp old_spalettes;
png_debug1(1, "in %s storage function", "sPLT");
@@ -1298,7 +1333,10 @@ png_set_sPLT(png_const_structrp png_ptr,
return;
}
- png_free(png_ptr, info_ptr->splt_palettes);
+ /* Defer freeing the old array until after the copy loop below,
+ * in case entries aliases info_ptr->splt_palettes (getter-to-setter).
+ */
+ old_spalettes = info_ptr->splt_palettes;
info_ptr->splt_palettes = np;
info_ptr->free_me |= PNG_FREE_SPLT;
@@ -1362,6 +1400,8 @@ png_set_sPLT(png_const_structrp png_ptr,
}
while (--nentries);
+ png_free(png_ptr, old_spalettes);
+
if (nentries > 0)
png_chunk_report(png_ptr, "sPLT out of memory", PNG_CHUNK_WRITE_ERROR);
}
@@ -1410,6 +1450,7 @@ png_set_unknown_chunks(png_const_structrp png_ptr,
png_inforp info_ptr, png_const_unknown_chunkp unknowns, int num_unknowns)
{
png_unknown_chunkp np;
+ png_unknown_chunkp old_unknowns;
if (png_ptr == NULL || info_ptr == NULL || num_unknowns <= 0 ||
unknowns == NULL)
@@ -1456,7 +1497,10 @@ png_set_unknown_chunks(png_const_structrp png_ptr,
return;
}
- png_free(png_ptr, info_ptr->unknown_chunks);
+ /* Defer freeing the old array until after the copy loop below,
+ * in case unknowns aliases info_ptr->unknown_chunks (getter-to-setter).
+ */
+ old_unknowns = info_ptr->unknown_chunks;
info_ptr->unknown_chunks = np; /* safe because it is initialized */
info_ptr->free_me |= PNG_FREE_UNKN;
@@ -1502,6 +1546,8 @@ png_set_unknown_chunks(png_const_structrp png_ptr,
++np;
++(info_ptr->unknown_chunks_num);
}
+
+ png_free(png_ptr, old_unknowns);
}
void PNGAPI
diff --git a/src/java.desktop/windows/native/libawt/windows/awt_PrintJob.cpp b/src/java.desktop/windows/native/libawt/windows/awt_PrintJob.cpp
index 8d016d8b39f..b18fa5a7e2c 100644
--- a/src/java.desktop/windows/native/libawt/windows/awt_PrintJob.cpp
+++ b/src/java.desktop/windows/native/libawt/windows/awt_PrintJob.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2026, 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
@@ -522,7 +522,6 @@ Java_sun_awt_windows_WPageDialogPeer__1show(JNIEnv *env, jobject peer)
AwtComponent *awtParent = (parent != NULL) ? (AwtComponent *)JNI_GET_PDATA(parent) : NULL;
HWND hwndOwner = awtParent ? awtParent->GetHWnd() : NULL;
- jboolean doIt = JNI_FALSE;
PAGESETUPDLG setup;
memset(&setup, 0, sizeof(setup));
@@ -578,7 +577,7 @@ Java_sun_awt_windows_WPageDialogPeer__1show(JNIEnv *env, jobject peer)
*/
if ((setup.hDevMode == NULL) && (setup.hDevNames == NULL)) {
CLEANUP_SHOW;
- return doIt;
+ return JNI_FALSE;
}
} else {
int measure = PSD_INTHOUSANDTHSOFINCHES;
@@ -606,7 +605,7 @@ Java_sun_awt_windows_WPageDialogPeer__1show(JNIEnv *env, jobject peer)
pageFormatToSetup(env, self, page, &setup, AwtPrintControl::getPrintDC(env, self));
if (env->ExceptionCheck()) {
CLEANUP_SHOW;
- return doIt;
+ return JNI_FALSE;
}
setup.lpfnPageSetupHook = reinterpret_cast(pageDlgHook);
@@ -615,89 +614,91 @@ Java_sun_awt_windows_WPageDialogPeer__1show(JNIEnv *env, jobject peer)
AwtDialog::CheckInstallModalHook();
BOOL ret = ::PageSetupDlg(&setup);
- if (ret) {
-
- jobject paper = getPaper(env, page);
- if (paper == NULL) {
- CLEANUP_SHOW;
- return doIt;
- }
- int units = setup.Flags & PSD_INTHOUSANDTHSOFINCHES ?
- MM_HIENGLISH :
- MM_HIMETRIC;
- POINT paperSize;
- RECT margins;
- jint orientation;
-
- /* The printer may have been changed, and we track that change,
- * but then need to get a new DC for the current printer so that
- * we validate the paper size correctly
- */
- if (setup.hDevNames != NULL) {
- DEVNAMES* names = (DEVNAMES*)::GlobalLock(setup.hDevNames);
- if (names != NULL) {
- LPTSTR printer = (LPTSTR)names+names->wDeviceOffset;
- SAVE_CONTROLWORD
- HDC newDC = ::CreateDC(TEXT("WINSPOOL"), printer, NULL, NULL);
- RESTORE_CONTROLWORD
- if (newDC != NULL) {
- HDC oldDC = AwtPrintControl::getPrintDC(env, self);
- if (oldDC != NULL) {
- ::DeleteDC(oldDC);
- }
- }
- AwtPrintControl::setPrintDC(env, self, newDC);
- }
- ::GlobalUnlock(setup.hDevNames);
- }
-
- /* Get the Windows paper and margins description.
- */
- retrievePaperInfo(&setup, &paperSize, &margins, &orientation,
- AwtPrintControl::getPrintDC(env, self));
-
- /* Convert the Windows' paper and margins description
- * and place them into a Paper instance.
- */
- setPaperValues(env, paper, &paperSize, &margins, units);
- if (env->ExceptionCheck()) {
- CLEANUP_SHOW;
- return doIt;
- }
- /*
- * Put the updated Paper instance and the orientation into
- * the PageFormat.
- */
- setPaper(env, page, paper);
- if (env->ExceptionCheck()) {
- CLEANUP_SHOW;
- return doIt;
- }
- setPageFormatOrientation(env, page, orientation);
- if (env->ExceptionCheck()) {
- CLEANUP_SHOW;
- return JNI_FALSE;
- }
- if (setup.hDevMode != NULL) {
- DEVMODE *devmode = (DEVMODE *)::GlobalLock(setup.hDevMode);
- if (devmode != NULL) {
- if (devmode->dmFields & DM_PAPERSIZE) {
- jboolean err = setPrintPaperSize(env, self, devmode->dmPaperSize);
- if (err) {
- CLEANUP_SHOW;
- return doIt;
- }
- }
- }
- ::GlobalUnlock(setup.hDevMode);
- }
- doIt = JNI_TRUE;
- }
AwtDialog::CheckUninstallModalHook();
-
AwtDialog::ModalActivateNextWindow(NULL, target, peer);
+ if (!ret) {
+ CLEANUP_SHOW;
+ return JNI_FALSE;
+ }
+
+ jobject paper = getPaper(env, page);
+ if (paper == NULL) {
+ CLEANUP_SHOW;
+ return JNI_FALSE;
+ }
+ int units = setup.Flags & PSD_INTHOUSANDTHSOFINCHES ?
+ MM_HIENGLISH :
+ MM_HIMETRIC;
+ POINT paperSize;
+ RECT margins;
+ jint orientation;
+
+ /* The printer may have been changed, and we track that change,
+ * but then need to get a new DC for the current printer so that
+ * we validate the paper size correctly
+ */
+ if (setup.hDevNames != NULL) {
+ DEVNAMES* names = (DEVNAMES*)::GlobalLock(setup.hDevNames);
+ if (names != NULL) {
+ LPTSTR printer = (LPTSTR)names+names->wDeviceOffset;
+ SAVE_CONTROLWORD
+ HDC newDC = ::CreateDC(TEXT("WINSPOOL"), printer, NULL, NULL);
+ RESTORE_CONTROLWORD
+ if (newDC != NULL) {
+ HDC oldDC = AwtPrintControl::getPrintDC(env, self);
+ if (oldDC != NULL) {
+ ::DeleteDC(oldDC);
+ }
+ }
+ AwtPrintControl::setPrintDC(env, self, newDC);
+ }
+ ::GlobalUnlock(setup.hDevNames);
+ }
+
+ /* Get the Windows paper and margins description.
+ */
+ retrievePaperInfo(&setup, &paperSize, &margins, &orientation,
+ AwtPrintControl::getPrintDC(env, self));
+
+ /* Convert the Windows' paper and margins description
+ * and place them into a Paper instance.
+ */
+ setPaperValues(env, paper, &paperSize, &margins, units);
+ if (env->ExceptionCheck()) {
+ CLEANUP_SHOW;
+ return JNI_FALSE;
+ }
+ /*
+ * Put the updated Paper instance and the orientation into
+ * the PageFormat.
+ */
+ setPaper(env, page, paper);
+ if (env->ExceptionCheck()) {
+ CLEANUP_SHOW;
+ return JNI_FALSE;
+ }
+ setPageFormatOrientation(env, page, orientation);
+ if (env->ExceptionCheck()) {
+ CLEANUP_SHOW;
+ return JNI_FALSE;
+ }
+ if (setup.hDevMode != NULL) {
+ DEVMODE *devmode = (DEVMODE *)::GlobalLock(setup.hDevMode);
+ if (devmode != NULL) {
+ if (devmode->dmFields & DM_PAPERSIZE) {
+ jboolean err = setPrintPaperSize(env, self, devmode->dmPaperSize);
+ if (err) {
+ ::GlobalUnlock(setup.hDevMode);
+ CLEANUP_SHOW;
+ return JNI_FALSE;
+ }
+ }
+ }
+ ::GlobalUnlock(setup.hDevMode);
+ }
+
HGLOBAL oldG = AwtPrintControl::getPrintHDMode(env, self);
if (setup.hDevMode != oldG) {
AwtPrintControl::setPrintHDMode(env, self, setup.hDevMode);
@@ -710,7 +711,7 @@ Java_sun_awt_windows_WPageDialogPeer__1show(JNIEnv *env, jobject peer)
CLEANUP_SHOW;
- return doIt;
+ return JNI_TRUE;
CATCH_BAD_ALLOC_RET(0);
}
diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/HttpRequestBuilderImpl.java b/src/java.net.http/share/classes/jdk/internal/net/http/HttpRequestBuilderImpl.java
index ef0e2b152bb..c39edf878c9 100644
--- a/src/java.net.http/share/classes/jdk/internal/net/http/HttpRequestBuilderImpl.java
+++ b/src/java.net.http/share/classes/jdk/internal/net/http/HttpRequestBuilderImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2026, 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
@@ -145,7 +145,7 @@ public class HttpRequestBuilderImpl implements HttpRequest.Builder {
@Override
public HttpRequestBuilderImpl headers(String... params) {
requireNonNull(params);
- if (params.length == 0 || params.length % 2 != 0) {
+ if (params.length % 2 != 0) {
throw newIAE("wrong number, %d, of parameters", params.length);
}
for (int i = 0; i < params.length; i += 2) {
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Preview.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Preview.java
index 1c93c37698a..7a8e6c6f4f1 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Preview.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Preview.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2026, 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
@@ -34,6 +34,7 @@ import com.sun.tools.javac.resources.CompilerProperties.LintWarnings;
import com.sun.tools.javac.resources.CompilerProperties.Warnings;
import com.sun.tools.javac.util.Assert;
import com.sun.tools.javac.util.Context;
+import com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag;
import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition;
import com.sun.tools.javac.util.JCDiagnostic.Error;
import com.sun.tools.javac.util.JCDiagnostic.LintWarning;
@@ -150,24 +151,26 @@ public class Preview {
/**
* Report usage of a preview feature. Usages reported through this method will affect the
* set of sourcefiles with dependencies on preview features.
+ * @param flag a flag to set on the diagnostic
* @param pos the position at which the preview feature was used.
* @param feature the preview feature used.
*/
- public void warnPreview(int pos, Feature feature) {
- warnPreview(new SimpleDiagnosticPosition(pos), feature);
+ public void warnPreview(DiagnosticFlag flag, int pos, Feature feature) {
+ warnPreview(flag, new SimpleDiagnosticPosition(pos), feature);
}
/**
* Report usage of a preview feature. Usages reported through this method will affect the
* set of sourcefiles with dependencies on preview features.
+ * @param flag a flag to set on the diagnostic
* @param pos the position at which the preview feature was used.
* @param feature the preview feature used.
*/
- public void warnPreview(DiagnosticPosition pos, Feature feature) {
+ public void warnPreview(DiagnosticFlag flag, DiagnosticPosition pos, Feature feature) {
Assert.check(isEnabled());
Assert.check(isPreview(feature));
markUsesPreview(pos);
- log.warning(pos,
+ log.warning(flag, pos,
feature.isPlural() ?
LintWarnings.PreviewFeatureUsePlural(feature.nameFragment()) :
LintWarnings.PreviewFeatureUse(feature.nameFragment()));
@@ -263,7 +266,7 @@ public class Preview {
log.error(pos, feature.error(source.name));
}
if (isEnabled() && isPreview(feature)) {
- warnPreview(pos, feature);
+ warnPreview(null, pos, feature);
}
}
}
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java
index 444530c7266..89ae68e85ba 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java
@@ -5270,11 +5270,15 @@ public class Attr extends JCTree.Visitor {
public void visitAnnotatedType(JCAnnotatedType tree) {
attribAnnotationTypes(tree.annotations, env);
- Type underlyingType = attribType(tree.underlyingType, env);
- Type annotatedType = underlyingType.preannotatedType();
+ Type underlyingType = attribTree(tree.underlyingType, env, resultInfo);
+ if (underlyingType.getTag() == PACKAGE) {
+ result = tree.type = underlyingType;
+ } else {
+ Type annotatedType = underlyingType.preannotatedType();
- annotate.annotateTypeSecondStage(tree, tree.annotations, annotatedType);
- result = tree.type = annotatedType;
+ annotate.annotateTypeSecondStage(tree, tree.annotations, annotatedType);
+ result = tree.type = annotatedType;
+ }
}
public void visitErroneous(JCErroneous tree) {
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java
index 55f2f76e358..d8b5b1ddd6b 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavaTokenizer.java
@@ -176,7 +176,7 @@ public class JavaTokenizer extends UnicodeReader {
lexError(pos, feature.error(source.name));
} else if (preview.isPreview(feature)) {
//use of preview feature, warn
- preview.warnPreview(pos, feature);
+ preview.warnPreview(DiagnosticFlag.SYNTAX, pos, feature);
}
}
@@ -1040,10 +1040,10 @@ public class JavaTokenizer extends UnicodeReader {
// Verify that the incidental indentation is consistent.
Set checks = TextBlockSupport.checkWhitespace(string);
if (checks.contains(TextBlockSupport.WhitespaceChecks.INCONSISTENT)) {
- log.warning(pos, LintWarnings.InconsistentWhiteSpaceIndentation);
+ log.warning(DiagnosticFlag.SYNTAX, pos, LintWarnings.InconsistentWhiteSpaceIndentation);
}
if (checks.contains(TextBlockSupport.WhitespaceChecks.TRAILING)) {
- log.warning(pos, LintWarnings.TrailingWhiteSpaceWillBeRemoved);
+ log.warning(DiagnosticFlag.SYNTAX, pos, LintWarnings.TrailingWhiteSpaceWillBeRemoved);
}
// Remove incidental indentation.
try {
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java
index df5da5cb954..b4dfb04766c 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java
@@ -772,7 +772,7 @@ public class JavacParser implements Parser {
}
} else if (token.kind == UNDERSCORE) {
if (Feature.UNDERSCORE_IDENTIFIER.allowedInSource(source)) {
- log.warning(token.pos, Warnings.UnderscoreAsIdentifier);
+ log.warning(DiagnosticFlag.SYNTAX, token.pos, Warnings.UnderscoreAsIdentifier);
} else if (asVariable) {
checkSourceLevel(Feature.UNNAMED_VARIABLES);
if (peekToken(LBRACKET)) {
@@ -2339,7 +2339,7 @@ public class JavacParser implements Parser {
if (allowYieldStatement) {
return true;
} else {
- log.warning(pos, Warnings.InvalidYield);
+ log.warning(DiagnosticFlag.SYNTAX, pos, Warnings.InvalidYield);
}
}
return false;
@@ -3858,35 +3858,35 @@ public class JavacParser implements Parser {
if (Feature.LOCAL_VARIABLE_TYPE_INFERENCE.allowedInSource(source)) {
return Source.JDK10;
} else if (shouldWarn) {
- log.warning(pos, Warnings.RestrictedTypeNotAllowed(name, Source.JDK10));
+ log.warning(DiagnosticFlag.SYNTAX, pos, Warnings.RestrictedTypeNotAllowed(name, Source.JDK10));
}
}
if (name == names.yield) {
if (allowYieldStatement) {
return Source.JDK14;
} else if (shouldWarn) {
- log.warning(pos, Warnings.RestrictedTypeNotAllowed(name, Source.JDK14));
+ log.warning(DiagnosticFlag.SYNTAX, pos, Warnings.RestrictedTypeNotAllowed(name, Source.JDK14));
}
}
if (name == names.record) {
if (allowRecords) {
return Source.JDK14;
} else if (shouldWarn) {
- log.warning(pos, Warnings.RestrictedTypeNotAllowedPreview(name, Source.JDK14));
+ log.warning(DiagnosticFlag.SYNTAX, pos, Warnings.RestrictedTypeNotAllowedPreview(name, Source.JDK14));
}
}
if (name == names.sealed) {
if (allowSealedTypes) {
return Source.JDK15;
} else if (shouldWarn) {
- log.warning(pos, Warnings.RestrictedTypeNotAllowedPreview(name, Source.JDK15));
+ log.warning(DiagnosticFlag.SYNTAX, pos, Warnings.RestrictedTypeNotAllowedPreview(name, Source.JDK15));
}
}
if (name == names.permits) {
if (allowSealedTypes) {
return Source.JDK15;
} else if (shouldWarn) {
- log.warning(pos, Warnings.RestrictedTypeNotAllowedPreview(name, Source.JDK15));
+ log.warning(DiagnosticFlag.SYNTAX, pos, Warnings.RestrictedTypeNotAllowedPreview(name, Source.JDK15));
}
}
return null;
@@ -4057,7 +4057,7 @@ public class JavacParser implements Parser {
if (source.compareTo(Source.JDK21) >= 0)
reportSyntaxError(semiList.first().pos, Errors.ExtraneousSemicolon);
else
- log.warning(semiList.first().pos, Warnings.ExtraneousSemicolon);
+ log.warning(DiagnosticFlag.SYNTAX, semiList.first().pos, Warnings.ExtraneousSemicolon);
}
seenImport = true;
defs.append(importDeclaration());
@@ -4074,7 +4074,7 @@ public class JavacParser implements Parser {
if (source.compareTo(Source.JDK21) >= 0)
reportSyntaxError(semiList.first().pos, Errors.ExtraneousSemicolon);
else
- log.warning(semiList.first().pos, Warnings.ExtraneousSemicolon);
+ log.warning(DiagnosticFlag.SYNTAX, semiList.first().pos, Warnings.ExtraneousSemicolon);
}
ModuleKind kind = ModuleKind.STRONG;
if (token.name() == names.open) {
@@ -5616,7 +5616,7 @@ public class JavacParser implements Parser {
log.error(pos, feature.error(source.name));
} else if (preview.isPreview(feature)) {
//use of preview feature, warn
- preview.warnPreview(pos, feature);
+ preview.warnPreview(DiagnosticFlag.SYNTAX, pos, feature);
}
}
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/TextBlockSupport.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/TextBlockSupport.java
index d099ceadba0..5112849d45f 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/TextBlockSupport.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/TextBlockSupport.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2020, 2026, 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
@@ -56,8 +56,8 @@ class TextBlockSupport {
// No need to check indentation if opting out (last line is empty.)
char lastChar = string.charAt(string.length() - 1);
boolean optOut = lastChar == '\n' || lastChar == '\r';
- // Split string based at line terminators.
- String[] lines = string.split("\\R");
+ // Split string using JLS text block line terminators: CRLF, CR, or LF.
+ String[] lines = string.split("\\r\\n|\\r|\\n");
int length = lines.length;
// Extract last line.
String lastLine = length == 0 ? "" : lines[length - 1];
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java
index 809c19d5012..11fa3a5aebf 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/processing/JavacProcessingEnvironment.java
@@ -1204,6 +1204,7 @@ public class JavacProcessingEnvironment implements ProcessingEnvironment, Closea
//where:
private final Predicate ACCEPT_NON_RECOVERABLE_LINTS =
d -> !Optional.of(d)
+ .filter(diag -> !diag.isFlagSet(SYNTAX))
.map(JCDiagnostic::getLintCategory)
.map(lc -> lc.annotationSuppression ||
lc == Lint.LintCategory.INCUBATING)
diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/AbstractLog.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/AbstractLog.java
index ce3e56f2f3f..b8b2a3af254 100644
--- a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/AbstractLog.java
+++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/AbstractLog.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2026, 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
@@ -192,6 +192,16 @@ public abstract class AbstractLog {
report(diags.warning(null, source, wrap(pos), warningKey));
}
+ /** Report a warning, unless suppressed by the -nowarn option or the
+ * maximum number of warnings has been reached.
+ * @param flag A flag to set on the diagnostic
+ * @param pos The source position at which to report the warning.
+ * @param warningKey The key for the localized warning message.
+ */
+ public void warning(DiagnosticFlag flag, int pos, Warning warningKey) {
+ report(diags.warning(flag, source, wrap(pos), warningKey));
+ }
+
/** Provide a non-fatal notification, unless suppressed by the -nowarn option.
* @param noteKey The key for the localized notification message.
*/
diff --git a/src/jdk.crypto.mscapi/windows/native/libsunmscapi/security.cpp b/src/jdk.crypto.mscapi/windows/native/libsunmscapi/security.cpp
index ff011dca889..5c84b929ef1 100644
--- a/src/jdk.crypto.mscapi/windows/native/libsunmscapi/security.cpp
+++ b/src/jdk.crypto.mscapi/windows/native/libsunmscapi/security.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2026, 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
@@ -1375,7 +1375,7 @@ JNIEXPORT jobject JNICALL Java_sun_security_mscapi_CKeyPairGenerator_00024RSA_ge
PROV_RSA_FULL,
CRYPT_NEWKEYSET) == FALSE)
{
- ThrowException(env, KEY_EXCEPTION, GetLastError());
+ ThrowExceptionWithMessageAndErrcode(env, KEY_EXCEPTION, "CryptAcquireContext failure", GetLastError());
__leave;
}
}
@@ -1387,7 +1387,7 @@ JNIEXPORT jobject JNICALL Java_sun_security_mscapi_CKeyPairGenerator_00024RSA_ge
dwFlags,
&hKeyPair) == FALSE)
{
- ThrowException(env, KEY_EXCEPTION, GetLastError());
+ ThrowExceptionWithMessageAndErrcode(env, KEY_EXCEPTION, "CryptGenKey failure", GetLastError());
__leave;
}
diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/CPUFeatures.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/CPUFeatures.java
index 0ad7ba1651d..05b5f6f69f4 100644
--- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/CPUFeatures.java
+++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/CPUFeatures.java
@@ -74,9 +74,6 @@ import static jdk.internal.vm.vector.Utils.debug;
debug("AVX=%b; AVX2=%b; AVX512F=%b; AVX512DQ=%b",
SUPPORTS_AVX, SUPPORTS_AVX2, SUPPORTS_AVX512F, SUPPORTS_AVX512DQ);
- assert SUPPORTS_AVX512F == (VectorShape.getMaxVectorBitSize(int.class) == 512);
- assert SUPPORTS_AVX2 == (VectorShape.getMaxVectorBitSize(byte.class) >= 256);
- assert SUPPORTS_AVX == (VectorShape.getMaxVectorBitSize(float.class) >= 256);
}
}
diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/VectorMathLibrary.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/VectorMathLibrary.java
index 823cebd85a9..59697733d86 100644
--- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/VectorMathLibrary.java
+++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/VectorMathLibrary.java
@@ -31,6 +31,7 @@ import jdk.internal.vm.vector.VectorSupport;
import java.lang.foreign.MemorySegment;
import java.lang.foreign.SymbolLookup;
+import java.util.Locale;
import java.util.function.IntFunction;
import static jdk.incubator.vector.Util.requires;
@@ -141,7 +142,7 @@ import static jdk.internal.vm.vector.Utils.debug;
String elemType = (vspecies.elementType() == float.class ? "f" : "");
boolean isFloatVector64 = (vspecies.elementType() == float.class) && (vspecies.length() == 2); // FloatVector64 or FloatVectorMax
int vlen = (isFloatVector64 ? 4 : vspecies.length()); // reuse 128-bit variant for 64-bit float vectors
- return String.format("__jsvml_%s%s%d_ha_%s", op.operatorName(), elemType, vlen, suffix);
+ return String.format(Locale.ROOT, "__jsvml_%s%s%d_ha_%s", op.operatorName(), elemType, vlen, suffix);
}
@Override
@@ -214,7 +215,7 @@ import static jdk.internal.vm.vector.Utils.debug;
boolean isFloatVector64 = (vspecies.elementType() == float.class) && (vspecies.length() == 2); // FloatVector64 or FloatVectorMax
int vlen = (isFloatVector64 ? 4 : vspecies.length()); // reuse 128-bit variant for 64-bit float vectors
boolean isShapeAgnostic = isRISCV64() || (isAARCH64() && vspecies.vectorBitSize() > 128);
- return String.format("%s%s%s_%s%s", op.operatorName(),
+ return String.format(Locale.ROOT, "%s%s%s_%s%s", op.operatorName(),
(vspecies.elementType() == float.class ? "f" : "d"),
(isShapeAgnostic ? "x" : Integer.toString(vlen)),
precisionLevel(op),
diff --git a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/VectorOperators.java b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/VectorOperators.java
index 2f2d33ab130..cc5a7ccbdef 100644
--- a/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/VectorOperators.java
+++ b/src/jdk.incubator.vector/share/classes/jdk/incubator/vector/VectorOperators.java
@@ -560,15 +560,15 @@ public final class VectorOperators {
/** Produce {@code a<<(n&(ESIZE*8-1))}. Integral only. */
- public static final /*bitwise*/ Binary LSHL = binary("LSHL", "<<", VectorSupport.VECTOR_OP_LSHIFT, VO_SHIFT);
+ public static final /*bitwise*/ Binary LSHL = binary("LSHL", "<<", VectorSupport.VECTOR_OP_LSHIFT, VO_SHIFT+VO_NOFP);
/** Produce {@code a>>(n&(ESIZE*8-1))}. Integral only. */
- public static final /*bitwise*/ Binary ASHR = binary("ASHR", ">>", VectorSupport.VECTOR_OP_RSHIFT, VO_SHIFT);
+ public static final /*bitwise*/ Binary ASHR = binary("ASHR", ">>", VectorSupport.VECTOR_OP_RSHIFT, VO_SHIFT+VO_NOFP);
/** Produce {@code (a&EMASK)>>>(n&(ESIZE*8-1))}. Integral only. */
- public static final /*bitwise*/ Binary LSHR = binary("LSHR", ">>>", VectorSupport.VECTOR_OP_URSHIFT, VO_SHIFT);
+ public static final /*bitwise*/ Binary LSHR = binary("LSHR", ">>>", VectorSupport.VECTOR_OP_URSHIFT, VO_SHIFT+VO_NOFP);
/** Produce {@code rotateLeft(a,n)}. Integral only. */
- public static final /*bitwise*/ Binary ROL = binary("ROL", "rotateLeft", VectorSupport.VECTOR_OP_LROTATE, VO_SHIFT);
+ public static final /*bitwise*/ Binary ROL = binary("ROL", "rotateLeft", VectorSupport.VECTOR_OP_LROTATE, VO_SHIFT+VO_NOFP);
/** Produce {@code rotateRight(a,n)}. Integral only. */
- public static final /*bitwise*/ Binary ROR = binary("ROR", "rotateRight", VectorSupport.VECTOR_OP_RROTATE, VO_SHIFT);
+ public static final /*bitwise*/ Binary ROR = binary("ROR", "rotateRight", VectorSupport.VECTOR_OP_RROTATE, VO_SHIFT+VO_NOFP);
/** Produce {@code compress(a,n)}. Integral, {@code int} and {@code long}, only.
* @since 19
*/
diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/doclet/StandardDoclet.java b/src/jdk.javadoc/share/classes/jdk/javadoc/doclet/StandardDoclet.java
index 8f5fec1e4b9..90511db8053 100644
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/doclet/StandardDoclet.java
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/doclet/StandardDoclet.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2026, 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,7 +48,7 @@ import jdk.javadoc.internal.doclets.formats.html.HtmlDoclet;
* in documentation comments.
*
* Taglets invoked by the standard doclet must return strings from
- * {@link Taglet#toString(List,Element) Taglet.toString} as follows:
+ * {@link Taglet#toString(List,Element,java.net.URI) Taglet.toString} as follows:
*
*
* - Inline Tags
diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/doclet/Taglet.java b/src/jdk.javadoc/share/classes/jdk/javadoc/doclet/Taglet.java
index 1ad67a89fef..ec079047dfa 100644
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/doclet/Taglet.java
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/doclet/Taglet.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2026, 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,6 +25,7 @@
package jdk.javadoc.doclet;
+import java.net.URI;
import java.util.List;
import java.util.Set;
@@ -34,7 +35,7 @@ import com.sun.source.doctree.DocTree;
/**
* The interface for a custom taglet supported by doclets such as
- * the {@link jdk.javadoc.doclet.StandardDoclet standard doclet}.
+ * the {@linkplain StandardDoclet standard doclet}.
* Custom taglets are used to handle custom tags in documentation
* comments; custom tags can be instantiated individually as either
* block tags, which appear at the end of a comment,
@@ -55,10 +56,10 @@ import com.sun.source.doctree.DocTree;
* {@link #isInlineTag() isInlineTag}, to determine the characteristics
* of the tags supported by the taglet.
*
- As appropriate, the doclet calls the
- * {@link #toString(List,Element) toString} method on the taglet object,
- * giving it a list of tags and the element for which the tags are part
- * of the element's documentation comment, from which the taglet can
- * determine the string to be included in the documentation.
+ * {@link #toString(List,Element,URI) toString} method on the taglet object,
+ * giving it a list of tags, the element whose documentation comment contains
+ * the tags, and the root URI of the generated output, from which the taglet
+ * can determine the string to be included in the documentation.
* The doclet will typically specify any requirements on the contents of
* the string that is returned.
*
@@ -126,25 +127,70 @@ public interface Taglet {
default void init(DocletEnvironment env, Doclet doclet) { }
/**
- * Returns the string representation of a series of instances of
- * this tag to be included in the generated output.
+ * Returns the string representation of the specified instances of this tag
+ * to be included in the generated output.
*
- *
If this taglet supports {@link #isInlineTag inline} tags, it will
+ *
If this taglet supports {@link #isInlineTag inline} tags, this method will
* be called once per instance of the inline tag, each time with a singleton list.
* If this taglet supports {@link #isBlockTag block} tags, it will be called once
* for each comment containing instances of block tags, with a list of all the instances
* of the block tag in that comment.
*
+ * @apiNote Taglets that do not need the root URI of the generated output may
+ * implement this method only. Taglets that require the root URI to link to other
+ * doclet-generated resources should override {@link #toString(List, Element, URI)},
+ * and optionally throw an exception in the implementation of this method.
+ *
* @param tags the list of instances of this tag
* @param element the element to which the enclosing comment belongs
* @return the string representation of the tags to be included in
* the generated output
- *
+ * @throws UnsupportedOperationException if {@link #toString(List, Element, URI)}
+ * should be invoked instead
* @see User-Defined Taglets
* for the Standard Doclet
+ * @see #toString(List, Element, URI)
*/
String toString(List extends DocTree> tags, Element element);
+ /**
+ * Returns the string representation of the specified instances of this tag
+ * to be included in the generated output.
+ *
+ *
If this taglet supports {@link #isInlineTag inline} tags, this method will
+ * be called once per instance of the inline tag, each time with a singleton list.
+ * If this taglet supports {@link #isBlockTag block} tags, it will be called once
+ * for each comment containing instances of block tags, with a list of all the instances
+ * of the block tag in that comment.
+ *
+ *
The {@code docRoot} argument identifies the root of the generated output
+ * as seen by the current resource, and may be used to {@linkplain URI#resolve(String)
+ * resolve} links to other resources generated by the doclet.
+ *
+ * @apiNote The exact form of {@code docRoot} is doclet-specific. For the
+ * {@linkplain StandardDoclet standard doclet}, it is a relative URI from
+ * the current resource to the root directory of the generated output.
+ * Taglets intended for use with other doclets should check the validity
+ * of the {@code docRoot} argument as appropriate.
+ *
+ * @implSpec The default implementation invokes {@link #toString(List, Element)
+ * toString(tags, element)}.
+ *
+ * @param tags the list of instances of this tag
+ * @param element the element to which the enclosing comment belongs
+ * @param docRoot the root URI of the generated output
+ * @return the string representation of the tags to be included in
+ * the generated output
+ * @throws IllegalArgumentException if {@code docRoot} is not a valid URI
+ * @see User-Defined Taglets
+ * for the Standard Doclet
+ * @see #toString(List, Element)
+ * @since 27
+ */
+ default String toString(List extends DocTree> tags, Element element, URI docRoot) {
+ return toString(tags, element);
+ }
+
/**
* The kind of location in which a tag may be used.
*/
diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDoclet.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDoclet.java
index 66fcd90e2e8..17d56ff11ba 100644
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDoclet.java
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDoclet.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2026, 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
@@ -335,16 +335,9 @@ public class HtmlDoclet extends AbstractDoclet {
if (options.createIndex()) {
copyResource(DocPaths.SEARCH_JS_TEMPLATE, DocPaths.SCRIPT_FILES.resolve(DocPaths.SEARCH_JS), true);
- copyResource(DocPaths.SEARCH_PAGE_JS, DocPaths.SCRIPT_FILES.resolve(DocPaths.SEARCH_PAGE_JS), true);
copyResource(DocPaths.GLASS_SVG, DocPaths.RESOURCE_FILES.resolve(DocPaths.GLASS_SVG), false);
copyResource(DocPaths.X_SVG, DocPaths.RESOURCE_FILES.resolve(DocPaths.X_SVG), false);
- // No newline replacement for JQuery files
- copyResource(DocPaths.JQUERY_DIR.resolve(DocPaths.JQUERY_JS),
- DocPaths.SCRIPT_FILES.resolve(DocPaths.JQUERY_JS), false);
- copyResource(DocPaths.JQUERY_DIR.resolve(DocPaths.JQUERY_UI_JS),
- DocPaths.SCRIPT_FILES.resolve(DocPaths.JQUERY_UI_JS), false);
- copyResource(DocPaths.JQUERY_DIR.resolve(DocPaths.JQUERY_UI_CSS),
- DocPaths.RESOURCE_FILES.resolve(DocPaths.JQUERY_UI_CSS), false); }
+ }
copyLegalFiles(options.createIndex(), options.syntaxHighlight());
// Print a notice if the documentation contains diagnostic markers
@@ -369,7 +362,7 @@ public class HtmlDoclet extends AbstractDoclet {
case "", "default" -> {
// use a known resource as a stand-in, because we cannot get the URL for a resources directory
var url = HtmlDoclet.class.getResource(
- DocPaths.RESOURCES.resolve(DocPaths.LEGAL).resolve(DocPaths.JQUERY_MD).getPath());
+ DocPaths.RESOURCES.resolve(DocPaths.LEGAL).resolve(DocPaths.DEJAVU_MD).getPath());
if (url != null) {
try {
legalNoticesDir = Path.of(url.toURI()).getParent();
diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java
index 86ac3a892fd..594c36c4af2 100644
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2026, 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
@@ -243,12 +243,8 @@ public abstract class HtmlDocletWriter {
if (generating) {
writeGenerating();
}
- CURRENT_PATH.set(path.getPath());
}
- /** Temporary workaround to share current path with taglets, see 8373909 */
- public static final ThreadLocal CURRENT_PATH = new ThreadLocal<>();
-
/**
* The top-level method to generate and write the page represented by this writer.
*
diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlIds.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlIds.java
index a3fba7eca14..50e6207b833 100644
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlIds.java
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlIds.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -112,6 +112,11 @@ public class HtmlIds {
static final HtmlId RELATED_PACKAGE_SUMMARY = HtmlId.of("related-package-summary");
static final HtmlId RESET_SEARCH = HtmlId.of("reset-search");
static final HtmlId SEARCH_INPUT = HtmlId.of("search-input");
+ static final HtmlId SEARCH_INPUT_CONTAINER = HtmlId.of("search-input-container");
+ static final HtmlId SEARCH_MODULES = HtmlId.of("search-modules");
+ static final HtmlId SEARCH_PAGE_LINK = HtmlId.of("search-page-link");
+ static final HtmlId SEARCH_RESULT_CONTAINER = HtmlId.of("search-result-container");
+ static final HtmlId SEARCH_RESULT_SECTION = HtmlId.of("search-result-section");
static final HtmlId SERVICES = HtmlId.of("services-summary");
static final HtmlId SKIP_NAVBAR_TOP = HtmlId.of("skip-navbar-top");
static final HtmlId THEME_BUTTON = HtmlId.of("theme-button");
diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Navigation.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Navigation.java
index 30318bbaeea..cde5b287e25 100644
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Navigation.java
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/Navigation.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2026, 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,8 @@ import jdk.javadoc.internal.html.Content;
import jdk.javadoc.internal.html.ContentBuilder;
import jdk.javadoc.internal.html.Entity;
import jdk.javadoc.internal.html.HtmlAttr;
+import jdk.javadoc.internal.html.HtmlId;
+import jdk.javadoc.internal.html.HtmlTag;
import jdk.javadoc.internal.html.HtmlTree;
import jdk.javadoc.internal.html.Text;
@@ -535,6 +537,42 @@ public class Navigation {
.add(inputText)
.add(inputReset);
target.add(searchDiv);
+ target.add(HtmlTree.DIV(HtmlIds.SEARCH_RESULT_SECTION)
+ .add(HtmlTree.DIV(HtmlStyles.searchForm)
+ .add(HtmlTree.DIV(HtmlTree.LABEL(HtmlIds.SEARCH_INPUT.name(),
+ contents.getContent("doclet.search.for"))))
+ .add(HtmlTree.DIV(HtmlIds.SEARCH_INPUT_CONTAINER).addUnchecked(Text.EMPTY))
+ .add(createModuleSelector()))
+ .add(HtmlTree.DIV(HtmlIds.SEARCH_RESULT_CONTAINER).addUnchecked(Text.EMPTY))
+ .add(HtmlTree.DIV(HtmlStyles.searchLinks)
+ .add(HtmlTree.DIV(links.createLink(pathToRoot.resolve(DocPaths.SEARCH_PAGE),
+ contents.getContent("doclet.search.linkSearchPageLabel"))
+ .setId(HtmlIds.SEARCH_PAGE_LINK)))
+ .add(options.noHelp() || !options.helpFile().isEmpty()
+ ? HtmlTree.DIV(Text.EMPTY).addUnchecked(Text.EMPTY)
+ : HtmlTree.DIV(links.createLink(pathToRoot.resolve(DocPaths.HELP_DOC).fragment("search"),
+ contents.getContent("doclet.search.linkSearchHelpLabel"))))));
+ }
+
+ private Content createModuleSelector() {
+ if (!configuration.showModules || configuration.modules.size() < 2) {
+ return Text.EMPTY;
+ }
+ var content = new ContentBuilder(HtmlTree.DIV(HtmlTree.LABEL(HtmlIds.SEARCH_MODULES.name(),
+ contents.getContent("doclet.search.in_modules"))));
+ var select = HtmlTree.of(HtmlTag.SELECT)
+ .setId(HtmlIds.SEARCH_MODULES)
+ .put(HtmlAttr.ARIA_LABEL, configuration.getDocResources().getText("doclet.selectModule"))
+ .add(HtmlTree.of(HtmlTag.OPTION)
+ .put(HtmlAttr.VALUE, "")
+ .add(contents.getContent("doclet.search.all_modules")));
+
+ for (ModuleElement module : configuration.modules) {
+ select.add(HtmlTree.of(HtmlTag.OPTION)
+ .put(HtmlAttr.VALUE, module.getQualifiedName().toString())
+ .add(Text.of(module.getQualifiedName().toString())));
+ }
+ return content.add(HtmlTree.DIV(select));
}
/**
diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SearchWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SearchWriter.java
index 433a641530d..5fa0daacf98 100644
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SearchWriter.java
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/SearchWriter.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2022, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2022, 2026, 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
@@ -92,17 +92,15 @@ public class SearchWriter extends HtmlDocletWriter {
.add(resourceSection)
.add(HtmlTree.P(contents.getContent("doclet.search.loading"))
.setId(HtmlId.of("page-search-notify")))
- .add(HtmlTree.DIV(HtmlTree.DIV(HtmlId.of("result-container"))
+ .add(HtmlTree.DIV(HtmlTree.DIV(HtmlIds.SEARCH_RESULT_CONTAINER)
.addUnchecked(Text.EMPTY))
- .setId(HtmlId.of("result-section"))
- .put(HtmlAttr.STYLE, "display: none;")
- .add(HtmlTree.SCRIPT(pathToRoot.resolve(DocPaths.SCRIPT_FILES)
- .resolve(DocPaths.SEARCH_PAGE_JS).getPath())));
+ .setId(HtmlIds.SEARCH_RESULT_SECTION)
+ .put(HtmlAttr.STYLE, "display: none;"));
}
private Content createModuleSelector() {
- if (!configuration.showModules) {
+ if (!configuration.showModules || configuration.modules.size() < 2) {
return Text.EMPTY;
}
@@ -118,7 +116,7 @@ public class SearchWriter extends HtmlDocletWriter {
.put(HtmlAttr.VALUE, module.getQualifiedName().toString())
.add(Text.of(module.getQualifiedName().toString())));
}
- return new ContentBuilder(contents.getContent("doclet.search.in", select));
+ return new ContentBuilder(contents.getContent("doclet.search.in_modules"), select);
}
private Content createResourceSection() {
diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Head.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Head.java
index cda4bc9a5be..bff32cbd7bf 100644
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Head.java
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/Head.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2026, 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
@@ -336,11 +336,6 @@ public class Head extends Content {
}
private void addStylesheets(HtmlTree head) {
- if (index) {
- // Add JQuery-UI stylesheet first so its rules can be overridden.
- addStylesheet(head, DocPaths.RESOURCE_FILES.resolve(DocPaths.JQUERY_UI_CSS));
- }
-
if (mainStylesheet == null) {
mainStylesheet = DocPaths.STYLESHEET;
}
@@ -381,8 +376,6 @@ public class Head extends Content {
.append("loadScripts();\n")
.append("initTheme();\n");
}
- addScriptElement(head, DocPaths.JQUERY_JS);
- addScriptElement(head, DocPaths.JQUERY_UI_JS);
}
for (HtmlConfiguration.JavaScriptFile javaScriptFile : additionalScripts) {
addScriptElement(head, javaScriptFile);
diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlStyles.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlStyles.java
index 9b59cb0cb47..2b154db7de7 100644
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlStyles.java
+++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/markup/HtmlStyles.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2010, 2025, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2026, 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
@@ -734,6 +734,16 @@ public enum HtmlStyles implements HtmlStyle {
*/
pageSearchInfo,
+ /**
+ * The class for a {@code div} element in the search widget containing the search form inputs.
+ */
+ searchForm,
+
+ /**
+ * The class for a {@code div} element in the search widget containing search-related links.
+ */
+ searchLinks,
+
/**
* The class for a link in the static "Index" pages to a custom searchable item,
* such as defined with an {@code @index} tag.
diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/jquery/jquery-3.7.1.js b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/jquery/jquery-3.7.1.js
deleted file mode 100644
index 1a86433c223..00000000000
--- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/jquery/jquery-3.7.1.js
+++ /dev/null
@@ -1,10716 +0,0 @@
-/*!
- * jQuery JavaScript Library v3.7.1
- * https://jquery.com/
- *
- * Copyright OpenJS Foundation and other contributors
- * Released under the MIT license
- * https://jquery.org/license
- *
- * Date: 2023-08-28T13:37Z
- */
-( function( global, factory ) {
-
- "use strict";
-
- if ( typeof module === "object" && typeof module.exports === "object" ) {
-
- // For CommonJS and CommonJS-like environments where a proper `window`
- // is present, execute the factory and get jQuery.
- // For environments that do not have a `window` with a `document`
- // (such as Node.js), expose a factory as module.exports.
- // This accentuates the need for the creation of a real `window`.
- // e.g. var jQuery = require("jquery")(window);
- // See ticket trac-14549 for more info.
- module.exports = global.document ?
- factory( global, true ) :
- function( w ) {
- if ( !w.document ) {
- throw new Error( "jQuery requires a window with a document" );
- }
- return factory( w );
- };
- } else {
- factory( global );
- }
-
-// Pass this if window is not defined yet
-} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) {
-
-// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1
-// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode
-// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common
-// enough that all such attempts are guarded in a try block.
-"use strict";
-
-var arr = [];
-
-var getProto = Object.getPrototypeOf;
-
-var slice = arr.slice;
-
-var flat = arr.flat ? function( array ) {
- return arr.flat.call( array );
-} : function( array ) {
- return arr.concat.apply( [], array );
-};
-
-
-var push = arr.push;
-
-var indexOf = arr.indexOf;
-
-var class2type = {};
-
-var toString = class2type.toString;
-
-var hasOwn = class2type.hasOwnProperty;
-
-var fnToString = hasOwn.toString;
-
-var ObjectFunctionString = fnToString.call( Object );
-
-var support = {};
-
-var isFunction = function isFunction( obj ) {
-
- // Support: Chrome <=57, Firefox <=52
- // In some browsers, typeof returns "function" for HTML